ProtoBoksi ohje

9” CrowPanel Home Assistant -näytöksi ESPHomella ja LVGL:llä

Tässä ohjeessa tehdään 9 tuuman ESP32-P4-pohjaisesta CrowPanel-näytöstä oma Home Assistant -kojetaulu. ESPHome hakee arvot Home Assistantista ja LVGL piirtää käyttöliittymän suoraan näytölle.

Mitä tässä rakennetaan?

Tavoitteena on tehdä oma kodin kojetaulu, josta näkee sähkön hinnan, talon kulutuksen, aurinkotuotannon, lämpötilat ja lämminvesivaraajan tilan. Lisäksi näytöltä voi ohjata valoja ja varaajaa Home Assistantin palvelukutsuilla.

SähköSähkön hinta, talon kulutus ja aurinkopaneelien tuotanto.
LämpötilatSisälämpö, ulkolämpö ja lämminvesivaraajan lämpötila.
OhjauksetNapilla valot, varaaja tai muu Home Assistant -laite päälle ja pois.
Tämä ei ole tavallinen Android-tabletti. Tässä Home Assistantin tiedot haetaan ESPHomella ja käyttöliittymä piirretään LVGL:llä suoraan ESP32-P4-näytölle.

Tärkeä vakauskorjaus V1.0-laudalle

Omissa testeissä V1.0-piirilevy kaatuili, jos ESP32-P4:n ja ESP32-C6:n välinen hosted WiFi / SDIO -yhteys meni väärään väylämoodiin. Oireina näkyi esimerkiksi sdmmc_send_cmd returned 0x109, sdio_get_tx_buffer_num: err: 265, task watchdog ja Instruction address misaligned.

V1.0-laudalla ratkaisu oli käyttää 1-bit SDIO -asetusta eli bus_width: 1. Tämä on mukana alla olevassa koodissa.

esp32_hosted:
  variant: esp32c6
  active_high: true
  bus_width: 1
  reset_pin: GPIO32
  cmd_pin: GPIO19
  clk_pin: GPIO18
  d0_pin: GPIO14
  d1_pin: GPIO15
Jos siulla on V1.1-piirilevy, pinniasetus voi olla eri. Tarkista oman näytön piirilevyversio ennen kuin kopioit koodin sokkona.

Tarvittavat asiat

Mukana tullut USB-C-johto voi olla pelkkä virtajohto. Jos Windowsiin ei ilmesty uutta COM-porttia eikä ESPHome Web tunnista laitetta, kokeile ensimmäisenä varmasti toimivaa datajohtoa.

Työvaiheet lyhyesti

  1. Fläshää ensin valmistajan tai oma minimitesti, jotta näyttö ja taustavalo toimivat.
  2. Tarkista piirilevyn versio. Tässä ohjeessa käytetty vakauskorjaus on V1.0-laudan bus_width: 1.
  3. Lisää omat Home Assistant -entiteetit substitutions:-kohtaan.
  4. Tarkista, että api_encryption_key, ota_password, wifi_ssid, wifi_password ja fallback_password löytyvät secrets.yaml-tiedostosta.
  5. Fläshää koodi USB:n kautta ensimmäisellä kerralla.
  6. Home Assistantissa salli ESPHome-laitteen tehdä palvelukutsuja, jotta napit toimivat.

Home Assistant -entiteetit

Nämä ovat omat esimerkkientiteetit. Vaihda ne siun Home Assistantin entiteetteihin.

substitutions:
  name: olkkarinaytto
  friendly_name: olkkarinäyttö

  # Vaihda nämä omiin Home Assistant -entiteetteihin
  ent_sahkon_hinta: sensor.nordpool_kwh_fi_eur_3_10_0255
  ent_talon_kulutus: sensor.sauna_home_power
  ent_aurinko: sensor.sauna_sum_power_of_all_pv_dc_inputs
  ent_sisa_lampo: sensor.lampoanturi2_lampotila
  ent_ulko_lampo: sensor.lampoanturi2_ulko_lampotila
  ent_vesivaraaja: switch.sonoff_10013b57e7_2
  ent_tyohuone_valo: light.tyohuone
  ent_olohuone_valo: switch.sonoff_100156aa41_2
  ent_sivu_valo: switch.sonoff_100156aa41_1
  ent_lvv_lampo: sensor.lamminvesivaraaja_varaajakeski

API, OTA ja WiFi

Salaisuudet kannattaa pitää secrets.yaml-tiedostossa, jotta YAMLia voi näyttää videolla ilman että oikeat avaimet näkyvät.

api:
  encryption:
    key: !secret api_encryption_key

ota:
  - platform: esphome
    password: !secret ota_password

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

  # Testissä lukittu eteisen AP:hen.
  # Jos ei yhdistä, kommentoi bssid ja fast_connect pois.
  
  fast_connect: true

  ap:
    ssid: "Olkkarinaytto Fallback Hotspot"
    password: !secret fallback_password

Sensorit ja näytön päivitys

Arvot haetaan Home Assistantista taustalle. Näyttöä ei päivitetä jokaisen sensorin on_value-kohdassa, vaan keskitetysti interval:-osiossa. Tämä vähentää LVGL-kuormaa.

Näytä sensorit, text_sensorit ja interval-päivitys
sensor:
  - platform: uptime
    name: "Olkkarinäyttö Uptime"
    id: olkkarinaytto_uptime
    update_interval: 30s

  - platform: wifi_signal
    name: "Olkkarinäyttö WiFi signaali"
    id: olkkarinaytto_wifi_signal
    update_interval: 30s

  # Home Assistant -arvot haetaan taustalle.
  # Näyttöä ei päivitetä on_value-kohdassa,
  # vaan keskitetysti interval-osiossa.

  - platform: homeassistant
    id: sahkon_hinta
    entity_id: ${ent_sahkon_hinta}
    filters:
      - throttle: 5min

  - platform: homeassistant
    id: talon_kulutus
    entity_id: ${ent_talon_kulutus}
    filters:
      - throttle: 15s

  - platform: homeassistant
    id: aurinko_tuotanto
    entity_id: ${ent_aurinko}
    filters:
      - throttle: 15s

  - platform: homeassistant
    id: sisa_lampo
    entity_id: ${ent_sisa_lampo}
    filters:
      - throttle: 30s

  - platform: homeassistant
    id: ulko_lampo
    entity_id: ${ent_ulko_lampo}
    filters:
      - throttle: 30s

  - platform: homeassistant
    id: lvv_lampo
    entity_id: ${ent_lvv_lampo}
    filters:
      - throttle: 30s

text_sensor:
  - platform: homeassistant
    id: vesivaraaja_state
    entity_id: ${ent_vesivaraaja}

  - platform: wifi_info
    ip_address:
      name: "Olkkarinäyttö IP"
    ssid:
      name: "Olkkarinäyttö SSID"
    bssid:
      name: "Olkkarinäyttö BSSID"

  - platform: debug
    reset_reason:
      name: "Olkkarinäyttö Reset Reason"

interval:
  - interval: 15s
    then:
      - lvgl.label.update:
          id: label_sahkon_hinta
          text: !lambda |-
            if (isnan(id(sahkon_hinta).state)) return std::string("-- c/kWh");
            char buf[24];
            snprintf(buf, sizeof(buf), "%.2f c/kWh", id(sahkon_hinta).state);
            return std::string(buf);

      - lvgl.label.update:
          id: label_talon_kulutus
          text: !lambda |-
            if (isnan(id(talon_kulutus).state)) return std::string("-- W");
            char buf[24];
            snprintf(buf, sizeof(buf), "%.0f W", id(talon_kulutus).state);
            return std::string(buf);

      - lvgl.label.update:
          id: label_aurinko
          text: !lambda |-
            if (isnan(id(aurinko_tuotanto).state)) return std::string("-- W");
            char buf[24];
            snprintf(buf, sizeof(buf), "%.0f W", id(aurinko_tuotanto).state);
            return std::string(buf);

      - lvgl.label.update:
          id: label_sisa_lampo
          text: !lambda |-
            if (isnan(id(sisa_lampo).state)) return std::string("-- °C");
            char buf[24];
            snprintf(buf, sizeof(buf), "%.1f °C", id(sisa_lampo).state);
            return std::string(buf);

      - lvgl.label.update:
          id: label_ulko_lampo
          text: !lambda |-
            if (isnan(id(ulko_lampo).state)) return std::string("-- °C");
            char buf[24];
            snprintf(buf, sizeof(buf), "%.1f °C", id(ulko_lampo).state);
            return std::string(buf);

      - lvgl.label.update:
          id: label_lvv_lampo
          text: !lambda |-
            if (isnan(id(lvv_lampo).state)) return std::string("-- °C");
            char buf[24];
            snprintf(buf, sizeof(buf), "%.1f °C", id(lvv_lampo).state);
            return std::string(buf);

      - lvgl.label.update:
          id: label_vesivaraaja
          text: !lambda |-
            std::string state = id(vesivaraaja_state).state;
            if (state == "on") return std::string("Päällä");
            if (state == "off") return std::string("Pois");
            if (state == "unavailable") return std::string("--");
            if (state == "unknown") return std::string("--");
            if (state.empty()) return std::string("--");
            return state;

Fontit ääkkösille

Roboto-fontteihin on määritelty mukaan å ä ö Å Ä Ö, jotta suomenkieliset tekstit näkyvät oikein.

Näytä fonttikoodi
font:
  - file: "gfonts://Roboto"
    id: roboto_20
    size: 20
    glyphs: "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖabcdefghijklmnopqrstuvwxyzåäö °€"

  - file: "gfonts://Roboto"
    id: roboto_22
    size: 22
    glyphs: "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖabcdefghijklmnopqrstuvwxyzåäö °€"

  - file: "gfonts://Roboto"
    id: roboto_26
    size: 26
    glyphs: "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖabcdefghijklmnopqrstuvwxyzåäö °€"

  - file: "gfonts://Roboto"
    id: roboto_30
    size: 30
    glyphs: "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖabcdefghijklmnopqrstuvwxyzåäö °€"

  - file: "gfonts://Roboto"
    id: roboto_34
    size: 34
    glyphs: "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖabcdefghijklmnopqrstuvwxyzåäö °€"

  - file: "gfonts://Roboto"
    id: roboto_48
    size: 48
    glyphs: "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖabcdefghijklmnopqrstuvwxyzåäö °€"

Lopullinen LVGL-näkymä

Tässä versiossa widgettien omat scrollaukset on otettu pois päältä. Kirkkausslider on vaihdettu staattiseksi tekstiksi, koska testien aikana ylimääräinen jatkuva säätö haluttiin pois.

Näytä LVGL widgets -koodi
lvgl:
  buffer_size: 15%
  byte_order: little_endian
  color_depth: 16
  log_level: ERROR
  bg_color: 0x101216
  text_font: roboto_26

  widgets:
    # Yläpalkki
    - obj:
        x: 24
        y: 20
        width: 976
        height: 96
        bg_color: 0x1A1D24
        border_width: 0
        radius: 20
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 18
        widgets:
          - label:
              x: 0
              y: 0
              text: "ProtoBoksi koti"
              text_color: 0xFFFFFF
              text_font: roboto_34

          - label:
              id: label_date
              x: 4
              y: 48
              text: "Odotetaan aikaa..."
              text_color: 0xAEB6C2
              text_font: roboto_20

          - label:
              id: label_clock
              align: TOP_RIGHT
              x: -8
              y: -6
              text: "--:--"
              text_color: 0xFFFFFF
              text_font: roboto_48

    # Sähkön hinta
    - obj:
        x: 24
        y: 132
        width: 300
        height: 150
        bg_color: 0x252A33
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 18
        widgets:
          - label:
              text: "Sähkön hinta"
              text_color: 0xAEB6C2
              text_font: roboto_22

          - label:
              id: label_sahkon_hinta
              x: 0
              y: 55
              text: "-- c/kWh"
              text_color: 0xFFFFFF
              text_font: roboto_34

    # Talon kulutus
    - obj:
        x: 362
        y: 132
        width: 300
        height: 150
        bg_color: 0x252A33
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 18
        widgets:
          - label:
              text: "Talon kulutus"
              text_color: 0xAEB6C2
              text_font: roboto_22

          - label:
              id: label_talon_kulutus
              x: 0
              y: 55
              text: "-- W"
              text_color: 0xFFFFFF
              text_font: roboto_34

    # Aurinkotuotanto
    - obj:
        x: 700
        y: 132
        width: 300
        height: 150
        bg_color: 0x252A33
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 18
        widgets:
          - label:
              text: "Aurinko"
              text_color: 0xAEB6C2
              text_font: roboto_22

          - label:
              id: label_aurinko
              x: 0
              y: 55
              text: "-- W"
              text_color: 0xFFFFFF
              text_font: roboto_34

    # Sisälämpö
    - obj:
        x: 24
        y: 302
        width: 220
        height: 120
        bg_color: 0x252A33
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 18
        widgets:
          - label:
              text: "Sisällä"
              text_color: 0xAEB6C2
              text_font: roboto_22

          - label:
              id: label_sisa_lampo
              x: 0
              y: 48
              text: "-- °C"
              text_color: 0xFFFFFF
              text_font: roboto_30

    # Ulkolämpö
    - obj:
        x: 270
        y: 302
        width: 220
        height: 120
        bg_color: 0x252A33
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 18
        widgets:
          - label:
              text: "Ulkona"
              text_color: 0xAEB6C2
              text_font: roboto_22

          - label:
              id: label_ulko_lampo
              x: 0
              y: 48
              text: "-- °C"
              text_color: 0xFFFFFF
              text_font: roboto_30

    # Vesivaraaja tila
    - obj:
        x: 516
        y: 302
        width: 220
        height: 120
        bg_color: 0x252A33
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 18
        widgets:
          - label:
              text: "Vesivaraaja"
              text_color: 0xAEB6C2
              text_font: roboto_22

          - label:
              id: label_vesivaraaja
              x: 0
              y: 48
              text: "--"
              text_color: 0xFFFFFF
              text_font: roboto_30

    # Näytön kirkkaus
    - obj:
        x: 762
        y: 302
        width: 238
        height: 120
        bg_color: 0x252A33
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 18
        widgets:
          - label:
              text: "Näyttö"
              text_color: 0xAEB6C2
              text_font: roboto_22

          - label:
              x: 0
              y: 48
              text: "100 %"
              text_color: 0xFFFFFF
              text_font: roboto_30

    # Lämminvesivaraajan lämpötila
    - obj:
        x: 24
        y: 445
        width: 230
        height: 95
        bg_color: 0x252A33
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 14
        widgets:
          - label:
              text: "LVV lämpö"
              text_color: 0xAEB6C2
              text_font: roboto_22

          - label:
              id: label_lvv_lampo
              x: 0
              y: 38
              text: "-- °C"
              text_color: 0xFFFFFF
              text_font: roboto_30

    # Olohuone nappi
    - button:
        x: 272
        y: 445
        width: 230
        height: 95
        bg_color: 0x2E3440
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        on_click:
          then:
            - homeassistant.service:
                service: switch.toggle
                data:
                  entity_id: ${ent_olohuone_valo}
        widgets:
          - label:
              align: CENTER
              text: "Olohuone"
              text_color: 0xFFFFFF
              text_font: roboto_30

    # Varaaja nappi
    - button:
        x: 520
        y: 445
        width: 230
        height: 95
        bg_color: 0x2E3440
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        on_click:
          then:
            - homeassistant.service:
                service: switch.toggle
                data:
                  entity_id: ${ent_vesivaraaja}
        widgets:
          - label:
              align: CENTER
              text: "Varaaja"
              text_color: 0xFFFFFF
              text_font: roboto_30

    # Olohuone 2 nappi
    - button:
        x: 768
        y: 445
        width: 232
        height: 95
        bg_color: 0x3B4252
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        on_click:
          then:
            - homeassistant.service:
                service: switch.toggle
                data:
                  entity_id: ${ent_sivu_valo}
        widgets:
          - label:
              align: CENTER
              text: "Olohuone 2"
              text_color: 0xFFFFFF
              text_font: roboto_30

Koko ESPHome YAML

Alla on koko käytössä ollut YAML yhtenä kopioitavana pakettina.

Näytä koko koodi
substitutions:
  name: olkkarinaytto
  friendly_name: olkkarinäyttö

  # Vaihda nämä omiin Home Assistant -entiteetteihin
  ent_sahkon_hinta: sensor.nordpool_kwh_fi_eur_3_10_0255
  ent_talon_kulutus: sensor.sauna_home_power
  ent_aurinko: sensor.sauna_sum_power_of_all_pv_dc_inputs
  ent_sisa_lampo: sensor.lampoanturi2_lampotila
  ent_ulko_lampo: sensor.lampoanturi2_ulko_lampotila
  ent_vesivaraaja: switch.sonoff_10013b57e7_2
  ent_tyohuone_valo: light.tyohuone
  ent_olohuone_valo: switch.sonoff_100156aa41_2
  ent_sivu_valo: switch.sonoff_100156aa41_1
  ent_lvv_lampo: sensor.lamminvesivaraaja_varaajakeski

esphome:
  name: ${name}
  friendly_name: ${friendly_name}

  on_boot:
    priority: 800
    then:
      - output.turn_on: backlight_pwm
      - delay: 200ms
      - output.turn_off: power_light
      - delay: 500ms
      - light.turn_on:
          id: back_light
          brightness: 1.0

esp32:
  variant: esp32p4
  engineering_sample: true
  cpu_frequency: 360MHz
  flash_size: 16MB
  framework:
    type: esp-idf
    advanced:
      enable_idf_experimental_features: true

psram:
  speed: 200MHz

esp_ldo:
  - channel: 3
    voltage: 2.5V
  - channel: 4
    voltage: 2.5V

logger:
  level: INFO
  logs:
    lvgl: ERROR
  hardware_uart: UART0

api:
  encryption:
    key: !secret api_encryption_key



ota:
  - platform: esphome
    password: !secret ota_password

esp32_hosted:
  variant: esp32c6
  active_high: true
  bus_width: 1
  reset_pin: GPIO32
  cmd_pin: GPIO19
  clk_pin: GPIO18
  d0_pin: GPIO14
  d1_pin: GPIO15


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

  # Testissä lukittu eteisen AP:hen.
  # Jos ei yhdistä, kommentoi bssid ja fast_connect pois.
  
  fast_connect: true

  ap:
    ssid: "Olkkarinaytto Fallback Hotspot"
    password: !secret fallback_password

captive_portal:

debug:
  update_interval: 30s

i2c:
  - id: bus_a
    sda: GPIO45
    scl: GPIO46
    frequency: 400kHz

time:
  - platform: homeassistant
    id: ha_time
    timezone: Europe/Helsinki
    on_time:
      - seconds: 0
        minutes: /1
        then:
          - script.execute: update_clock

script:
  - id: update_clock
    then:
      - lvgl.label.update:
          id: label_clock
          text: !lambda |-
            auto now = id(ha_time).now();
            if (!now.is_valid()) return std::string("--:--");
            return now.strftime("%H:%M");

      - lvgl.label.update:
          id: label_date
          text: !lambda |-
            auto now = id(ha_time).now();
            if (!now.is_valid()) return std::string("Odotetaan aikaa...");
            return now.strftime("%d.%m.%Y");

sensor:
  - platform: uptime
    name: "Olkkarinäyttö Uptime"
    id: olkkarinaytto_uptime
    update_interval: 30s

  - platform: wifi_signal
    name: "Olkkarinäyttö WiFi signaali"
    id: olkkarinaytto_wifi_signal
    update_interval: 30s

  # Home Assistant -arvot haetaan taustalle.
  # Näyttöä ei päivitetä on_value-kohdassa,
  # vaan keskitetysti interval-osiossa.

  - platform: homeassistant
    id: sahkon_hinta
    entity_id: ${ent_sahkon_hinta}
    filters:
      - throttle: 5min

  - platform: homeassistant
    id: talon_kulutus
    entity_id: ${ent_talon_kulutus}
    filters:
      - throttle: 15s

  - platform: homeassistant
    id: aurinko_tuotanto
    entity_id: ${ent_aurinko}
    filters:
      - throttle: 15s

  - platform: homeassistant
    id: sisa_lampo
    entity_id: ${ent_sisa_lampo}
    filters:
      - throttle: 30s

  - platform: homeassistant
    id: ulko_lampo
    entity_id: ${ent_ulko_lampo}
    filters:
      - throttle: 30s

  - platform: homeassistant
    id: lvv_lampo
    entity_id: ${ent_lvv_lampo}
    filters:
      - throttle: 30s

text_sensor:
  - platform: homeassistant
    id: vesivaraaja_state
    entity_id: ${ent_vesivaraaja}

  - platform: wifi_info
    ip_address:
      name: "Olkkarinäyttö IP"
    ssid:
      name: "Olkkarinäyttö SSID"
    bssid:
      name: "Olkkarinäyttö BSSID"

  - platform: debug
    reset_reason:
      name: "Olkkarinäyttö Reset Reason"

interval:
  - interval: 15s
    then:
      - lvgl.label.update:
          id: label_sahkon_hinta
          text: !lambda |-
            if (isnan(id(sahkon_hinta).state)) return std::string("-- c/kWh");
            char buf[24];
            snprintf(buf, sizeof(buf), "%.2f c/kWh", id(sahkon_hinta).state);
            return std::string(buf);

      - lvgl.label.update:
          id: label_talon_kulutus
          text: !lambda |-
            if (isnan(id(talon_kulutus).state)) return std::string("-- W");
            char buf[24];
            snprintf(buf, sizeof(buf), "%.0f W", id(talon_kulutus).state);
            return std::string(buf);

      - lvgl.label.update:
          id: label_aurinko
          text: !lambda |-
            if (isnan(id(aurinko_tuotanto).state)) return std::string("-- W");
            char buf[24];
            snprintf(buf, sizeof(buf), "%.0f W", id(aurinko_tuotanto).state);
            return std::string(buf);

      - lvgl.label.update:
          id: label_sisa_lampo
          text: !lambda |-
            if (isnan(id(sisa_lampo).state)) return std::string("-- °C");
            char buf[24];
            snprintf(buf, sizeof(buf), "%.1f °C", id(sisa_lampo).state);
            return std::string(buf);

      - lvgl.label.update:
          id: label_ulko_lampo
          text: !lambda |-
            if (isnan(id(ulko_lampo).state)) return std::string("-- °C");
            char buf[24];
            snprintf(buf, sizeof(buf), "%.1f °C", id(ulko_lampo).state);
            return std::string(buf);

      - lvgl.label.update:
          id: label_lvv_lampo
          text: !lambda |-
            if (isnan(id(lvv_lampo).state)) return std::string("-- °C");
            char buf[24];
            snprintf(buf, sizeof(buf), "%.1f °C", id(lvv_lampo).state);
            return std::string(buf);

      - lvgl.label.update:
          id: label_vesivaraaja
          text: !lambda |-
            std::string state = id(vesivaraaja_state).state;
            if (state == "on") return std::string("Päällä");
            if (state == "off") return std::string("Pois");
            if (state == "unavailable") return std::string("--");
            if (state == "unknown") return std::string("--");
            if (state.empty()) return std::string("--");
            return state;

output:
  - platform: ledc
    pin: GPIO31
    id: backlight_pwm

  - platform: gpio
    id: power_light
    pin: GPIO29
    inverted: true

light:
  - platform: monochromatic
    name: "Backlight"
    output: backlight_pwm
    id: back_light
    restore_mode: ALWAYS_ON
    internal: true

font:
  - file: "gfonts://Roboto"
    id: roboto_20
    size: 20
    glyphs: "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖabcdefghijklmnopqrstuvwxyzåäö °€"

  - file: "gfonts://Roboto"
    id: roboto_22
    size: 22
    glyphs: "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖabcdefghijklmnopqrstuvwxyzåäö °€"

  - file: "gfonts://Roboto"
    id: roboto_26
    size: 26
    glyphs: "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖabcdefghijklmnopqrstuvwxyzåäö °€"

  - file: "gfonts://Roboto"
    id: roboto_30
    size: 30
    glyphs: "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖabcdefghijklmnopqrstuvwxyzåäö °€"

  - file: "gfonts://Roboto"
    id: roboto_34
    size: 34
    glyphs: "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖabcdefghijklmnopqrstuvwxyzåäö °€"

  - file: "gfonts://Roboto"
    id: roboto_48
    size: 48
    glyphs: "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖabcdefghijklmnopqrstuvwxyzåäö °€"

display:
  - platform: mipi_dsi
    id: my_display
    model: WAVESHARE-ESP32-P4-WIFI6-TOUCH-LCD-7B
    reset_pin:
      number: 41
    update_interval: never
    auto_clear_enabled: false
    dimensions:
      width: 1024
      height: 600
    color_order: RGB
    color_depth: 16

touchscreen:
  - platform: gt911
    id: my_touchscreen
    i2c_id: bus_a
    reset_pin: 40
    interrupt_pin: 42
    update_interval: 50ms
    transform:
      swap_xy: false
      mirror_x: false
      mirror_y: false

lvgl:
  buffer_size: 15%
  byte_order: little_endian
  color_depth: 16
  log_level: ERROR
  bg_color: 0x101216
  text_font: roboto_26

  widgets:
    # Yläpalkki
    - obj:
        x: 24
        y: 20
        width: 976
        height: 96
        bg_color: 0x1A1D24
        border_width: 0
        radius: 20
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 18
        widgets:
          - label:
              x: 0
              y: 0
              text: "ProtoBoksi koti"
              text_color: 0xFFFFFF
              text_font: roboto_34

          - label:
              id: label_date
              x: 4
              y: 48
              text: "Odotetaan aikaa..."
              text_color: 0xAEB6C2
              text_font: roboto_20

          - label:
              id: label_clock
              align: TOP_RIGHT
              x: -8
              y: -6
              text: "--:--"
              text_color: 0xFFFFFF
              text_font: roboto_48

    # Sähkön hinta
    - obj:
        x: 24
        y: 132
        width: 300
        height: 150
        bg_color: 0x252A33
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 18
        widgets:
          - label:
              text: "Sähkön hinta"
              text_color: 0xAEB6C2
              text_font: roboto_22

          - label:
              id: label_sahkon_hinta
              x: 0
              y: 55
              text: "-- c/kWh"
              text_color: 0xFFFFFF
              text_font: roboto_34

    # Talon kulutus
    - obj:
        x: 362
        y: 132
        width: 300
        height: 150
        bg_color: 0x252A33
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 18
        widgets:
          - label:
              text: "Talon kulutus"
              text_color: 0xAEB6C2
              text_font: roboto_22

          - label:
              id: label_talon_kulutus
              x: 0
              y: 55
              text: "-- W"
              text_color: 0xFFFFFF
              text_font: roboto_34

    # Aurinkotuotanto
    - obj:
        x: 700
        y: 132
        width: 300
        height: 150
        bg_color: 0x252A33
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 18
        widgets:
          - label:
              text: "Aurinko"
              text_color: 0xAEB6C2
              text_font: roboto_22

          - label:
              id: label_aurinko
              x: 0
              y: 55
              text: "-- W"
              text_color: 0xFFFFFF
              text_font: roboto_34

    # Sisälämpö
    - obj:
        x: 24
        y: 302
        width: 220
        height: 120
        bg_color: 0x252A33
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 18
        widgets:
          - label:
              text: "Sisällä"
              text_color: 0xAEB6C2
              text_font: roboto_22

          - label:
              id: label_sisa_lampo
              x: 0
              y: 48
              text: "-- °C"
              text_color: 0xFFFFFF
              text_font: roboto_30

    # Ulkolämpö
    - obj:
        x: 270
        y: 302
        width: 220
        height: 120
        bg_color: 0x252A33
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 18
        widgets:
          - label:
              text: "Ulkona"
              text_color: 0xAEB6C2
              text_font: roboto_22

          - label:
              id: label_ulko_lampo
              x: 0
              y: 48
              text: "-- °C"
              text_color: 0xFFFFFF
              text_font: roboto_30

    # Vesivaraaja tila
    - obj:
        x: 516
        y: 302
        width: 220
        height: 120
        bg_color: 0x252A33
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 18
        widgets:
          - label:
              text: "Vesivaraaja"
              text_color: 0xAEB6C2
              text_font: roboto_22

          - label:
              id: label_vesivaraaja
              x: 0
              y: 48
              text: "--"
              text_color: 0xFFFFFF
              text_font: roboto_30

    # Näytön kirkkaus
    - obj:
        x: 762
        y: 302
        width: 238
        height: 120
        bg_color: 0x252A33
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 18
        widgets:
          - label:
              text: "Näyttö"
              text_color: 0xAEB6C2
              text_font: roboto_22

          - label:
              x: 0
              y: 48
              text: "100 %"
              text_color: 0xFFFFFF
              text_font: roboto_30

    # Lämminvesivaraajan lämpötila
    - obj:
        x: 24
        y: 445
        width: 230
        height: 95
        bg_color: 0x252A33
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        pad_all: 14
        widgets:
          - label:
              text: "LVV lämpö"
              text_color: 0xAEB6C2
              text_font: roboto_22

          - label:
              id: label_lvv_lampo
              x: 0
              y: 38
              text: "-- °C"
              text_color: 0xFFFFFF
              text_font: roboto_30

    # Olohuone nappi
    - button:
        x: 272
        y: 445
        width: 230
        height: 95
        bg_color: 0x2E3440
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        on_click:
          then:
            - homeassistant.service:
                service: switch.toggle
                data:
                  entity_id: ${ent_olohuone_valo}
        widgets:
          - label:
              align: CENTER
              text: "Olohuone"
              text_color: 0xFFFFFF
              text_font: roboto_30

    # Varaaja nappi
    - button:
        x: 520
        y: 445
        width: 230
        height: 95
        bg_color: 0x2E3440
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        on_click:
          then:
            - homeassistant.service:
                service: switch.toggle
                data:
                  entity_id: ${ent_vesivaraaja}
        widgets:
          - label:
              align: CENTER
              text: "Varaaja"
              text_color: 0xFFFFFF
              text_font: roboto_30

    # Olohuone 2 nappi
    - button:
        x: 768
        y: 445
        width: 232
        height: 95
        bg_color: 0x3B4252
        border_width: 0
        radius: 22
        scrollbar_mode: "OFF"
        scroll_dir: NONE
        on_click:
          then:
            - homeassistant.service:
                service: switch.toggle
                data:
                  entity_id: ${ent_sivu_valo}
        widgets:
          - label:
              align: CENTER
              text: "Olohuone 2"
              text_color: 0xFFFFFF
              text_font: roboto_30

Home Assistantin lupa palvelukutsuille

Jos näytön napit eivät tee mitään, tarkista Home Assistantista, että ESPHome-laite saa kutsua Home Assistantin palveluita.

  1. Avaa Settings.
  2. Mene kohtaan Devices & services.
  3. Avaa ESPHome.
  4. Valitse tämä näyttö.
  5. Paina Configure.
  6. Salli laitteen tehdä Home Assistant -palvelukutsuja.

Vianhaku

Laite kaatuilee tai logissa näkyy SDIO-virheitä

Tarkista ensin piirilevyversio. V1.0-laudalla tämän ohjeen tärkein kohta on esp32_hosted-osion bus_width: 1. Jos käytössä on väärä SDIO-moodi, seurauksena voi olla satunnaisia rebootteja ja SDIO/SDMMC-virheitä.

esp32_hosted:
  variant: esp32c6
  active_high: true
  bus_width: 1
  reset_pin: GPIO32
  cmd_pin: GPIO19
  clk_pin: GPIO18
  d0_pin: GPIO14
  d1_pin: GPIO15

Laite ei näy Windowsissa

Kokeile toista USB-C-johtoa. Mukana tullut johto voi olla pelkkä virtajohto.

Ä ja Ö eivät näy

Käytä Roboto-fontteja ja lisää ääkköset glyphs-listaan.

Näyttö rullaa oudosti

Lisää kortteihin ja nappeihin:

scrollbar_mode: "OFF"
scroll_dir: NONE

Napit eivät ohjaa mitään

Tarkista entiteetin nimi, käytä oikeaa palvelua kuten switch.toggle tai light.toggle, ja salli ESPHome-laitteelle Home Assistant -palvelukutsut.

Yhteenveto

Kun V1.0-laudan SDIO-asetus korjattiin 1-bit-moodiin, näyttö pysyi testeissä pystyssä myös varsinaisella Home Assistant -kojetaulukoodilla. Tämä oli tärkein ero verrattuna aiempaan kaatuiluun.