CYD Cheap Yellow Display mit Home Assistant und ESP Home

Hallo,

ich habe in der HA Community ein interessantes Projekt gefunden. Über ESP-Home kann man das CYD Display in Home Assistant integrieren. Man hat im Anschluss zwei konfigurierbare Seiten, eine Startseite und eine Seite für Buttons aller Art. Hier der Link zum Projekt: CYD/Habbit Device to control HA - Share your Projects! - Home Assistant Community

Ich habe das mal versucht umzusetzen nach dieser Anleitung: Integrar la Cheap Yellow Display en HA - Aguacatec

Das hat auch gut funktioniert, aber zum Anfang gab es Schwierigkeiten mit der Darstellung des Displays. Das ist halt immer abhängig vom genutzten board. Nach etwas ausprobieren und lesen habe ich für mein Display die Settings für model und rotation im Code wie folgt geändert:

display:
  - platform: ili9xxx
    id: esp_display
    model: ili9341
    spi_id: tft
    cs_pin: GPIO15
    dc_pin: GPIO2
    rotation: 0
    invert_colors: false
    lambda: |-

Nun wurde auch der Code korrekt auf dem Display dargestellt. Also habe ich begonnen das Setup des Displays selber vorzunehmen und meine Entitäten aus HA entsprechend umgeschrieben bzw. ergänzt.

Dabei ist mir auch aufgefallen, dass die letzten beiden Button auf der zweiten Seite von der Anordnung her nicht stimmen und nur in den Ecken gedrückt werden konnten. Das habe ich entsprechend korrigiert. Hier meine quick and dirty angepasste Version:

esphome:
  name: cyd
  friendly_name: CYD Schlafzimmer

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "secret"

ota:
  - platform: esphome
    password: "secret"

wifi:
  ssid: "secret"
  password: "secret"

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Cyd Fallback Hotspot"
    password: "LEMTsad123"

captive_portal:

globals:
  - id: show_return_page
    type: bool
    restore_value: yes
    initial_value: "false"

# Setup a pin to control the backlight and the LED
output:
  - platform: ledc
    pin: GPIO21
    id: backlight_pwm
  - platform: ledc
    id: output_red
    pin: GPIO4
    inverted: true
  - platform: ledc
    id: output_green
    pin: GPIO16
    inverted: true
  - platform: ledc
    id: output_blue
    pin: GPIO17
    inverted: true

light:
  - platform: monochromatic
    output: backlight_pwm
    name: Display Backlight
    id: backlight
    restore_mode: ALWAYS_ON
  - platform: rgb
    name: LED
    red: output_red
    id: led
    green: output_green
    blue: output_blue
    restore_mode: ALWAYS_OFF

# Setup SPI for the display. The ESP32-2432S028R uses separate SPI buses for display and touch
spi:
  - id: tft
    clk_pin: GPIO14
    mosi_pin: GPIO13
    miso_pin: GPIO12
  - id: touch
    clk_pin: GPIO25
    mosi_pin: GPIO32
    miso_pin: GPIO39

touchscreen:
  platform: xpt2046
  spi_id: touch
  cs_pin: GPIO33
  interrupt_pin: GPIO36
  update_interval: 50ms
  threshold: 400
  calibration:
    x_min: 3860
    x_max: 280
    y_min: 340
    y_max: 3860
  transform:
    swap_xy: false   

# Create a font to use, add and remove glyphs as needed. 
# Crea las fuente que quieres utilizar, añade o quita los caracteres que necesites.

font:
  - file: "gfonts://Itim"
    id: fecha
    size: 15
  - file: "gfonts://Itim"
    id: fetcha
    size: 17  
  - file: "gfonts://Kanit"
    id: hora
    size: 60
  - file: "gfonts://Roboto"
    id: info
    size: 15
  - file: "gfonts://Roboto"
    id: botones
    size: 11

# Create the colors you want to use.
# Crea los colores que quieres utilizar.

color:
  - id: black
    hex: '000000'
  - id: orange
    hex: 'eb9c17'
  - id: red
    hex: 'b20b23'
  - id: green
    hex: '148e23'  
  - id: grey
    hex: '464646'
    
# Create the icons you want to use.
# Crea los iconos que quieres utilizar.

image:
  - file: mdi:home-thermometer
    id: hometemperature
    resize: 40x40
  - file: mdi:weather-partly-cloudy
    id: weather
    resize: 40x40
  - file: mdi:solar-power-variant
    id: finance
    resize: 40x40
  - file: mdi:transmission-tower
    id: health
    resize: 40x40
  - file: mdi:page-previous
    id: back
    resize: 40x40
  - file: mdi:lightbulb-group-off-outline
    id: fan
    resize: 40x40
  - file: mdi:floor-lamp-torchiere
    id: thermostat
    resize: 40x40
  - file: mdi:mirror-rectangle
    id: vacuum
    resize: 40x40
  - file: mdi:led-strip-variant
    id: desk
    resize: 40x40
  - file: mdi:desk-lamp
    id: printer
    resize: 40x40
  - file: mdi:lightbulb
    id: printer3d
    resize: 40x40
  - file: mdi:home-assistant
    id: habbit
    resize: 40x40

# Replace the home gif as you want.
# Reemplaza el gif the inicio como quieras.

#animation:
#  - file: "habbit.gif"
#    id: ha
#    resize: 70x70
#    type: TRANSPARENT_BINARY

# This will fetch time from Home Assistant
time:
  - platform: homeassistant
    id: esptime

# Create sensors from HA you want to use and show.
# Crea los sensores de HA que quieres utilizar y mostrar.

sensor:
  - platform: homeassistant
    id: temperatura
    entity_id: sensor.wandthermostat_jan_temperatur
    internal: true
  - platform: homeassistant
    id: humedad
    entity_id: sensor.wandthermostat_jan_luftfeuchtigkeit
    internal: true
  - platform: homeassistant
    id: tempexterior
    entity_id: sensor.aussentemperatur_temperatur
    internal: true
  - platform: homeassistant
    id: problluvia
    entity_id: sensor.aussentemperatur_luftfeuchtigkeit
    internal: true
  - platform: homeassistant
    id: solarkwh
    entity_id: sensor.homestation_solar_total_energie_heute
    internal: true
  - platform: homeassistant
    id: netzeinsp
    entity_id: sensor.solar_netzeinspeisung_kwh_taglich
    internal: true
  - platform: homeassistant
    id: weight
    entity_id: sensor.stromverbrauch_taglich
    internal: true
  - platform: homeassistant
    id: distancia
    entity_id: sensor.stromverbrauch_gesamt_kwh
    internal: true
  - platform: homeassistant
    id: totalstrom
    entity_id: sensor.total_power_nur_verbrauch
    internal: true

text_sensor:
  - platform: homeassistant
    id: aireacondicionado
    entity_id: scene.lichtgruppe_wohnzimmer_aus
    internal: true
  - platform: homeassistant
    id: calefaccion
    entity_id: light.schlafzimmerlicht
    internal: true
  - platform: homeassistant
    id: aspirador
    entity_id: switch.bad_spiegellicht
    internal: true
  - platform: homeassistant
    id: escritorio
    entity_id: light.wandlicht
    internal: true
  - platform: homeassistant
    id: impresora
    entity_id: switch.pc_led_pv_led
    internal: true
  - platform: homeassistant
    id: impresora3d
    entity_id: light.couchlicht
    internal: true

# Assigns a function to each button, by calling the corresponding service in HA.
# Asigna una función a cada botón, llamando al servicio correspondiente en HA.

binary_sensor:
  - platform: touchscreen
    name: Button 1
    x_min: 0
    x_max: 140
    y_min: 0
    y_max: 65
    on_press:
      then:
        - if:
            condition:
              lambda: 'return !id(show_return_page);'
            then:
              - globals.set:
                  id: show_return_page
                  value: !lambda "return !id(show_return_page);"
            else:
              - homeassistant.service:
                  service: scene.toggle
                  data:
                    entity_id: scene.lichtgruppe_wohnzimmer_aus
  - platform: touchscreen
    name: Button 2
    x_min: 140
    x_max: 280
    y_min: 0
    y_max: 65
    on_press:
      then:
        - if:
            condition:
              lambda: 'return !id(show_return_page);'
            then:
              - globals.set:
                  id: show_return_page
                  value: !lambda "return !id(show_return_page);"
            else:
              - homeassistant.service:
                  service: light.toggle
                  data:
                    entity_id: light.schlafzimmerlicht
  - platform: touchscreen
    name: Button 3
    x_min: 0
    x_max: 140
    y_min: 65
    y_max: 130
    on_press:
      then:
        - if:
            condition:
              lambda: 'return !id(show_return_page);'
            then:
              - globals.set:
                  id: show_return_page
                  value: !lambda "return !id(show_return_page);"
            else:
              - homeassistant.service:
                  service: switch.toggle
                  data:
                    entity_id: switch.bad_spiegellicht
  - platform: touchscreen
    name: Button 4
    x_min: 140
    x_max: 280
    y_min: 65
    y_max: 130
    on_press:
      then:
        - if:
            condition:
              lambda: 'return !id(show_return_page);'
            then:
              - globals.set:
                  id: show_return_page
                  value: !lambda "return !id(show_return_page);"
            else:
              - homeassistant.service:
                  service: light.toggle
                  data:
                    entity_id: light.wandlicht
  - platform: touchscreen
    name: Button 5
    x_min: 0
    x_max: 140
    y_min: 130
    y_max: 195
    on_press:
      then:
        - if:
            condition:
              lambda: 'return !id(show_return_page);'
            then:
              - globals.set:
                  id: show_return_page
                  value: !lambda "return !id(show_return_page);"
            else:
              - homeassistant.service:
                  service: switch.toggle
                  data:
                    entity_id: switch.pc_led_pv_led
  - platform: touchscreen
    name: Button 6
    x_min: 140
    x_max: 280
    y_min: 130
    y_max: 195
    on_press:
      then:
        - if:
            condition:
              lambda: 'return !id(show_return_page);'
            then:
              - globals.set:
                  id: show_return_page
                  value: !lambda "return !id(show_return_page);"
            else:
              - homeassistant.service:
                  service: light.toggle
                  data:
                    entity_id: light.couchlicht
  - platform: touchscreen
    name: Button 7
    x_min: 0
    x_max: 140
    y_min: 195
    y_max: 260
    on_press:
      then:
        - if:
            condition:
              lambda: 'return !id(show_return_page);'
            then:
              - globals.set:
                  id: show_return_page
                  value: !lambda "return !id(show_return_page);"
  - platform: touchscreen
    name: Button 8
    x_min: 140
    x_max: 280
    y_min: 195
    y_max: 260
    on_press:
      then:
        - globals.set:
            id: show_return_page
            value: !lambda "return !id(show_return_page);"

# Setup the ili9xxx platform
# Display is used as 240x320 by default so we rotate it to 90°     model: ili9342 changed to model: ili9341

display:
  - platform: ili9xxx
    id: esp_display
    model: ili9341
    spi_id: tft
    cs_pin: GPIO15
    dc_pin: GPIO2
    rotation: 0
    invert_colors: false
    lambda: |-
      if (id(show_return_page)) {
        int button_width = 100;
        int button_height = 65;
        int x_start = 15;
        int y_start = 15;
        int x_padding = 10;
        int y_padding = 10;

        // Define los textos para los botones
        const char* button_texts[] = {
          "Wohnzimmer",
          "Schlafzimmer",
          "Badlicht",
          "Wandlicht",
          "PC-Licht",
          "Couchlicht",
          "Free",
          "Start"
        };

        for (int row = 0; row < 4; row++) {
          for (int col = 0; col < 2; col++) {
            int button_index = row * 2 + col;
            int x = x_start + col * (button_width + x_padding);
            int y = y_start + row * (button_height + y_padding);
            it.rectangle(x, y, button_width, button_height, id(grey));
            int text_width = strlen(button_texts[button_index]) * 5.5; 
            int text_height = 16; 
            it.print(x + (button_width - text_width) / 2, y + (button_height - text_height) / 2 + 20, id(botones), button_texts[button_index]);
          }
        }
        if (id(aireacondicionado).state == "on") {
          it.image(45, 20, id(fan), id(orange));
        } else {
          it.image(45, 20, id(fan), id(grey));
        }
        if (id(calefaccion).state == "on") {
          it.image(155, 20, id(thermostat), id(orange));
        } else {
          it.image(155, 20, id(thermostat), id(grey));
        }
        if (id(aspirador).state == "on") {
          it.image(45, 95, id(vacuum), id(orange));
        } else {
          it.image(45, 95, id(vacuum), id(grey));
        }
        if (id(escritorio).state == "on") {
          it.image(155, 95, id(desk), id(orange));
        } else {
          it.image(155, 95, id(desk), id(grey));
        }
        if (id(impresora).state == "on") {
          it.image(45, 170, id(printer), id(orange));
        } else {
          it.image(45, 170, id(printer), id(grey));
        }
        if (id(impresora3d).state == "on") {
          it.image(155, 170, id(printer3d), id(orange));
        } else {
          it.image(155, 170, id(printer3d), id(grey));
        }
        it.image(45, 245, id(habbit), id(grey));
        it.image(155, 245, id(back), id(green));

      } else {
        static int y = 182;
        static int y_direction = 4;  // Velocidad del movimiento
        const int y_min = 180;       
        const int y_max = 187;       

        it.fill(id(black));
        it.strftime(120, 55, id(fecha), TextAlign::CENTER, "%d/%m/%Y", id(esptime).now());
        it.strftime(120, 92, id(hora), TextAlign::CENTER, "%H:%M", id(esptime).now());
        it.printf(120, 135, id(fetcha), TextAlign::CENTER, "Aussentemp %.1f C", id(tempexterior).state);
        it.line(50, 150, 190, 150);
        it.printf(120, 163, id(fetcha), TextAlign::CENTER, "Hausstr %.1f W", id(totalstrom).state);
        
        static int current_text_index = 0;
        static float text_timer = 0;
        const float text_interval = 4.0;  // Intervalo para cambiar el texto en segundos

        text_timer += 1.0;  
        if (text_timer >= text_interval) {
          text_timer = 0;
          current_text_index = (current_text_index + 1) % 4;  // Alternar entre cuatro textos
        }

        if (current_text_index == 0) {
          it.image(15, 260, id(hometemperature), id(orange));
          it.print(70, 260, id(info), "Temperatur");
          it.printf(175, 260, id(info), "%.1f C", id(temperatura).state);
          it.print(70, 280, id(info), "Luftfeuchte");
          it.printf(175, 280, id(info), "%.1f %%", id(humedad).state);
        } else if (current_text_index == 1) {
          it.image(15, 260, id(weather), id(orange));
          it.print(70, 260, id(info), "Temperatur");
          it.printf(175, 260, id(info), "%.1f C", id(tempexterior).state);
          it.print(70, 280, id(info), "Au Luftfeuchte");
          it.printf(175, 280, id(info), "%.1f %%", id(problluvia).state);
        } else if (current_text_index == 2) {
          it.image(15, 260, id(finance), id(green));
          it.print(70, 260, id(info), "Solarertrag");
          it.printf(175, 260, id(info), "%.1f kWh", id(solarkwh).state);
          it.print(70, 280, id(info), "Einspeisung");
          it.printf(175, 280, id(info), "%.1f kWh", id(netzeinsp).state);
        } else if (current_text_index == 3) {
          it.image(15, 260, id(health), id(red));
          it.print(70, 260, id(info), "Strom heute");
          it.printf(175, 260, id(info), "%.1f kWh", id(weight).state);
          it.print(70, 280, id(info), "Strom total");
          it.printf(175, 280, id(info), "%.1f kWh", id(distancia).state);
        }
      }

Zum Abschluß brauchte ich natürlich noch ein passendes Gehäuse. Ich habe den Ständer selber gezeichnet und ein fertiges Gehäuse dazu ausgedruckt. Das Gehäuse ist auf meiner Druckseite mit verlinkt.

Jetzt steht das Display auf meinem Nachttisch und zeigt mir die wichtigsten Daten an. Auf Seite zwei habe ich die Hauptlichter hinterlegt.
Vielleicht hat ja der ein oder andere Interesse bzw. Lust so etwas zu basteln. :slight_smile:

Grüße Jayson

2 „Gefällt mir“

Hallo Jayson
Danke für die Beschreibung.
Ich habe noch einen CYD bei mir daheim rumliegen und war genau auf der Suche nach so etwas.
Allerdings habe ich als Anfänger 2 Fragen.
Wo bekommst Du den API-Key für HA und das Passwort für ota her.

EDIT:
OK ich habe gerade in der Beschreibung vom Link gefunden, dass ich diese im Originalcode von ESP-Home finde :sweat_smile:

Wer lesen kann ist klar im Vorteil :laughing:

Hi, korrekt das findest du beim erstellen des ESP Home Gerätes. Dann einfach in Editor kopieren und im Anschluss im neuen Code entsprechend austauschen.

Schön, genauso ging es mir auch. Wusste nicht so richtig was ich mit dem CYD jetzt mache und ist eine echt günstige Lösung für knapp 10€

Grüße Jayson

Hi, tolles Projekt, bin auch gerade dabei. Wo hast du denn die Einstellung für die verschiedenen Displays gefunden


So sieht es im Moment bei mir aus.

Danke

Gruß

André

Spannend! erst recht für den Preis!

Ich nehme an, ich kann auf dem Display prinzipiell alles darstellen? Und wenn es “nur”…Die Uhrzeit ist?
Ich spiele darauf an: Updated BVG (Berlin public transit) sensor - #2 by LukeAno - Share your Projects! - Home Assistant Community
Ich habs aktuell auf meinem Homescreen/Dashboard von HA, würde es mit de r Zeit aber auch gern auf ein externes Display packen.
Ich hab ein E-ink gedacht - aber das wäre schon nicht günstig.

Moin, ich habe da einfach herumprobiert und im Netzt geschaut nach model: ili9342. Dabei ist mir aufgefallen, dass es Modell ili9341 gibt. Weißt es nicht genau, aber gibt bestimmt auch noch andere. Im Prinzip sieht es bei dir korrekt aus, daher würde ich erstmal nur die Rotation wieder auf 90 setzen. Wenn das nicht geht, kannst du den nachfolgenden Code gerne mal testen.

  - platform: ili9xxx
    id: esp_display
    model: ili9342
    spi_id: tft
    cs_pin: GPIO15
    dc_pin: GPIO2
    rotation: 90

@Luke Wäre mal ein Versuch wert und sollte eigentlich auch funktionieren.

Ich finde so spannend, dass man die Teile echt günstig kaufen kann. :slight_smile:

Danke, bei mir wars ein ili9342, das funktioniert jetzt. Hier gibt es eine gute Übersicht
Im Netzwerk ist erlaubt LanScan auch, irgendwie fehlt mir noch die Verbindung zum HA. Kann den HA irgendwo explizit angeben?

Gruß

André

Eigentlich nein, kann ich dir aber auch nicht genau sagen. Man legt ja ein ESP-Home Gerät unter HA an und überträgt von dort den Code, dann sollte es korrekt in HA laufen und eingebunden sein.

Dachte ich auch, ich habe da schon einiges getestet, werde es einfach einmal sauber aufsetzen.

Gruß

André