esphome:
  name: kona-mqtt-sender
  comment: "ESP32 #2 – empfängt Kona EV Daten via UART, sendet per MQTT an Home Assistant"

esp32:
  board: esp32dev
  framework:
    type: arduino

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  fast_connect: true

web_server:
  port: 80
  local: true

logger:
  level: DEBUG

api:
  encryption:
    key: !secret ha_api_key_2

ota:
  platform: esphome

# ──────────────────────────────────────────────
# MQTT Verbindung zu Home Assistant
# ──────────────────────────────────────────────
mqtt:
  broker: 192.168.x.x   #YOUR_MQTT_BROKER_IP
  port: 1883
  username: !secret mqtt_username
  password: !secret mqtt_password
  client_id: kona-mqtt-sender
  topic_prefix: kona
  birth_message:
    topic: kona/status
    payload: online
  will_message:
    topic: kona/status
    payload: offline
  on_message:
    - topic: zigbee2mqtt/Garagentor
      then:
        - lambda: |-
            // Nur beim Öffnen triggern (contact: false)
            if (x.find("\"contact\":false") != std::string::npos) {
              ESP_LOGI("GARAGE", "Tor geöffnet - OBD Impuls fuer 5min");
              id(g_garage_enable_until) = millis() + 300000; // 5 Minuten
              if (!id(g_wallbox_charging)) {
                id(g_enabled) = true;
                id(uart_from_esp1).write_str("CMD:ENABLE\n");
              }
            }

    - topic: delta-wallbox/sensor/evse1_charge_state/state
      then:
        - lambda: |-
            int state = atoi(x.c_str());
            if (state == 3) {
              id(g_wallbox_charging) = true;
              id(g_enabled) = true;
              ESP_LOGI("CTRL", "OBD Abfragen aktiviert (Wallbox laedt)");
              id(uart_from_esp1).write_str("CMD:ENABLE\n");
            } else {
              id(g_wallbox_charging) = false;
              ESP_LOGI("CTRL", "Wallbox laedt nicht (State: %d)", state);
              // Nur deaktivieren wenn auch kein Garage-Timer aktiv
              if (id(g_garage_enable_until) == 0 || millis() > id(g_garage_enable_until)) {
                id(g_enabled) = false;
                id(g_garage_enable_until) = 0;
                // Strom, Leistung und Ladestatus explizit auf 0 setzen
                // da ESP1 nach CMD:DISABLE keine UART-Pakete mehr sendet
                id(g_charging) = false;
                id(g_current) = 0.0f;
                id(sensor_current).publish_state(0.0f);
                id(sensor_power).publish_state(0.0f);
                id(sensor_charging).publish_state(false);
                ESP_LOGI("CTRL", "OBD Abfragen deaktiviert (Wallbox nicht laden)");
                id(uart_from_esp1).write_str("CMD:DISABLE\n");
              }
            }


# ──────────────────────────────────────────────
# UART von ESP32 #1
# TX von ESP32 #1 (GPIO17) → RX hier (GPIO16)
# GND verbinden nicht vergessen!
# ──────────────────────────────────────────────
uart:
  id: uart_from_esp1
  rx_pin: GPIO16
  tx_pin: GPIO17
  baud_rate: 115200

# ──────────────────────────────────────────────
# Globale Variablen
# ──────────────────────────────────────────────
globals:
  - id: g_enabled
    type: bool
    initial_value: "true"
  - id: g_garage_enable_until
    type: unsigned long
    initial_value: "0"
  - id: g_wallbox_charging
    type: bool
    initial_value: "false"
  - id: g_soc
    type: float
    initial_value: "0.0"
  - id: g_soh
    type: float
    initial_value: "0.0"
  - id: g_tavg
    type: float
    initial_value: "0.0"
  - id: g_tmin
    type: float
    initial_value: "0.0"
  - id: g_tmax
    type: float
    initial_value: "0.0"
  - id: g_voltage
    type: float
    initial_value: "0.0"
  - id: g_current
    type: float
    initial_value: "0.0"
  - id: g_charging
    type: bool
    initial_value: "false"
  - id: g_rssi
    type: int
    initial_value: "0"
  - id: g_cycles
    type: float
    initial_value: "0.0"
  - id: uart_buf
    type: std::string
    initial_value: '""'

# ──────────────────────────────────────────────
# UART einlesen + parsen
# Format: SOC:85.5,SOH:97.0,TAVG:24.5,TMIN:22.0,TMAX:27.0,V:385.2,I:-5.3,CHG:0,CYC:123
# ──────────────────────────────────────────────
interval:
  - interval: 30s
    then:
      - lambda: |-
          // Garage Timer prüfen
          if (id(g_garage_enable_until) > 0 && millis() > id(g_garage_enable_until)) {
            id(g_garage_enable_until) = 0;
            if (!id(g_wallbox_charging)) {
              ESP_LOGI("GARAGE", "5min Impuls abgelaufen - OBD deaktivieren");
              id(g_enabled) = false;
              // Strom, Leistung und Ladestatus auf 0 setzen
              id(g_charging) = false;
              id(g_current) = 0.0f;
              id(sensor_current).publish_state(0.0f);
              id(sensor_power).publish_state(0.0f);
              id(sensor_charging).publish_state(false);
              id(uart_from_esp1).write_str("CMD:DISABLE\n");
            }
          }

  - interval: 100ms
    then:
      - lambda: |-
          // Alle verfügbaren Bytes einlesen
          while (id(uart_from_esp1).available()) {
            uint8_t c;
            id(uart_from_esp1).read_byte(&c);

            if (c == '\n') {
              // Zeile komplett → parsen
              std::string line = id(uart_buf);
              id(uart_buf) = "";

              if (line.empty()) return;
              ESP_LOGD("UART", "Empfangen: %s", line.c_str());

              // Hilfsfunktion: Wert nach Key extrahieren
              auto get_val = [&](const std::string& key) -> std::string {
                size_t pos = line.find(key + ":");
                if (pos == std::string::npos) return "";
                pos += key.size() + 1;
                size_t end = line.find(',', pos);
                if (end == std::string::npos) end = line.size();
                return line.substr(pos, end - pos);
              };

              // Werte parsen
              std::string v;
              v = get_val("SOC");  if (!v.empty()) id(g_soc)     = atof(v.c_str());
              v = get_val("SOH");  if (!v.empty()) id(g_soh)     = atof(v.c_str());
              v = get_val("TAVG"); if (!v.empty()) id(g_tavg)    = atof(v.c_str());
              v = get_val("TMIN"); if (!v.empty()) id(g_tmin)    = atof(v.c_str());
              v = get_val("TMAX"); if (!v.empty()) id(g_tmax)    = atof(v.c_str());
              v = get_val("V");    if (!v.empty()) id(g_voltage) = atof(v.c_str());
              v = get_val("CHG");  if (!v.empty()) id(g_charging) = (atoi(v.c_str()) == 1);
              v = get_val("I");    if (!v.empty()) id(g_current) = id(g_charging) ? atof(v.c_str()) : 0.0f;
              v = get_val("CYC");  if (!v.empty()) id(g_cycles)  = atof(v.c_str());
              v = get_val("RSSI"); if (!v.empty()) id(g_rssi) = atoi(v.c_str());

              // WiFi Signal immer publizieren
              id(sensor_wifi_signal).publish_state(id(g_rssi));
              id(g_rssi) = 0;  // Zurücksetzen damit kein veralteter Wert publiziert wird
              // Laden-Status immer publizieren (unabhängig von SOC)
              id(sensor_charging).publish_state(id(g_charging));
              // Nur publizieren wenn echte Daten vorhanden (SOC > 0)
              if (id(g_soc) > 0.0f) {
                id(sensor_soc).publish_state(id(g_soc));
                id(sensor_soh).publish_state(id(g_soh));
                id(sensor_tavg).publish_state(id(g_tavg));
                id(sensor_tmin).publish_state(id(g_tmin));
                id(sensor_tmax).publish_state(id(g_tmax));
                id(sensor_voltage).publish_state(id(g_voltage));
                id(sensor_current).publish_state(id(g_current));
                id(sensor_cycles).publish_state(id(g_cycles));
                id(sensor_power).publish_state(id(g_voltage) * id(g_current));
              }

            } else if (c != '\r') {
              id(uart_buf) += (char)c;
            }
          }

# ──────────────────────────────────────────────
# Sensoren → werden automatisch per MQTT publiziert
# Topics: kona/sensor/kona_soc/state  usw.
# ──────────────────────────────────────────────
sensor:
  - platform: template
    name: "Kona SOC"
    id: sensor_soc
    unit_of_measurement: "%"
    accuracy_decimals: 1
    device_class: battery
    state_class: measurement

  - platform: template
    name: "Kona SOH"
    id: sensor_soh
    unit_of_measurement: "%"
    accuracy_decimals: 1
    state_class: measurement
    filters:
      - delta: 1.0

  - platform: template
    name: "Kona Batterie Temp Avg"
    id: sensor_tavg
    unit_of_measurement: "°C"
    accuracy_decimals: 1
    device_class: temperature
    state_class: measurement
    filters:
      - delta: 0.5

  - platform: template
    name: "Kona Batterie Temp Min"
    id: sensor_tmin
    unit_of_measurement: "°C"
    accuracy_decimals: 1
    device_class: temperature
    state_class: measurement
    filters:
      - delta: 0.5

  - platform: template
    name: "Kona Batterie Temp Max"
    id: sensor_tmax
    unit_of_measurement: "°C"
    accuracy_decimals: 1
    device_class: temperature
    state_class: measurement
    filters:
      - delta: 0.5

  - platform: template
    name: "Kona Batterie Spannung"
    id: sensor_voltage
    unit_of_measurement: "V"
    accuracy_decimals: 1
    device_class: voltage
    state_class: measurement
    filters:
      - delta: 0.5

  - platform: template
    name: "Kona Batterie Strom"
    id: sensor_current
    unit_of_measurement: "A"
    accuracy_decimals: 1
    device_class: current
    state_class: measurement

  - platform: template
    name: "Kona Ladezyklen"
    id: sensor_cycles
    unit_of_measurement: ""
    accuracy_decimals: 0
    state_class: total_increasing
    filters:
      - delta: 1.0

  - platform: template
    name: "Kona iCar2 Signal"
    id: sensor_wifi_signal
    unit_of_measurement: "dBm"
    device_class: signal_strength
    state_class: measurement
    accuracy_decimals: 0
    filters:
      - lambda: |-
          if (x >= 0) return {};  // 0 und INT_MAX filtern
          return x;

  - platform: template
    name: "Kona Batterie Leistung"
    id: sensor_power
    unit_of_measurement: "W"
    accuracy_decimals: 0
    device_class: power
    state_class: measurement

binary_sensor:
  - platform: template
    name: "Kona lädt"
    id: sensor_charging
    device_class: battery_charging
