Esphome i menu / podmenu wyswietlacza lcd1602 / 2004

Witam
Walczę z menu na wyswietlaczu 2004 do wyswietlania odczytanych danych z Wmbus na kilku mieszkaniach. Aktualnie mogę za pomocą encodera i przycisku przechodzic po menu i wracac ale nie wiem jak zmusić wyswietlanie stanu licznika w odpowiednim podmenu. Funkcja return id wyswietla poprawnie tylko adres ip. a potrzebowałby w podmenu informacje " woda zimna" - licznik, " woda ciepla" - licznik. Jak w w drugim przykładzie

esp32:
  board: esp32dev
  framework:
    type: arduino

time:
  - platform: sntp
    id: time_sntp
    timezone: Europe/Berlin
# Enable logging
logger:

# Enable Home Assistant API
api:

# Allow Over-The-Air updates
ota:
- platform: esphome

# Allow provisioning Wi-Fi via serial
improv_serial:

wifi:
  # Set up a wifi access point
  ap: {}

# In combination with the `ap` this allows the user
# to provision wifi credentials to the device via WiFi AP.
captive_portal:

# Sets up Bluetooth LE (Only on ESP32) to allow the user
# to provision wifi credentials to the device.
# esp32_improv:
#  authorizer: none

# To have a "next url" for improv serial
web_server:
  port: 80
  version: 3
  auth:
    username: !secret web_server_username
    password: !secret web_server_password

external_components:
  - source: github://SzczepanLeon/esphome-components@main
#  - source: github://SzczepanLeon/esphome-components@2.4.10
#  - source: github://SzczepanLeon/esphome-components@3.2.3
    refresh: 0d
    components: [ wmbus ]

wmbus:
  frequency: 868.950
  mosi_pin: GPIO23
  miso_pin: GPIO19
  clk_pin:  GPIO18
  cs_pin:   GPIO15
  gdo0_pin: GPIO16
  gdo2_pin: GPIO17
#  led_blink_time: "1s"

  all_drivers: false
  sync_mode: True
  log_all: True

i2c:
  sda: 21
  scl: 22
  scan: True
  frequency: 400kHz

display:
  - platform: lcd_pcf8574
    dimensions: 20x4
    address: 0x27
    id: my_lcd
    lambda: |-
      id(my_lcd_menu).draw();
      if (!id(my_lcd_menu).is_active())
        it.print("Menu is not active");

# Declare a LCD menu
lcd_menu:
  id: my_lcd_menu
  display_id: my_lcd
  active: true
  mode: rotary
  on_enter:
    then:
      lambda: 'ESP_LOGI("display_menu", "root enter");'
  on_leave:
    then:
      lambda: 'ESP_LOGI("display_menu", "root leave");'
  items:
  - type: menu
    text: 'Max'
    on_enter:
      then:
        lambda: 'ESP_LOGI("display_menu", "enter: %s", it->get_text().c_str());'
    on_leave:
      then:
        lambda: 'ESP_LOGI("display_menu", "leave: %s", it->get_text().c_str());'
    items:
      - type: back
        text: 'Back'
      - type: label
        text: 'tekst'

  - type: menu
    text: 'Moja'
    on_enter:
      then:
        lambda: 'ESP_LOGI("display_menu", "enter: %s", it->get_text().c_str());'
    on_leave:
      then:
        lambda: 'ESP_LOGI("display_menu", "leave: %s", it->get_text().c_str());'
    items:
      - type: back
        text: 'Back'
      - type: menu
        text: 'Mieszkanie1'
        on_enter:
          then:
            lambda: 'ESP_LOGI("display_menu", "enter: %s", it->get_text().c_str());'
        on_leave:
          then:
            lambda: 'ESP_LOGI("display_menu", "leave: %s", it->get_text().c_str());'
        items:
          - type: back
            text: 'Back'
          - type: label
            text: 'lambda z danymi'
      - type: menu
        text: 'Mieszkanie2'
        on_enter:
          then:
            lambda: 'ESP_LOGI("display_menu", "enter: %s", it->get_text().c_str());'
        on_leave:
          then:
            lambda: 'ESP_LOGI("display_menu", "leave: %s", it->get_text().c_str());'
        items:
          - type: back
            text: 'Back'
          - type: label
            text: !lambda |-
              return id(esp_ip_address).state.c_str();

#              return id(some_sensor).state / 100.0;
          
# Encoder to provide navigation
sensor:
  - platform: rotary_encoder
    name: Rotary Encoder
    id: rotary
    pin_a:
      number: 25
      mode:
        input: true
    pin_b:
      number: 26
      mode:
        input: true
    filters:
      debounce: 120ms
    on_anticlockwise:
      - display_menu.up:
    on_clockwise:
      - display_menu.down:

  - platform: wmbus
    meter_id: 0x415F2497
    type: izar
    sensors:
      - name: "woda1 RSSi"
        field: "rssi"
        accuracy_decimals: 0
        unit_of_measurement: "dBm"
        device_class: "signal_strength"
        state_class: "measurement"
        entity_category: "diagnostic"
      - name: "woda1"
        id: woda1 
        field: "total"
        accuracy_decimals: 3
        unit_of_measurement: "m³"
        device_class: "water"
        state_class: "total_increasing"
        icon: "mdi:water"
      - name: "woda1 poprzedni mies."
        field: "last_month_total"
        accuracy_decimals: 3
        unit_of_measurement: "m³"
        device_class: "water"
        state_class: "total_increasing"
        icon: "mdi:water"
      - name: "Okres nadawania - Izar"
        field: "transmit_period"
        accuracy_decimals: 0
        unit_of_measurement: "s"
#        device_class: "signal_strength"
#        state_class: "measurement"
        entity_category: "diagnostic"

# A de-bounced GPIO is used to 'click'
binary_sensor:
  - platform: gpio
    pin: 
      number: GPIO27
      mode: INPUT_PULLUP
      inverted: True
    name: "Joystick click"
    id: joystick_click
    filters:
      - delayed_on: 10ms
      - delayed_off: 10ms
    on_press:
      - display_menu.enter:

button:
  - platform: restart
    name: "Restart ESP"
    icon: mdi:restart

switch:
  - platform: gpio
    id: led_wifi
    pin: GPIO2
    inverted: False

interval:
  - interval: 5s                                        # wykonaj co 1 sekundę
    then:
      if:                                               # jeżeli
        condition:
          wifi.connected:                               # połączenie z Wi-Fi
        then:                                           
          - if:
              condition:
                api.connected:                          
              then:                                     # jeżeli połączono z Wi-Fi
                - switch.turn_on: led_wifi              # to włącz LED Wi-Fi
              else:                                     # jeśli nie ma połączenia z HA to mrugaj LED Wi-Fi
                - switch.turn_on: led_wifi              # włącz LED Wi-Fi
                - delay: 500ms                          # odczekaj
                - switch.turn_off: led_wifi             # wyłącz LED Wi-Fi
                - delay: 500ms                          # odczekaj
        else:                                           # jeżeli nie połączono z Wi-Fi (automatycznie z HA również nie)
          - switch.turn_off: led_wifi

text_sensor:
  - platform: wifi_info
    ip_address:
      id: esp_ip_address
      icon: mdi:ip-network
      name: ESP IP Address
      address_0:
        name: ESP IP Address 0
    ssid:
      name: ESP Connected SSID
    bssid:
      name: ESP Connected BSSID
    mac_address:
      name: ESP Mac Wifi Address
    scan_results:
      name: ESP Latest Scan Results
    dns_address:
      name: ESP DNS Address

chodzi mi o to aby w poszczególnych podmenu wyswietlały sie informacje jak np:

display:
  - platform: lcd_pcf8574
    dimensions: 20x4
    address: 0x27
    id: lcd
    lambda: |-
          switch (id(page)){
            case 1:
              it.print(0, 0, "mieszkanie1");
              it.strftime(10, 0, "%d.%m.%Y", id(time_sntp).now());
              it.print(0, 2, "Woda Zimna  :%.1f m3");
              it.print(0, 3, "Woda Ciepla :%.1f m3");
              break;
            case 2:
              it.print(0, 0, "Mieszkanie2");
              it.strftime(10, 0, "%d.%m.%Y", id(time_sntp).now());
              it.print(0, 2, "Woda Zimna  :%.1f m3");
              it.print(0, 3, "Woda Ciepla :%.1f m3");
              break;
            case 3:
              it.print(0, 0, "Mieszkanie3");
              it.strftime(10, 0, "%d.%m.%Y", id(time_sntp).now());
              it.print(0, 2, "Woda Zimna  :%.1f m3");
              it.print(0, 3, "Woda Ciepla :%.1f m3");
              break;
            case 4:
              it.print(0, 0, "Termin Odczytu");
              it.strftime(0, 1, "Czas     "  "%H:%M ", id(time_sntp).now());
              it.strftime(0, 2, "Data   "  "%d.%m.%Y", id(time_sntp).now());
              it.printf(0, 3, "Ip :%s", id(esp_ip_address).state.c_str());
              break;
            case 5:
              it.strftime(0, 1, "Czas     "  "%H:%M ", id(time_sntp).now());
              it.strftime(0, 2, "Data   "  "%d.%m.%Y", id(time_sntp).now());
              it.printf(0, 3, "Ip :%s", id(esp_ip_address).state.c_str());
              break;
          }

A dokładniej
it.strftime(10, 0, “%d.%m.%Y”, id(time_sntp).now());
it.print(0, 2, “Woda Zimna :%.1f m3”);
it.print(0, 3, “Woda Ciepla :%.1f m3”);
Wiem ze brakuje Id woda1 id woda2 ale chcialem narazie wyswietlic cokolwiek (np.tekst) i pózniej uzupełnić id
Dzięki za pomoc

Skoro masz utworzone strony jak w drugim przykładzie to spróbuj poprzez zmianę stron. Musisz dodać zmienną globalną do przełączania stron. A akcję zmiany zmiennej globalnej ustawić w enkoderze lub pod przyciskiem. Zobacz ten temat bardzo podobny

PS. Nie zauważyłem że obydwa posty są Twoje :wink:

Sterownik Hitachi HD44780 (oraz jego klony, a ta konstrukcja jest z początku lat osiemdziesiątych zeszłego wieku i patenty już dawno wygasły, więc produkować teraz to może każdy) nie obsługuje stron.

Nie rozumiem, czemu ktoś usunął taga hd44780 z tego wątku, skoro właśnie chodzi o taką konstrukcję… (nazwy w rodzaju lcd1602 czy lcd2004 chyba wymyślili Chińczycy w czasach, gdy patenty jeszcze nie wygasły, bo klony tego sprzętu istnieją od lat), tak samo komponent do jego sterowania ma mylącą nazwę lcd_pcf8574 podczas gdy układ PCF8574 (też konstrukcja z ubiegłego wieku) jest użyty tylko w charakterze ekspandera z I2C na port równoległy (którym to portem równoległym de facto jest sterowany HD44780, tak samo jakby był sterowany z MCU Motoroli 6800 czy intela 8051 te 40 lat temu).


Wracając do zasadniczego tematu - metoda obejścia braku stron (jedna z wielu) w tym sterowniku wyświetlacza jest zamieszczona w… dokumentacji ESPHome

Natomiast co do kwestii objętości kodu, to na moje oko w tej chwili jest to chyba jakieś 10% tego co potrzeba finalnie do pełnej obsługi tego pomysłu, który jest opisany, więc proponuję rzeźbić po kawałeczku aż do skutku.

Komponent umożliwiający “łatwą” obsługę menu na wyświetlaczu alfanumerycznym wcale nie jest taki łatwy w użyciu (przede wszystkim ma bardzo ubogą dokumentację bez konkretnych przykładów).


Pomijając kwestię stron świetny przykład wykorzystania tego wyświetlacza jest opisany tu

warto zwrócić uwagę na ograniczenia w możliwościach wyświetlania danej ilości znaków (już na pierwszy rzut oka widać taki negatywny przykład tu

string

"mieszkanie1"

ma jedenaście znaków, ale w/g następnej linii ma się zmieścić w 10 znakach (awykonalne, zostanie nadpisana ta jedynka na końcu)

dalej

chcesz wyświetlać znaczniki czasowe oparte na platformie SNTP, tu też trzeba policzyć użyte znaki, zapis
“%d.%m.%Y”
wygeneruje potencjalnie taki najdłuższy ciąg, czyli równiutkie 10 znaków
12.12.1234

możesz to zmodyfikować na

              it.strftime(1`2, 0, "%d.%m.%y", id(time_sntp).now());

a wtedy wyświetlisz sobie 2 znaki dalej, a zmiana Y na y spowoduje skrócenie stringa do
12.12.34

https://esphome.io/components/time/#strftime

jeśli chodzi o SNTP, to proponuję taką bardziej rozbudowaną deklarację dla Polski

time:
  - platform: sntp
    timezone: Europe/Warsaw
    servers:
      - 0.pl.pool.ntp.org
      - 1.pl.pool.ntp.org
      - 2.pl.pool.ntp.org
    id: sntp_time

jeśli chodzi o formatowany tekst ( it.printf a nie it.print który służy tylko do wydrukowania treści “jak jest”)
https://esphome.io/components/display/#formatted-text

co do zmiany stron, myślę że odpowiednie będą 2 automatyzacje oparte na on_press którymi będziesz modyfikować zmienną id_page - w jednej automatyzacji ją zwiększać, a w drugiej zmniejszać

# 3 strony jak dla przykładu z dokumentacji, dla siebie modyfikujesz na 5
binary_sensor:
  - platform: gpio
    # ... tu definujesz przycisk pierwszy
    on_press:
      then:
        - lambda: |-
            id(page) = (id(page) + 1);
            if (id(page) > 3) {
              id(page) = 1;
            }
  - platform: gpio
    # ... tu definujesz przycisk drugi
    on_press:
      then:
        - lambda: |-
            id(page) = (id(page) - 1);
            if (id(page) < 1) {
              id(page) = 3;
            }
# UWAGA kluczowa jest deklaracja zmiennej globalnej  page
globals:
- id: page
  type: int
  initial_value: "1"

https://esphome.io/components/binary_sensor/#on-press
https://esphome.io/cookbook/lambda_magic#display-pages-alternative

PS tymczasowo proponuję w charakterze atrapy danych importować sobie encje z HA (i obsługę dużego wyświetlacza zrobić póki co bez odbiornika wmbus na osobnej konstrukcji)

Zdaje sobie sprawę ze ustawienia przesylane do wyswietlacza mogą być błędne ale to tylko na czas testów. Np. Mieszkanie1 docelowo ulica np. “Wielka” itp.
W innym moim poście “zaktom” pomógł rozwiązać problem zmiany stron

Jednak przy tym rozwiazaniu z encoderem i menu mogę sie poruszać i wyświetlać tylko część danych.

Pewnie wynika to z tych ustawień

on_enter:
          then:
            lambda: 'ESP_LOGI("display_menu", "enter: %s", it->get_text().c_str());'
        on_leave:
          then:
            lambda: 'ESP_LOGI("display_menu", "leave: %s", it->get_text().c_str());'
        items:
          - type: back
            text: 'Back'
          - type: label
            text: !lambda |-
              return id(esp_ip_address).state.c_str();
          - type: label
            text: 'inne dane woda1'
#             it.printf(0, 0, "Woda1 :%.1f m3", id(woda1).state);
#             it.printf(0, 1, "Woda2 :%.1f m3", id(woda2).state);
#             return id(some_sensor).state / 100.0;

gdzie
lambda: ‘ESP_LOGI(“display_menu”, “enter: %s”, it->get_text().c_str());’
pozwala wyswietlić tylko return id(esp_ip_address).state.c_str();
natomiast innych zmiennych nie id(woda1).state); lub id(time_sntp).now());

Ewentualnie jak to można zmienić.
Przeszukałem wiele stron zanim zamieściłem posta i faktycznie informacji o menu i submenu dla Esphome nie znalazłem jest zatem sporo na arduino ale nietedy droga. Jak widać na zdjeciu można dane wyświetlić ale jak dodać inne próbowałem na różne sposoby ale jestem za słaby nawet ja Validate przechodzi to wysypuje sie przy instalacji i wyswietla blad conversji

/config/esphome/esphome-web-6889a8.yaml: In lambda function:
/config/esphome/esphome-web-6889a8.yaml:161:21: error: could not convert 'woda1->esphome::sensor::Sensor::state' from 'float' to 'std::__cxx11::string' {aka 'std::__cxx11::basic_string<char>'}
               return id(woda1).state);
               ~~~~~~^~~~~
/config/esphome/esphome-web-6889a8.yaml:161:26: error: expected ';' before ')' token
               return id(woda1).state);
                          ^
                          ;
/config/esphome/esphome-web-6889a8.yaml:161:26: error: expected primary-expression before ')' token
*** [.pioenvs/esphome-web-6889a8/src/main.cpp.o] Error 1
========================= [FAILED] Took 25.24 seconds =========================
          - type: label
            text: !lambda |-
              return id(esp_ip_address).state.c_str();
          - type: label
            text: !lambda |-
              return id(woda1).state);
#             it.printf(0, 1, "Woda2 :%.1f m3", id(woda2).state);
#             return id(some_sensor).state / 100.0;

ilość nawiasów się nie zgadza (każdy otwierający musi mieć zamykający)

niestety nie mam dość wolnego czasu na zabawę z komponentem menu (a nigdy go nie stosowałem)

Wlasnie doczytałem i miałem poprawic ale i tak wywala błąd

Compiling .pioenvs/esphome-web-6889a8/src/main.cpp.o
/config/esphome/esphome-web-6889a8.yaml: In lambda function:
/config/esphome/esphome-web-6889a8.yaml:161:27: error: expression cannot be used as a function
               return id(woda1).state();
                           ^
*** [.pioenvs/esphome-web-6889a8/src/main.cpp.o] Error 1
========================= [FAILED] Took 23.93 seconds =========================

przy

- type: label
  text: !lambda |-
      return id(woda1).state();

musisz gdzieś mieć zadeklarowaną zmienną woda1 (encja musi istnieć, dlatego sugerowałem atrapę danych w postaci importu encji z HA)

Zmienna jest zadeklarowana

- platform: wmbus
    meter_id: 0x415F2497
    type: izar
    sensors:
      - name: "woda1 RSSi"
        field: "rssi"
        accuracy_decimals: 0
        unit_of_measurement: "dBm"
        device_class: "signal_strength"
        state_class: "measurement"
        entity_category: "diagnostic"
      - name: "woda1"
        id: woda1 
        field: "total"
        accuracy_decimals: 3
        unit_of_measurement: "m³"
        device_class: "water"
        state_class: "total_increasing"
        icon: "mdi:water"
      - name: "woda1 poprzedni mies."
        field: "last_month_total"
        accuracy_decimals: 3
        unit_of_measurement: "m³"
        device_class: "water"
        state_class: "total_increasing"
        icon: "mdi:water"
      - name: "Okres nadawania - Izar"
        field: "transmit_period"
        accuracy_decimals: 0
        unit_of_measurement: "s"
#        device_class: "signal_strength"
#        state_class: "measurement"
        entity_category: "diagnostic"

A sekcję wmbus masz wyżej w YAMLu niż całą zabawę z wyświetlaczem?
Jeśli faktycznie wszystko jest OK, to mogą być błędy interpretera YAML - ESPHome miewa błędy, a stosujesz też komponent niestandardowy.
W komponencie menu masowo używasz lambdy, więc należałoby analizować powstały kod c++

Przeniosłem WMbus na pocztek yaml, przyciełem wywołania lambda do

lcd_menu:
  id: my_lcd_menu
  display_id: my_lcd
  active: true
  mode: rotary
  on_enter:
    then:
      lambda: 'ESP_LOGI("display_menu", "root enter");'
  on_leave:
    then:
      lambda: 'ESP_LOGI("display_menu", "root leave");'
  items:
  - type: menu
    text: 'Max'
    on_enter:
      then:
        lambda: 'ESP_LOGI("display_menu", "enter: %s", it->get_text().c_str());'
    on_leave:
      then:
        lambda: 'ESP_LOGI("display_menu", "leave: %s", it->get_text().c_str());'
    items:
      - type: back
        text: 'Back'
      - type: label
        text: !lambda |-
          return id(esp_ip_address).state.c_str();
      - type: label
        text: 'lambda z danymi'
      - type: label
        text: !lambda |-
          return id(woda1).state();

niestety błąd

Compiling .pioenvs/esphome-web-6889a8/src/main.cpp.o
/config/esphome/esphome-web-6889a8.yaml: In lambda function:
/config/esphome/esphome-web-6889a8.yaml:180:27: error: expression cannot be used as a function
           return id(woda1).state();
                           ^
*** [.pioenvs/esphome-web-6889a8/src/main.cpp.o] Error 1

nie wynika to z faktu ze mam cos takiego zdefiniowane
lambda: ‘ESP_LOGI(“display_menu”, “enter: %s”, it->get_text().c_str());’
i przyjmuje tylko
return id(esp_ip_address).state.c_str();
a pozostale jak chce zdefiniowac maja
return id(woda1).state();
i dlatego wywala błąd podczas Compilacji

walisz na lewo i prawo tymi lambdami, ale nie wiem czy w ogóle platforma arduino ma funkcję ESP_LOGI
w platformie ESP-IDF z pewnością jest bo jest to w dokumentacji
https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/log.html
ale skoro na tym samym ESP używasz komponentu @_Szczepan to jesteś przyspawany do arduino.

Zacznij budować ten projekt wyświetlacza od podstaw i krok po kroczku, a nie od razu cały, bo nigdy nie dojdziesz gdzie są problemy.

Pracuje w esphome
na stronie maja cos takiego, bazują na lambdach

Ja wiem co mają w dokumentacji, bo sam ją tu linkowałem, chodzi mi o stopień skomplikowania projektu, który masz już na wstępie chcąc się wdrożyć w stosowanie komponentu, który ma dramatycznie słabą dokumentację (mówię o LCD menu) więc nie powinieneś startować z tak rozbudowanego projektu.

Aby to zrobić skutecznie wywal wszystko inne z projektu i zrób na początek jakieś minimalistyczne menu.

Niestety logi, które podajesz odnoszą się do projektu, którego nie widzimy (bo są odniesienia do konkretnych linii YAMLa, więc jeśli w komplecie nie dajesz całego YAMLa to nikt nie jest w stanie tego zreplikować u siebie, jeśli będziesz używał jakiś kompnent niestandardowy wymagający specyficznego sprzętu tu mówię o wmbus, to też nikt tego nie odtworzy u siebie, więcej empatii).

Wspominałem o frameworku, bo dla ESP32 możliwe są 2 różne frameworki
ALE dla komponentu Szczepana NIE

ESPHome pod spodem używa albo ESP-IDF albo Arduino (co swoją drogą definiuje się w YAMLu), dlatego o tym piszę bo te frameworki są totalnie różne od siebie.

jak wspominałem wcześniej nie próbowałem używać tego menu (olałem ten pomysł widząc jaka jest dokumentacja, a nie mam na to czasu), zakładam, że istnieje taka możliwość, że ten komponent nie działa w arduino (to z doświadczenia - bo przez kilka lat trafiałem w ESPHome na różne niespodzianki, a też nie jestem programistą…)

a teraz kwestia różnic między esp_ip_address a innymi encjami to jest taka, że ta encja zwraca wartość, która jest już stringiem ( c_str() odwołuje się do tablicy), a inne pewnie mają jakieś wartości stało lub zmiennoprzecinkowe

Aktualna wersja Yaml

substitutions:
  name: esphome-web-6889a8
  friendly_name: ESPHome Web 6889a8

esphome:
  name: ${name}
  friendly_name: ${friendly_name}
  min_version: 2024.6.0
  name_add_mac_suffix: false
  project:
    name: esphome.web
    version: dev

esp32:
  board: esp32dev
  framework:
    type: arduino

time:
  - platform: sntp
    id: time_sntp
    timezone: Europe/Warsaw
# Enable logging
logger:

# Enable Home Assistant API
api:

# Allow Over-The-Air updates
ota:
- platform: esphome

# Allow provisioning Wi-Fi via serial
improv_serial:

wifi:
  # Set up a wifi access point
  ap: {}

# In combination with the `ap` this allows the user
# to provision wifi credentials to the device via WiFi AP.
captive_portal:

# Sets up Bluetooth LE (Only on ESP32) to allow the user
# to provision wifi credentials to the device.
# esp32_improv:
#  authorizer: none

# To have a "next url" for improv serial
web_server:
  port: 80
  version: 3
  auth:
    username: !secret web_server_username
    password: !secret web_server_password

external_components:
  - source: github://SzczepanLeon/esphome-components@main
#  - source: github://SzczepanLeon/esphome-components@2.4.10
#  - source: github://SzczepanLeon/esphome-components@3.2.3
    refresh: 0d
    components: [ wmbus ]

wmbus:
  frequency: 868.950
  mosi_pin: GPIO23
  miso_pin: GPIO19
  clk_pin:  GPIO18
  cs_pin:   GPIO15
  gdo0_pin: GPIO16
  gdo2_pin: GPIO17
#  led_blink_time: "1s"

  all_drivers: false
  sync_mode: True
  log_all: True
# Encoder to provide navigation
sensor:
  - platform: rotary_encoder
    name: Rotary Encoder
    id: rotary
    pin_a:
      number: 25
      mode:
        input: true
    pin_b:
      number: 26
      mode:
        input: true
    filters:
      debounce: 120ms
    on_anticlockwise:
      - display_menu.up:
    on_clockwise:
      - display_menu.down:

  - platform: wmbus
    meter_id: 0x415F2497
    type: izar
    sensors:
      - name: "woda1 RSSi"
        field: "rssi"
        accuracy_decimals: 0
        unit_of_measurement: "dBm"
        device_class: "signal_strength"
        state_class: "measurement"
        entity_category: "diagnostic"
      - name: "woda1"
        id: woda1 
        field: "total"
        accuracy_decimals: 3
        unit_of_measurement: "m³"
        device_class: "water"
        state_class: "total_increasing"
        icon: "mdi:water"
      - name: "woda1 poprzedni mies."
        field: "last_month_total"
        accuracy_decimals: 3
        unit_of_measurement: "m³"
        device_class: "water"
        state_class: "total_increasing"
        icon: "mdi:water"
      - name: "Okres nadawania - Izar"
        field: "transmit_period"
        accuracy_decimals: 0
        unit_of_measurement: "s"
#        device_class: "signal_strength"
#        state_class: "measurement"
        entity_category: "diagnostic"

# A de-bounced GPIO is used to 'click'

i2c:
  sda: 21
  scl: 22
  scan: True
  frequency: 400kHz

display:
  - platform: lcd_pcf8574
    dimensions: 20x4
    address: 0x27
    id: my_lcd
    lambda: |-
      id(my_lcd_menu).draw();
      if (!id(my_lcd_menu).is_active())
        it.print("Menu is not active");

# Declare a LCD menu
lcd_menu:
  id: my_lcd_menu
  display_id: my_lcd
  active: true
  mode: rotary
  on_enter:
    then:
      lambda: 'ESP_LOGI("display_menu", "root enter");'
  on_leave:
    then:
      lambda: 'ESP_LOGI("display_menu", "root leave");'
  items:
  - type: menu
    text: 'Max'
    on_enter:
      then:
        lambda: 'ESP_LOGI("display_menu", "enter: %s", it->get_text().c_str());'
    on_leave:
      then:
        lambda: 'ESP_LOGI("display_menu", "leave: %s", it->get_text().c_str());'
    items:
      - type: back
        text: 'Back'
      - type: label
        text: !lambda |-
          return id(esp_ip_address).state.c_str();
      - type: label
        text: 'lambda z danymi'
      - type: label
        text: !lambda |-
          return id(woda1).state();

#  - type: menu
#    text: 'Moja'
#    on_enter:
#      then:
#        lambda: 'ESP_LOGI("display_menu", "enter: %s", it->get_text().c_str());'
#    on_leave:
#      then:
#        lambda: 'ESP_LOGI("display_menu", "leave: %s", it->get_text().c_str());'
#    items:
#      - type: back
#        text: 'Back'
#      - type: menu
#        text: 'Mieszkanie1'
#        on_enter:
#          then:
#            lambda: 'ESP_LOGI("display_menu", "enter: %s", it->get_text().c_str());'
#        on_leave:
#          then:
#            lambda: 'ESP_LOGI("display_menu", "leave: %s", it->get_text().c_str());'
#        items:
#          - type: back
#            text: 'Back'
#          - type: label
#            text: 'lambda z danymi'
#      - type: menu
#        text: 'Mieszkanie2'
#        on_enter:
#          then:
#            lambda: 'ESP_LOGI("display_menu", "enter: %s", it->get_text().c_str());'
#        on_leave:
#          then:
#            lambda: 'ESP_LOGI("display_menu", "leave: %s", it->get_text().c_str());'
#        items:
#          - type: back
#            text: 'Back'
#          - type: label
#            text: !lambda |-
#              return id(esp_ip_address).state.c_str();
#          - type: label
#            text: !lambda |-
#              return id(woda1).state);
#             it.printf(0, 1, "Woda2 :%.1f m3", id(woda2).state);
#             return id(some_sensor).state / 100.0;
          

binary_sensor:
  - platform: gpio
    pin: 
      number: GPIO27
      mode: INPUT_PULLUP
      inverted: True
    name: "Joystick click"
    id: joystick_click
    filters:
      - delayed_on: 10ms
      - delayed_off: 10ms
    on_press:
      - display_menu.enter:

button:
  - platform: restart
    name: "Restart ESP"
    icon: mdi:restart

switch:
  - platform: gpio
    id: led_wifi
    pin: GPIO2
    inverted: False

interval:
  - interval: 5s                                        # wykonaj co 1 sekundę
    then:
      if:                                               # jeżeli
        condition:
          wifi.connected:                               # połączenie z Wi-Fi
        then:                                           
          - if:
              condition:
                api.connected:                          
              then:                                     # jeżeli połączono z Wi-Fi
                - switch.turn_on: led_wifi              # to włącz LED Wi-Fi
              else:                                     # jeśli nie ma połączenia z HA to mrugaj LED Wi-Fi
                - switch.turn_on: led_wifi              # włącz LED Wi-Fi
                - delay: 500ms                          # odczekaj
                - switch.turn_off: led_wifi             # wyłącz LED Wi-Fi
                - delay: 500ms                          # odczekaj
        else:                                           # jeżeli nie połączono z Wi-Fi (automatycznie z HA również nie)
          - switch.turn_off: led_wifi

text_sensor:
  - platform: wifi_info
    ip_address:
      id: esp_ip_address
      icon: mdi:ip-network
      name: ESP IP Address
      address_0:
        name: ESP IP Address 0
    ssid:
      name: ESP Connected SSID
    bssid:
      name: ESP Connected BSSID
    mac_address:
      name: ESP Mac Wifi Address
    scan_results:
      name: ESP Latest Scan Results
    dns_address:
      name: ESP DNS Address

Praktycznie wzor ze strony esphome

items:
  - type: menu
    text: 'My Submenu'
    on_enter:
      then:
        lambda: 'ESP_LOGI("display_menu", "enter: %s", it->get_text().c_str());'
    on_leave:
      then:
        lambda: 'ESP_LOGI("display_menu", "leave: %s", it->get_text().c_str());'
    items:
      - type: label
        text: 'Label'
      - type: back
        text: 'Back'

poczyszcze do 0 i dam znac

Chyba jednak nie czytasz…
Wywal wszystko co jest niezwiązane z wyświetlaczem ze swojego kodu i wtedy walcz.

Funkcja która jak sądzę powoduje problemy w ogóle nie jest związana z funkcjonalnością wyświetlacza - ten blok kodu który wstawiłeś na końcu w dużym stopniu służy do generowania wpisów w logu.