CYD ESP32-2432S028 mit ESPHome + ESPHome Disigner

Hallo, hat jemand schon einen Temperatur wert aus HA auf dem CYD ESP32-2432S028 Display erfolgreich zu Anzeige gebracht? Bei Mir wird immer „nan“ angezeigt. Der code würde mit CYD ESP32-2432S028 erzeugt.

„nan“ steht vermutlich für „not a number“. D. h. dein anzuzeigender Wert ist keine gültige Real- oder Fliesskommazahl.

Was ist das für ein Format. Bei einer Definition als Text, erschein ein Wert 1.71 bei einer Temperatur von > 20 Grad.

Hat jemand dieses Display im Einsatz, das auch korrekte Werte anzeigt.

Habe gerade festgestellt, der Wert 1.71 bleibt konstant auch wenn der Sensor wechselt.

:crayon:by HarryP: Zusammenführung Doppelpost (bei Änderungen oder hinzufügen von Inhalten bitte die „Bearbeitungsfunktion“ anstatt „Antworten“ zu nutzen)

Ich nutze das Display auch um alles rund um meine PV und Wetter anzuzeigen.

  - platform: homeassistant
    id: garage_temp
    entity_id: sensor.garage_hinten_bewegungsmelder_air_temperature
    on_value:
      - lvgl.label.update:
          id: lbl_garage_temp
          text: !lambda |-
            char buf[16];
            snprintf(buf, sizeof(buf), "%.1f°C", x);
            return std::string(buf);

Danke für eure Unterstützung.

Ich gebe auf. Für die Programmierung reichen meine Kenntnis nicht aus.

Hast du mal openHASP versucht? Auf einem ESP32 mit einem 3,2” Display funktioniert das bei mir sehr gut.

Allerdings scheint es da Probleme mit einigen 2432S028 CYDs zu geben, weil die den falschen Displaycontroller eingebaut haben.

Ich habe auch 0 Ahnung vom Programmieren. Es ist aber recht simple.

Die Lösung für das „nan"-Problem

„nan" bedeutet not a number Der Wert vom Sensor kommt als String oder als ungültige Zahl an. Drei Dinge müssen stimmen:

Erstens, die Entity-ID muss exakt mit der in Home Assistant übereinstimmen, inklusive sensor. davor. Prüfe unter Entwicklerwerkzeuge - Zustände in HA. Zweitens, der Sensor in HA muss eine numerische device_class wie temperature haben und einen unit_of_measurement (°C) - sonst behandelt ESPHome ihn nicht als Float. Drittens, das platform: homeassistant unter sensor: benutzen (nicht unter text_sensor:). Die on_value-Aktion mit dem snprintf-Lambda, wie oben und auch im Beispiel im Thread, formatiert den Float dann korrekt als z. B. „21.3 °C".

Wenn du als text_sensor definierst, bekommst du genau das: einen festen Wert wie „1.71", weil das die Länge des Strings oder ein Speicher-Offset ist, nicht der eigentliche Wert.

Ich kann Dir meine ESP-Home Konfiguration zum testen egben.

Hallo,

habe das display selbst mit diesem teil zum laufen gebracht:

https://cheapyellowdisplay.co.uk/config-generator

ich denke, da kannst du mit deinen Entitäten “spielen”, da du selbst festlegen musst, ob es ein Textsensor oder ein numerischer Sensor ist. Du könntest also einfach ausprobieren.

Zum zweiten hatte ich ein anderes Display, das nur 2 Temperaturen anzeigen sollte. Dieses Teil hat sehr oft “nan” angezeigt. Lag in diesem Fall schlicht an der Wlan Verbindung und letztlich die Verbindung zu HA. Habe mir das dann so erklärt: das Teil läuft hoch und zeigt an, was da ist. Solange die Wlan Verbindung aber noch nicht stabil war, hat es nan statt der Temperaturen angezeigt.

Auszug aus der yaml des displays:

sensor:
  - platform: homeassistant
    name: "Aussen"
    id: aussen
    entity_id: sensor.wetter2_aussentemperatur
    internal: true
  - platform: homeassistant
    name: "Innen"
    id: innen
    entity_id: sensor.kuchetemp_temperature
    internal: true
  - platform: wifi_signal
    name: "WiFi Signal Sensor"
    id: wifix
    update_interval: 60s
# Auszug aus der Lambda:
    lambda: |-
      it.print(7,42, id(font2), yellow, "I:");
      it.printf(150, 10, id(font3), white,TextAlign::TOP_RIGHT, "  %.1f ", id(innen).state);
      it.print(7, 96, id(font2), yellow, "O:");
      it.printf(150,66, id(font3), white, TextAlign::TOP_RIGHT,"  %.1f ", id(aussen).state);
      it.printf(7, 15, id(font2), white, "%.0f", id(wifix).state);

Wie du siehst, habe ich irgendwann das wifi signal mit anzeigen lassen…

Hoffe das hilft dir, um noch nicht aufzugeben.

Das Ganze ist schon ca 1 Jahr alt und mittlerweile nutze ich - ungern - gemini um solche Fehler zu finden. Ist nach meiner Erfahrung manchmal klüger, manchmal aber auch dümmer, als ich erwartet hätte - für mich aber effektiv “schneller”

Herzliche Grüße

Rolo

Hallo Oliver

Habe alles in Entwicklerwerkzeugen kontrolliert. Alles ist wie es sein sollte, dennoch funktioniert es nicht. Eine brauchbare anzeige habe ich mit dem Link config-generator von rolo hin bekommen.

Würde dennoch auf dein Angebot zurückkommen und deine ESP-Home Konfiguration testen

Grüße

Waldemar

substitutions:
  device_name: cyd-display
  friendly_name: "CYD Display"

esphome:
  name: ${device_name}
  friendly_name: ${friendly_name}
  min_version: 2025.6.0

esp32:
  board: esp32dev
  framework:
    type: arduino

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: "CYD Display Fallback"
    password: "changeme1234"

captive_portal:

logger:
  level: INFO

api:
  encryption:
    key: !secret api_encryption_key

ota:
  - platform: esphome
    password: !secret ota_password

# Globale Variablen -------------------------------------------------
globals:
  - id: nacht_modus
    type: bool
    restore_value: no
    initial_value: 'false'
  - id: pv_displayed
    type: float
    restore_value: no
    initial_value: '0.0'
  - id: pv_target
    type: float
    restore_value: no
    initial_value: '0.0'
  - id: verbrauch_displayed
    type: float
    restore_value: no
    initial_value: '0.0'
  - id: verbrauch_target
    type: float
    restore_value: no
    initial_value: '0.0'
  - id: bezug_displayed
    type: float
    restore_value: no
    initial_value: '0.0'
  - id: bezug_target
    type: float
    restore_value: no
    initial_value: '0.0'
  - id: einspeisung_displayed
    type: float
    restore_value: no
    initial_value: '0.0'
  - id: einspeisung_target
    type: float
    restore_value: no
    initial_value: '0.0'
  - id: anim_tick
    type: int
    restore_value: no
    initial_value: '0'
  - id: autoslide_pause
    type: int
    restore_value: no
    initial_value: '0'

# Smooth-Wert-Animation alle 50ms -----------------------------------
interval:
  - interval: 50ms
    then:
      - lambda: |-
          auto tween = [](float displayed, float target) -> float {
            float diff = target - displayed;
            if (std::abs(diff) < 1.0) return target;
            return displayed + diff * 0.10;
          };
          id(pv_displayed) = tween(id(pv_displayed), id(pv_target));
          id(verbrauch_displayed) = tween(id(verbrauch_displayed), id(verbrauch_target));
          id(bezug_displayed) = tween(id(bezug_displayed), id(bezug_target));
          id(einspeisung_displayed) = tween(id(einspeisung_displayed), id(einspeisung_target));
      - lvgl.label.update:
          id: lbl_pv
          text: !lambda |-
            char buf[24];
            float v = id(pv_displayed);
            if (v < 1000) snprintf(buf, sizeof(buf), "%.0f W", v);
            else          snprintf(buf, sizeof(buf), "%.2f kW", v / 1000.0);
            return std::string(buf);
      - lvgl.label.update:
          id: lbl_verbrauch
          text: !lambda |-
            char buf[24];
            float v = std::abs(id(verbrauch_displayed));
            if (v < 1000) snprintf(buf, sizeof(buf), "%.0f W", v);
            else          snprintf(buf, sizeof(buf), "%.2f kW", v / 1000.0);
            return std::string(buf);
      - lvgl.label.update:
          id: lbl_netzbezug
          text: !lambda |-
            char buf[24];
            float v = id(bezug_displayed);
            if (v < 1000) snprintf(buf, sizeof(buf), "%.0f W", v);
            else          snprintf(buf, sizeof(buf), "%.2f kW", v / 1000.0);
            return std::string(buf);
      - lvgl.label.update:
          id: lbl_einspeisung
          text: !lambda |-
            char buf[24];
            float v = id(einspeisung_displayed);
            if (v < 1000) snprintf(buf, sizeof(buf), "%.0f W", v);
            else          snprintf(buf, sizeof(buf), "%.2f kW", v / 1000.0);
            return std::string(buf);

  # Dauer-Animationen alle 150ms
  - interval: 150ms
    then:
      - lambda: 'id(anim_tick) = (id(anim_tick) + 1) % 4;'

      - lvgl.widget.update:
          id: pulse_dot
          bg_opa: !lambda |-
            if (id(pv_target) < 5.0) return 30;
            int t = id(anim_tick);
            int values[4] = {100, 200, 255, 200};
            return values[t];

      - lvgl.widget.update:
          id: flow_pv_dot1
          bg_opa: !lambda |-
            if (id(pv_target) < 5.0) return 0;
            return (id(anim_tick) == 0) ? 255 : 60;
      - lvgl.widget.update:
          id: flow_pv_dot2
          bg_opa: !lambda |-
            if (id(pv_target) < 5.0) return 0;
            return (id(anim_tick) == 1) ? 255 : 60;
      - lvgl.widget.update:
          id: flow_pv_dot3
          bg_opa: !lambda |-
            if (id(pv_target) < 5.0) return 0;
            return (id(anim_tick) == 2) ? 255 : 60;
      - lvgl.widget.update:
          id: flow_pv_dot4
          bg_opa: !lambda |-
            if (id(pv_target) < 5.0) return 0;
            return (id(anim_tick) == 3) ? 255 : 60;

      - lvgl.widget.update:
          id: flow_haus_dot1
          bg_opa: !lambda |-
            float bezug = id(bezug_target);
            float ein = id(einspeisung_target);
            int t = id(anim_tick);
            if (ein > 5)   return (t == 0) ? 255 : 60;
            if (bezug > 5) return (t == 3) ? 255 : 60;
            return 0;
      - lvgl.widget.update:
          id: flow_haus_dot2
          bg_opa: !lambda |-
            float bezug = id(bezug_target);
            float ein = id(einspeisung_target);
            int t = id(anim_tick);
            if (ein > 5)   return (t == 1) ? 255 : 60;
            if (bezug > 5) return (t == 2) ? 255 : 60;
            return 0;
      - lvgl.widget.update:
          id: flow_haus_dot3
          bg_opa: !lambda |-
            float bezug = id(bezug_target);
            float ein = id(einspeisung_target);
            int t = id(anim_tick);
            if (ein > 5)   return (t == 2) ? 255 : 60;
            if (bezug > 5) return (t == 1) ? 255 : 60;
            return 0;
      - lvgl.widget.update:
          id: flow_haus_dot4
          bg_opa: !lambda |-
            float bezug = id(bezug_target);
            float ein = id(einspeisung_target);
            int t = id(anim_tick);
            if (ein > 5)   return (t == 3) ? 255 : 60;
            if (bezug > 5) return (t == 0) ? 255 : 60;
            return 0;

  # Auto-Slide alle 10 Sekunden, pausiert 30s nach Touch
  - interval: 1s
    then:
      - lambda: |-
          if (id(autoslide_pause) > 0) {
            id(autoslide_pause) -= 1;
          }
      - if:
          condition:
            lambda: |-
              return id(autoslide_pause) == 0;
          then:
            - lambda: |-
                static int counter = 0;
                counter += 1;
                if (counter >= 10) {
                  counter = 0;
                  id(do_next_page).execute();
                }

# Script: zur nächsten Seite wechseln
script:
  - id: do_next_page
    then:
      - lvgl.page.next:
          animation: OVER_LEFT
          time: 300ms

# Zeitsteuerung -----------------------------------------------------
time:
  - platform: homeassistant
    id: ha_time
    on_time:
      - hours: 21
        minutes: 0
        seconds: 0
        then:
          - globals.set:
              id: nacht_modus
              value: 'true'
          - light.turn_on:
              id: backlight
              brightness: 30%
              transition_length: 3s
      - hours: 6
        minutes: 0
        seconds: 0
        then:
          - globals.set:
              id: nacht_modus
              value: 'false'
          - light.turn_on:
              id: backlight
              brightness: 100%
              transition_length: 3s
    on_time_sync:
      then:
        - if:
            condition:
              lambda: |-
                auto t = id(ha_time).now();
                if (!t.is_valid()) return false;
                return (t.hour >= 21 || t.hour < 6);
            then:
              - globals.set:
                  id: nacht_modus
                  value: 'true'
              - light.turn_on:
                  id: backlight
                  brightness: 30%
                  transition_length: 2s
            else:
              - globals.set:
                  id: nacht_modus
                  value: 'false'
              - light.turn_on:
                  id: backlight
                  brightness: 100%
                  transition_length: 2s

# Fonts -------------------------------------------------------------
font:
  - file:
      type: gfonts
      family: Roboto
      weight: 400
    id: roboto_12
    size: 12
    bpp: 4
    glyphs: " !\"%()+=,-_.:°/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzÄÖÜäöüß"

  - file:
      type: gfonts
      family: Roboto
      weight: 400
    id: roboto_14
    size: 14
    bpp: 4
    glyphs: " !\"%()+=,-_.:°/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzÄÖÜäöüß"

  - file:
      type: gfonts
      family: Roboto
      weight: 400
    id: roboto_18
    size: 18
    bpp: 4
    glyphs: " !\"%()+=,-_.:°/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzÄÖÜäöüß"

  - file:
      type: gfonts
      family: Roboto
      weight: 700
    id: roboto_28
    size: 28
    bpp: 4
    glyphs: " !\"%()+=,-_.:°/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzÄÖÜäöüß"

  - file:
      type: gfonts
      family: Roboto
      weight: 700
    id: roboto_36
    size: 36
    bpp: 4
    glyphs: " !\"%()+=,-_.:°/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzÄÖÜäöüß"

  - file: "https://github.com/Templarian/MaterialDesign-Webfont/raw/master/fonts/materialdesignicons-webfont.ttf"
    id: mdi_72
    size: 72
    bpp: 4
    glyphs:
      - "\U000F0599"  # weather-sunny
      - "\U000F0590"  # weather-cloudy
      - "\U000F0595"  # weather-partly-cloudy
      - "\U000F0597"  # weather-rainy
      - "\U000F067F"  # weather-pouring
      - "\U000F0598"  # weather-snowy
      - "\U000F067E"  # weather-snowy-rainy
      - "\U000F0596"  # weather-night
      - "\U000F0F31"  # weather-night-partly-cloudy
      - "\U000F0594"  # weather-fog
      - "\U000F0F32"  # weather-windy
      - "\U000F0593"  # weather-lightning
      - "\U000F067D"  # weather-lightning-rainy
      - "\U000F0F38"  # weather-hail
      - "\U000F0F30"  # help-circle (fallback)

# SPI Busse ---------------------------------------------------------
spi:
  - id: tft_spi
    clk_pin: GPIO14
    mosi_pin: GPIO13
    miso_pin: GPIO12

  - id: touch_spi
    clk_pin: GPIO25
    mosi_pin: GPIO32
    miso_pin: GPIO39

# Display - PHYSISCH 240x320, Rotation kommt von LVGL ---------------
display:
  - platform: ili9xxx
    id: main_display
    model: ILI9341
    spi_id: tft_spi
    cs_pin: GPIO15
    dc_pin: GPIO2
    invert_colors: false
    color_palette: 8BIT
    dimensions:
      width: 240
      height: 320
    update_interval: never
    auto_clear_enabled: false

# Touch - XPT2046 ---------------------------------------------------
touchscreen:
  - platform: xpt2046
    id: touch
    spi_id: touch_spi
    cs_pin: GPIO33
    interrupt_pin: GPIO36
    update_interval: 50ms
    threshold: 400
    calibration:
      x_min: 280
      x_max: 3860
      y_min: 340
      y_max: 3860
    transform:
      swap_xy: false
      mirror_x: false
      mirror_y: false
    on_touch:
      - lambda: 'id(autoslide_pause) = 30;'
      - light.turn_on:
          id: backlight
          brightness: 100%
          transition_length: 500ms
      - delay: 30s
      - if:
          condition:
            lambda: 'return id(nacht_modus);'
          then:
            - light.turn_on:
                id: backlight
                brightness: 30%
                transition_length: 2s

# Outputs -----------------------------------------------------------
output:
  - platform: ledc
    pin: GPIO21
    id: backlight_pwm
  - platform: ledc
    pin:
      number: GPIO4
      inverted: true
    id: led_red_pwm
  - platform: ledc
    pin:
      number: GPIO16
      inverted: true
    id: led_green_pwm
  - platform: ledc
    pin:
      number: GPIO17
      inverted: true
    id: led_blue_pwm

light:
  - platform: monochromatic
    output: backlight_pwm
    name: "Display Backlight"
    id: backlight
    restore_mode: ALWAYS_ON
    default_transition_length: 1s

  - platform: rgb
    name: "Status LED"
    id: status_led
    red: led_red_pwm
    green: led_green_pwm
    blue: led_blue_pwm
    restore_mode: ALWAYS_OFF

# PV-Sensoren -------------------------------------------------------
sensor:
  - platform: homeassistant
    id: pv_leistung
    entity_id: sensor.solarnet_pv_leistung
    on_value:
      - lambda: 'id(pv_target) = x;'

  - platform: homeassistant
    id: verbrauch
    entity_id: sensor.solarnet_leistung_verbrauch
    on_value:
      - lambda: 'id(verbrauch_target) = x;'

  - platform: homeassistant
    id: netzbezug
    entity_id: sensor.solarnet_leistung_netzbezug
    on_value:
      - lambda: 'id(bezug_target) = x;'

  - platform: homeassistant
    id: einspeisung
    entity_id: sensor.solarnet_leistung_netzeinspeisung
    on_value:
      - lambda: 'id(einspeisung_target) = x;'

  - platform: homeassistant
    id: ladeleistung
    entity_id: sensor.solarnet_ladeleistung
    on_value:
      - lvgl.label.update:
          id: lbl_batterie_power
          text: !lambda |-
            char buf[32];
            float lade = id(ladeleistung).state;
            float entlade = id(entladeleistung).state;
            if (!isnan(lade) && lade > 5) {
              if (lade < 1000) snprintf(buf, sizeof(buf), "Lädt: %.0f W", lade);
              else             snprintf(buf, sizeof(buf), "Lädt: %.2f kW", lade/1000.0);
            } else if (!isnan(entlade) && entlade > 5) {
              if (entlade < 1000) snprintf(buf, sizeof(buf), "Entlädt: %.0f W", entlade);
              else                snprintf(buf, sizeof(buf), "Entlädt: %.2f kW", entlade/1000.0);
            } else {
              snprintf(buf, sizeof(buf), "Ruht");
            }
            return std::string(buf);

  - platform: homeassistant
    id: entladeleistung
    entity_id: sensor.solarnet_entladeleistung
    on_value:
      - lvgl.label.update:
          id: lbl_batterie_power
          text: !lambda |-
            char buf[32];
            float lade = id(ladeleistung).state;
            float entlade = id(entladeleistung).state;
            if (!isnan(lade) && lade > 5) {
              if (lade < 1000) snprintf(buf, sizeof(buf), "Lädt: %.0f W", lade);
              else             snprintf(buf, sizeof(buf), "Lädt: %.2f kW", lade/1000.0);
            } else if (!isnan(entlade) && entlade > 5) {
              if (entlade < 1000) snprintf(buf, sizeof(buf), "Entlädt: %.0f W", entlade);
              else                snprintf(buf, sizeof(buf), "Entlädt: %.2f kW", entlade/1000.0);
            } else {
              snprintf(buf, sizeof(buf), "Ruht");
            }
            return std::string(buf);

  - platform: homeassistant
    id: batterie_soc
    entity_id: sensor.byd_battery_box_premium_hv_ladezustand
    on_value:
      - lvgl.label.update:
          id: lbl_batterie_soc
          text: !lambda |-
            char buf[16];
            snprintf(buf, sizeof(buf), "%.0f%%", x);
            return std::string(buf);
      - lvgl.bar.update:
          id: bar_batterie_soc
          value: !lambda 'return (int) x;'
          animated: true

  - platform: homeassistant
    id: autarkie
    entity_id: sensor.solarnet_autarkiegrad
    on_value:
      - lvgl.label.update:
          id: lbl_autarkie
          text: !lambda |-
            char buf[16];
            snprintf(buf, sizeof(buf), "%.0f%%", x);
            return std::string(buf);
      - lvgl.bar.update:
          id: bar_autarkie
          value: !lambda 'return (int) x;'
          animated: true

  - platform: homeassistant
    id: eigenverbrauch
    entity_id: sensor.solarnet_eigenverbrauch
    on_value:
      - lvgl.label.update:
          id: lbl_eigenverbrauch
          text: !lambda |-
            char buf[16];
            snprintf(buf, sizeof(buf), "%.0f%%", x);
            return std::string(buf);
      - lvgl.bar.update:
          id: bar_eigenverbrauch
          value: !lambda 'return (int) x;'
          animated: true

  - platform: homeassistant
    id: garage_temp
    entity_id: sensor.garage_hinten_bewegungsmelder_air_temperature
    on_value:
      - lvgl.label.update:
          id: lbl_garage_temp
          text: !lambda |-
            char buf[16];
            snprintf(buf, sizeof(buf), "%.1f°C", x);
            return std::string(buf);

# Wetter ------------------------------------------------------------
text_sensor:
  - platform: homeassistant
    id: wetter_state
    entity_id: weather.forecast_home
    on_value:
      - lvgl.label.update:
          id: lbl_wetter_icon
          text: !lambda |-
            std::string state = x;
            if (state == "sunny")                    return std::string("\U000F0599");
            if (state == "clear-night")              return std::string("\U000F0596");
            if (state == "cloudy")                   return std::string("\U000F0590");
            if (state == "partlycloudy")             return std::string("\U000F0595");
            if (state == "rainy")                    return std::string("\U000F0597");
            if (state == "pouring")                  return std::string("\U000F067F");
            if (state == "snowy")                    return std::string("\U000F0598");
            if (state == "snowy-rainy")              return std::string("\U000F067E");
            if (state == "fog")                      return std::string("\U000F0594");
            if (state == "windy")                    return std::string("\U000F0F32");
            if (state == "lightning")                return std::string("\U000F0593");
            if (state == "lightning-rainy")          return std::string("\U000F067D");
            if (state == "hail")                     return std::string("\U000F0F38");
            return std::string("\U000F0F30");
      - lvgl.label.update:
          id: lbl_wetter_text
          text: !lambda |-
            std::string state = x;
            if (state == "sunny")           return std::string("Sonnig");
            if (state == "clear-night")     return std::string("Klar");
            if (state == "cloudy")          return std::string("Bewölkt");
            if (state == "partlycloudy")    return std::string("Teils bew.");
            if (state == "rainy")           return std::string("Regen");
            if (state == "pouring")         return std::string("Starkregen");
            if (state == "snowy")           return std::string("Schnee");
            if (state == "snowy-rainy")     return std::string("Schneeregen");
            if (state == "fog")             return std::string("Nebel");
            if (state == "windy")           return std::string("Windig");
            if (state == "lightning")       return std::string("Gewitter");
            if (state == "lightning-rainy") return std::string("Gewitterreg.");
            if (state == "hail")            return std::string("Hagel");
            return std::string(state);

# LVGL UI - QUERFORMAT 320x240 via Rotation 90 ----------------------
lvgl:
  displays:
    - main_display
  touchscreens:
    - touch
  rotation: 90

  style_definitions:
    - id: card_style
      bg_color: 0x222222
      bg_opa: COVER
      border_width: 0
      radius: 8
      pad_all: 6
      text_color: 0xFFFFFF

  pages:
    # ===== SEITE 1: PV LIVE =====
    - id: page_live
      bg_color: 0x000000
      on_swipe_left:
        - lambda: 'id(autoslide_pause) = 30;'
        - lvgl.page.next:
            animation: OVER_LEFT
            time: 300ms
      on_swipe_right:
        - lambda: 'id(autoslide_pause) = 30;'
        - lvgl.page.previous:
            animation: OVER_RIGHT
            time: 300ms
      widgets:
        - label:
            align: TOP_MID
            y: 4
            text: "PV LIVE"
            text_font: roboto_18
            text_color: 0xFFAA00

        - obj:
            id: pulse_dot
            x: 280
            y: 8
            width: 14
            height: 14
            radius: 7
            bg_color: 0x00FF00
            bg_opa: 12%
            border_width: 0

        - obj:
            x: 6
            y: 28
            width: 156
            height: 130
            styles: card_style
            bg_color: 0x1F3D1F
            widgets:
              - label:
                  align: TOP_MID
                  y: 6
                  text: "PV-Erzeugung"
                  text_font: roboto_14
                  text_color: 0xAAFFAA
              - label:
                  id: lbl_pv
                  align: CENTER
                  y: 8
                  text: "0 W"
                  text_font: roboto_36
                  text_color: 0x00FF00

        - obj:
            x: 168
            y: 28
            width: 146
            height: 72
            styles: card_style
            widgets:
              - label:
                  align: TOP_LEFT
                  x: 6
                  y: 4
                  text: "Verbrauch"
                  text_font: roboto_14
              - label:
                  id: lbl_verbrauch
                  align: BOTTOM_RIGHT
                  x: -6
                  y: -6
                  text: "0 W"
                  text_font: roboto_28
                  text_color: 0xFFCC00

        - obj:
            x: 168
            y: 106
            width: 71
            height: 52
            styles: card_style
            bg_color: 0x3D1F1F
            widgets:
              - label:
                  align: TOP_MID
                  y: 4
                  text: "Bezug"
                  text_font: roboto_12
                  text_color: 0xFF8888
              - label:
                  id: lbl_netzbezug
                  align: BOTTOM_MID
                  y: -4
                  text: "0 W"
                  text_font: roboto_14
                  text_color: 0xFF6666

        - obj:
            x: 243
            y: 106
            width: 71
            height: 52
            styles: card_style
            bg_color: 0x1F3D2F
            widgets:
              - label:
                  align: TOP_MID
                  y: 4
                  text: "Einspeis."
                  text_font: roboto_12
                  text_color: 0x88FF88
              - label:
                  id: lbl_einspeisung
                  align: BOTTOM_MID
                  y: -4
                  text: "0 W"
                  text_font: roboto_14
                  text_color: 0x66FF66

        - obj:
            x: 6
            y: 164
            width: 308
            height: 72
            styles: card_style
            bg_color: 0x1F2F4D
            widgets:
              - label:
                  align: TOP_LEFT
                  x: 6
                  y: 4
                  text: "Batterie"
                  text_font: roboto_14
                  text_color: 0xAACCFF
              - label:
                  id: lbl_batterie_soc
                  align: TOP_RIGHT
                  x: -6
                  y: 2
                  text: "--%"
                  text_font: roboto_18
                  text_color: 0xFFFFFF
              - bar:
                  id: bar_batterie_soc
                  align: CENTER
                  y: 2
                  width: 290
                  height: 10
                  min_value: 0
                  max_value: 100
                  value: 0
                  indicator:
                    bg_color: 0x44AAFF
              - label:
                  id: lbl_batterie_power
                  align: BOTTOM_MID
                  y: -4
                  text: "Ruht"
                  text_font: roboto_14
                  text_color: 0xCCDDFF

    # ===== SEITE 2: ENERGIEFLUSS =====
    - id: page_fluss
      bg_color: 0x000000
      on_swipe_left:
        - lambda: 'id(autoslide_pause) = 30;'
        - lvgl.page.next:
            animation: OVER_LEFT
            time: 300ms
      on_swipe_right:
        - lambda: 'id(autoslide_pause) = 30;'
        - lvgl.page.previous:
            animation: OVER_RIGHT
            time: 300ms
      widgets:
        - label:
            align: TOP_MID
            y: 4
            text: "ENERGIEFLUSS"
            text_font: roboto_18
            text_color: 0xFFAA00

        - obj:
            x: 8
            y: 80
            width: 80
            height: 80
            styles: card_style
            bg_color: 0x1F3D1F
            widgets:
              - label:
                  align: TOP_MID
                  y: 8
                  text: "PV"
                  text_font: roboto_18
                  text_color: 0xAAFFAA
              - label:
                  align: BOTTOM_MID
                  y: -8
                  text: "Solar"
                  text_font: roboto_14
                  text_color: 0x00FF00

        - obj:
            x: 92
            y: 117
            width: 60
            height: 6
            bg_color: 0x222222
            bg_opa: COVER
            border_width: 0
            radius: 0

        - obj:
            id: flow_pv_dot1
            x: 92
            y: 115
            width: 10
            height: 10
            radius: 5
            bg_color: 0x00FF00
            bg_opa: 24%
            border_width: 0
        - obj:
            id: flow_pv_dot2
            x: 108
            y: 115
            width: 10
            height: 10
            radius: 5
            bg_color: 0x00FF00
            bg_opa: 24%
            border_width: 0
        - obj:
            id: flow_pv_dot3
            x: 124
            y: 115
            width: 10
            height: 10
            radius: 5
            bg_color: 0x00FF00
            bg_opa: 24%
            border_width: 0
        - obj:
            id: flow_pv_dot4
            x: 140
            y: 115
            width: 10
            height: 10
            radius: 5
            bg_color: 0x00FF00
            bg_opa: 24%
            border_width: 0

        - obj:
            x: 156
            y: 80
            width: 80
            height: 80
            styles: card_style
            bg_color: 0x3D2F1F
            widgets:
              - label:
                  align: TOP_MID
                  y: 8
                  text: "Haus"
                  text_font: roboto_18
                  text_color: 0xFFE0AA
              - label:
                  align: BOTTOM_MID
                  y: -8
                  text: "Verbrauch"
                  text_font: roboto_12
                  text_color: 0xFFCC00

        - obj:
            x: 240
            y: 117
            width: 60
            height: 6
            bg_color: 0x222222
            bg_opa: COVER
            border_width: 0
            radius: 0

        - obj:
            id: flow_haus_dot1
            x: 240
            y: 115
            width: 10
            height: 10
            radius: 5
            bg_color: 0xFFAA44
            bg_opa: 24%
            border_width: 0
        - obj:
            id: flow_haus_dot2
            x: 256
            y: 115
            width: 10
            height: 10
            radius: 5
            bg_color: 0xFFAA44
            bg_opa: 24%
            border_width: 0
        - obj:
            id: flow_haus_dot3
            x: 272
            y: 115
            width: 10
            height: 10
            radius: 5
            bg_color: 0xFFAA44
            bg_opa: 24%
            border_width: 0
        - obj:
            id: flow_haus_dot4
            x: 288
            y: 115
            width: 10
            height: 10
            radius: 5
            bg_color: 0xFFAA44
            bg_opa: 24%
            border_width: 0

        - obj:
            x: 232
            y: 80
            width: 80
            height: 80
            styles: card_style
            bg_color: 0x1F2F4D
            widgets:
              - label:
                  align: TOP_MID
                  y: 8
                  text: "Netz"
                  text_font: roboto_18
                  text_color: 0xAACCFF
              - label:
                  align: BOTTOM_MID
                  y: -8
                  text: "Stromnetz"
                  text_font: roboto_12
                  text_color: 0xCCDDFF

    # ===== SEITE 3: BILANZ =====
    - id: page_bilanz
      bg_color: 0x000000
      on_swipe_left:
        - lambda: 'id(autoslide_pause) = 30;'
        - lvgl.page.next:
            animation: OVER_LEFT
            time: 300ms
      on_swipe_right:
        - lambda: 'id(autoslide_pause) = 30;'
        - lvgl.page.previous:
            animation: OVER_RIGHT
            time: 300ms
      widgets:
        - label:
            align: TOP_MID
            y: 4
            text: "BILANZ"
            text_font: roboto_18
            text_color: 0xFFAA00

        - obj:
            x: 8
            y: 30
            width: 152
            height: 200
            styles: card_style
            widgets:
              - label:
                  align: TOP_MID
                  y: 8
                  text: "Autarkiegrad"
                  text_font: roboto_14
                  text_color: 0xAAFFAA
              - label:
                  id: lbl_autarkie
                  align: CENTER
                  y: 0
                  text: "--%"
                  text_font: roboto_36
                  text_color: 0x00FF88
              - bar:
                  id: bar_autarkie
                  align: BOTTOM_MID
                  y: -16
                  width: 130
                  height: 12
                  min_value: 0
                  max_value: 100
                  value: 0
                  indicator:
                    bg_color: 0x00FF88

        - obj:
            x: 168
            y: 30
            width: 144
            height: 200
            styles: card_style
            widgets:
              - label:
                  align: TOP_MID
                  y: 8
                  text: "Eigenverbrauch"
                  text_font: roboto_14
                  text_color: 0xFFE0AA
              - label:
                  id: lbl_eigenverbrauch
                  align: CENTER
                  y: 0
                  text: "--%"
                  text_font: roboto_36
                  text_color: 0xFFCC44
              - bar:
                  id: bar_eigenverbrauch
                  align: BOTTOM_MID
                  y: -16
                  width: 122
                  height: 12
                  min_value: 0
                  max_value: 100
                  value: 0
                  indicator:
                    bg_color: 0xFFCC44

    # ===== SEITE 4: GARAGE & WETTER =====
    - id: page_garage
      bg_color: 0x000000
      on_swipe_left:
        - lambda: 'id(autoslide_pause) = 30;'
        - lvgl.page.next:
            animation: OVER_LEFT
            time: 300ms
      on_swipe_right:
        - lambda: 'id(autoslide_pause) = 30;'
        - lvgl.page.previous:
            animation: OVER_RIGHT
            time: 300ms
      widgets:
        - label:
            align: TOP_MID
            y: 4
            text: "AUSSEN"
            text_font: roboto_18
            text_color: 0xFFAA00

        - obj:
            x: 8
            y: 30
            width: 152
            height: 200
            styles: card_style
            bg_color: 0x1F2F4D
            widgets:
              - label:
                  align: TOP_MID
                  y: 8
                  text: "Wetter"
                  text_font: roboto_14
                  text_color: 0xAACCFF
              - label:
                  id: lbl_wetter_icon
                  align: CENTER
                  y: -10
                  text: "\U000F0F30"
                  text_font: mdi_72
                  text_color: 0xFFDD44
              - label:
                  id: lbl_wetter_text
                  align: BOTTOM_MID
                  y: -10
                  text: "..."
                  text_font: roboto_18
                  text_color: 0xCCDDFF

        - obj:
            x: 168
            y: 30
            width: 144
            height: 200
            styles: card_style
            bg_color: 0x3D2F1F
            widgets:
              - label:
                  align: TOP_MID
                  y: 8
                  text: "Garage"
                  text_font: roboto_14
                  text_color: 0xFFE0AA
              - label:
                  align: CENTER
                  y: -30
                  text: "Temperatur"
                  text_font: roboto_14
                  text_color: 0xFFCC88
              - label:
                  id: lbl_garage_temp
                  align: CENTER
                  y: 15
                  text: "--°C"
                  text_font: roboto_36
                  text_color: 0xFFCC44
1 „Gefällt mir“