ESP32 mit 1.3 Zoll OLED Display

Hallo zusammen,
ich experimentiere gerade mit einem ESP32 auf einem Breakout Board mit
einem 1.3 Zoll OLED Display.

Das Teil soll mir im Bad die Temperatur und Luftfeuchte anzeigen inkl. Datum und Uhrzeit. Das klappt auch schonmal (s. Bild).

Ich möchte nun bei Nutzung meiner OralB IO Zahnbürste eine zweite Page auf dem OLED Display anzeigen lassen und mir die Zahnputzzeit anzeigen lassen.
Wie das in der Theorie funktionieren soll steht auf der ESPHome-Seite, nur verstehe ich die Vorgehensweise nicht. Kann mir bei diesem Problem jemand helfen?

Am besten dann die von meiner Frau und mir (sofern wir beide putzen). Die Zahnbürsten sind bereits in Homeassistant vorhanden und lassen sich auch mir einer einfach Automation einbinden.

Der aktuelle Code für den ESP32 lautet:

esphome:
  name: espbad
  friendly_name: espbad

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

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

ota:
  password: "xxxxxxxxxxxxxxxxxxxxxxxxx"

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: !secret fallback_ssid 
    password: !secret fallback_password 


# Zeit holen für ESP
time:
  - platform: homeassistant
    id: esptime

captive_portal:

i2c:
  sda: GPIO16
  scl: GPIO17

font:
  - file: "fonts/Verdana.ttf"
    id: verdana10
    size: 10
  - file: "fonts/Verdana.ttf"
    id: verdana12
    size: 12

display:
  - platform: ssd1306_i2c
    model: "SH1106 128x32"
  
    lambda: |-    
      it.printf(0, 0, id(verdana10), "%.1f °C", id(temp).state);
      it.printf(85, 0, id(verdana10), "%.1f %%", id(hum).state);
      it.line(0,14,128,14);
      it.strftime(2, 15, id(verdana12), "%d.%m.%Y - %H:%M", id(esptime).now());

sensor:
  - platform: homeassistant
    name: Temperatur
    id: temp
    entity_id: sensor.temperatur_bad

  - platform: homeassistant
    name: Luftfeuchte
    id: hum
    entity_id: sensor.lf_bad

Viele Grüße
AndiFidi

1 „Gefällt mir“

Moin @andifidi,
Du hast zwei Codeblöcke in Deinem ESP YAML:
in meinem Beispiel das drücken eines Touch-sensor und zeitlich begrenzte Anzeige von H/T Daten auf dem Display und weitere Informationen

  1. den Aufruf der Seiten mit einer “on_…:”-Aktion
binary_sensor:
  - platform: esp32_touch
    pin: 12
    name: "Touch_5" # es ist T5 des ESP32
    threshold: 500
    id: touch
    on_press: # für 20 sec das Display anzeigen
      - lambda: id(oled).turn_on();
      - display.page.show: page1 # 5 sec Seite 1 
      - delay: 5s
      - display.page.show: page2 # 5 sec Seite 2 
      - delay: 5s
      - display.page.show: page3 # 10 sec Seite 3
      - delay: 10s
      - display.page.show: page1 # und wieder zurück auf page1
      - lambda: id(oled).turn_off(); # ... und AUS
  1. die Display-Funktionen mit den Seitenbeschreibungen
# 1.3" OLED Display 128x64 mit SH1106 I2C Interface
i2c: #I2C Adresspins
  sda: 21
  scl: 22

font: # Zeichensatz für Display in config/esphome
  - file: "din1451m.ttf" # Schriftgröße Displayhöhe 1-zeilig
    id: my_font_A
    size: 40
  - file: "din1451m.ttf" # mittlere Schriftgröße für Statusseite 2-zeilig
    id: my_font_M
    size: 22
  - file: "din1451m.ttf" # kleine Schriftgröße für Statusseite 4-zeilig
    id: my_font_K
    size: 15  

display: # Display Anzeige
  - platform: ssd1306_i2c
    model: "SH1106 128x64"
    address: 0x3C
    contrast: 50%
    # rotation: 0
    id: oled
    pages:
      - id: page1
        lambda: |-
          it.printf(64, 0, id(my_font_K), TextAlign::TOP_CENTER, "Garage");
          it.printf(0, 20, id(my_font_M), TextAlign::TOP_LEFT, "%.1f °C", id(GAR_TO).state);
          it.printf(128, 20, id(my_font_M) ,TextAlign::TOP_RIGHT, "%.1f %%", id(GAR_HO).state);
          it.printf(0, 40, id(my_font_M), TextAlign::TOP_LEFT, "%.1f °C", id(GAR_TU).state);
          it.printf(128, 40, id(my_font_M) ,TextAlign::TOP_RIGHT, "%.1f %%", id(GAR_HU).state);
      # Anzeige der Garagentemperatur und -feuchte auf Display
      
      - id: page2
        lambda: |-
          it.printf(64, 0, id(my_font_K), TextAlign::TOP_CENTER, "Aussentemperatur");
          it.printf(64, 20, id(my_font_A), TextAlign::TOP_CENTER, "%.1f °C", id(Aussen_temp).state);
      # Anzeige der Aussentemperatur Nordseite
          
      - id: page3
        lambda: |-
          it.printf(64, 0, id(my_font_K), TextAlign::TOP_CENTER, "DKB4 Status");
          if (apiCo) {
              it.printf(88, 16, id(my_font_K),"coAPI");
          } else {
              it.printf(88, 16, id(my_font_K),"ncAPI");
          }
          it.printf(0, 16, id(my_font_K),"%.1f °C", id(Geh_temp).state);
          it.printf(0, 32, id(my_font_K),"%.1f dBm", id(wifi_signal_db).state);
          it.printf(90, 32, id(my_font_K),"%.0f %%", id(wifi_signal_p).state);  
      # ESP32 Status Gehäusetemperatur und WiFi Signalstärke [dBm] & [%]und API Connection
      # % ist ein Format Zeichen, das %% bringt ein "%" auf das Display!

Gruß
Frank

Hi @FrankS
Vielen Dank, das hilft schon ein wenig.
Ich habe mal etwas probiert, mein Code sieht aktuell so aus:

esphome:
  name: espbad
  friendly_name: espbad

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

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

ota:
  password: "xxxxxxx"

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: !secret fallback_ssid
    password: !secret fallback_password

sensor:
  - platform: homeassistant
    name: Temperatur
    id: temp
    entity_id: sensor.temperatur_bad

  - platform: homeassistant
    name: Luftfeuchte
    id: hum
    entity_id: sensor.lf_bad

  - platform: homeassistant
    name: Putzzeit_A
    id: putza
    entity_id: sensor.oral_b_andreas_time
  
  - platform: homeassistant
    name: Putzzeit_N
    id: putzn
    entity_id: sensor.oral_b_nicole_time
  
  - platform: homeassistant
    name: Außentemperatur
    id: aussentemp
    entity_id: sensor.aussen

  - platform: homeassistant
    name: Außenluftfeuchte
    id: aussenlf
    entity_id: sensor.balkon   


# Zeit holen für ESP
time:
  - platform: homeassistant
    id: esptime

captive_portal:

i2c:
  sda: GPIO16
  scl: GPIO17

font:
  - file: "fonts/Verdana.ttf"
    id: verdana10
    size: 10
  - file: "fonts/Verdana.ttf"
    id: verdana12
    size: 12

display:
    - platform: ssd1306_i2c
      model: "SH1106 128x32"
      id: oled
      pages:
        - id: page1
          lambda: |-  
            it.printf(0, 0, id(verdana10), "%.1f °C", id(temp).state);
            it.printf(85, 0, id(verdana10), "%.1f %%", id(hum).state);
            it.line(0,14,128,14);
            it.strftime(2, 15, id(verdana12), "%d.%m.%Y - %H:%M", id(esptime).now());

        - id: page2
          lambda: |-  
            it.printf(0, 0, id(verdana10), "Andreas: %.1f min.", id(putza).state);
            it.line(0,14,128,14);
            it.printf(0, 15, id(verdana10), "Nicole: %.1f min.", id(putzn).state);

        - id: page3
          lambda: |-  
            it.printf(0, 0, id(verdana10), "Balkon Temp: %.1f °C", id(aussentemp).state);
            it.line(0,14,128,14);
            it.printf(0, 15, id(verdana10), "Balkon LF: %.1f %%", id(aussenlf).state);           
interval:
  - interval: 5s
    then:
      - display.page.show_next: oled
      - component.update: oled

Man muss feststellen, dass dieser Syntax wirklich sehr fehleranfällig ist. Ein Tab falsch und es funktioniert nicht :slight_smile:

Was ich noch nicht verstanden habe, ist der Syntax on_xxxx
on_press ist in meinem Beispiel nicht möglich. Denkbar wäre aber wenn ein Sensor aus Homeassistant z.B. Zahnbürstetimer startet, dann zeige Page01 an.
Wir würde man sowas lösen können?
Gruß
AndiFidi

Hi. Auch wenn der Artikel schon älter ist, so blieb die letzte Frage unbeantwortet, was ich hiermit nachholen will, weil ich beim googlen der Frage hier gelandet bin und das vielleicht auch anderen passiert. Die dokumentation zu pages auf dem display ist ausgezeichnet und wurde auch gut umgesetzt. Nun ist das Blättern in den pages eine Aktion die getriggert werden muss. Im Beispiel oben wird dies durch die komponente interval: gemacht. Um dies nun über einen button oder einen Sensorwert zu machen kommen die Actions ins Spiel (on_press, on_value, usw.)Diese werden im Boolean (schalter, button, etc.) mit on_press, on_click, etc. und im Sensor mit on_value ausgelöst.

button:
  name: button
  on_press:
      - display.page.show_next: oled
      - component.update: oled

sensor:
  name: sensor
  on_value:
    if:
      condition:
        sensor.state: # HIER kommt der 
          id: my_sensor
          state: 'on'
    then:
      - display.page.show_next: oled
      - component.update: oled

Dies kann dann ins unendliche mit if/else , while , usw. kombiniert werden, um automationen direkt auf dem esp abzubilden. Wichtig ist nur die Zusammenhänge (trigger, actions) zu verstehen, dann klappt der Rest bald von alleine. in o.g. Fall wäre ein Boolean gut der einfach nur sagt: zahnbürste an oder aus und dann kann dies als trigger für page_1 und page_2 verwendet werden. oder ein numerischer trigger aus der oral integration, der den nutzer wiederspiegelt um dann
kein nutzer→ page 1
nutzer 1 → page 2
nutzer 2 → page 3
anzeigen zu können. Wenn man page 1 & 4 im intervall anzeigen will, wenn zahnbürste inaktiv und entweder page 2 oder 3 (nutzerabhängig) wenn Zahnbürste aktiv, dann sähe das so aus:


sensor:
  - platform: homeassistant
    name: Zahnbürste aktiv
    id: oralaktiv
    entity_id: input_boolean.oral_b_aktiv # diese entität muss ggfls umbenannt oder als helfer in HA angelegt werden

  - platform: homeassistant
    name: Nutzer Nr
    id: nutzer_id
    entity_id: number.oral_b_nutzer # diese entität muss ggfls umbenannt oder als helfer in HA angelegt werden

display:
  - platform: ssd1306_i2c
    model: "SH1106 128x32"
    id: oled
    pages:
      - id: page1
        lambda: |-
          it.printf(0, 0, id(verdana10), "%.1f °C", id(temp).state);
          it.printf(85, 0, id(verdana10), "%.1f %%", id(hum).state);
          it.line(0,14,128,14);
          it.strftime(2, 15, id(verdana12), "%d.%m.%Y - %H:%M", id(esptime).now());

      - id: page2
        lambda: |-
          it.printf(0, 0, id(verdana10), "Balkon Temp: %.1f °C", id(aussentemp).state);
          it.line(0,14,128,14);
          it.printf(0, 15, id(verdana10), "Balkon LF: %.1f %%", id(aussenlf).state);

      - id: andreas
        lambda: |-
          it.printf(0, 0, id(verdana10), "Andreas: %.1f min.", id(putza).state);

      - id: nicole
        lambda: |-
          it.printf(0, 15, id(verdana10), "Nicole: %.1f min.", id(putzn).state);
    update_interval: 3s # sorgt dafür das alle 3 sekunden das display aktualisiert wird
    lambda: |-
      static int current_page_num = 1;
      int number_of_pages = 2; // Seiten die automatisch gewechselt werden sollen 1-?
      
      // der Teil erkennt ob und welcher Nutzer aktiv ist und zeigt statisch die entsprechende Seite an
      if (id(oralaktiv)){
        if (id(nutzer_id).state == '2'){
          return id(nicole);  
        } else { 
          return id(andreas); // Nutzer 1 ist Standard weitere Nutzer können mit else if angefügt werden
        }
      } else { // Ist kein Nutzer aktiv werden die Wechselseiten angezeigt 
        
      // der switch kann an Hand der number_of_pages und entsprechenden Anzahl an pages erweitert werden
        switch (current_page_num) {
      
          case 1:
          return id(page1);
          break;
        
          case 2:
          return id(page2);
          break;
              
          default:
          break;         
        }
        current_page_num += 1;
        if (current_page_num > number_of_pages) {
          current_page_num = 1;
        }
      }

      ESP_LOGD("display", "Page: %f", id(current_page_num).state);


Noch als Anmerkung: sollte der Aufruf der pages im lambda: Block so nicht funktionieren (ungetestet), dann statt der return id(page); Zeile direkt die Displayzeilen eintragen und auf den pages: Block verzichten (so läuft es bei mir reibungslos aber es hätte im Code die Trennung zwischen Neu und Alt verwaschen und so unleserlicher gemacht.