CCCPaste

lilka second display

esphome:
  name: lilka
  friendly_name: lilka
  on_boot:
    priority: 600
    then:
      - output.turn_on: display_power
      - delay: 100ms

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: esp-idf

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: "Lilka Fallback Hotspot"
    password: "hnYImYM4O6I0"

captive_portal:

web_server:
  port: 80

api:
  encryption:
    key: "Yw3yq8lxsaze+jdggjAwxKpV4GD6gNZptvw4d6OPfOc="

logger:

ota:
  - platform: esphome
    password: "bb198feb99159fdaefc8092f10039acd"

output:
  - platform: gpio
    pin: 46
    id: display_power
    inverted: false

# ---------------------------------------------------
# СЕНСОРИ
# ---------------------------------------------------

sensor:
  - platform: adc
    pin: GPIO3
    name: "Battery Voltage"
    id: battery_voltage
    attenuation: 12db
    update_interval: 10s
    filters:
      - multiply: 1.33

  - platform: template
    name: "Battery Level"
    id: battery_level
    unit_of_measurement: "%"
    accuracy_decimals: 0
    update_interval: 10s
    lambda: |-
      float voltage = id(battery_voltage).state;
      float percent = (voltage - 3.0) / (4.2 - 3.0) * 100.0;
      if (percent > 100) percent = 100;
      if (percent < 0) percent = 0;
      return percent;

# ---------------------------------------------------
# ДИСПЛЕЙ + LVGL
# ---------------------------------------------------

spi:
  clk_pin: 18
  mosi_pin: 17

display:
  - platform: mipi_spi
    model: ST7789V
    id: my_display
    dc_pin: 15
    cs_pin: 7
    update_interval: 1s
    rotation: 270
    invert_colors: true
    color_order: BGR
    pixel_mode: 16bit
    dimensions:
      width: 280
      height: 240
      offset_width: 20
      offset_height: 0
    auto_clear_enabled: false

lvgl:
  log_level: INFO

  pages:

    # ---------------- MAIN PAGE -----------------
    - id: main_page
      bg_color: 0x000000
      widgets:

        - button:
            id: red_button
            align: CENTER
            y: -40
            width: 180
            height: 50
            bg_color: 0xFF0000
            widgets:
              - label:
                  id: battery_label
                  text: "Battery: --"
                  align: CENTER

        - button:
            id: green_button
            align: CENTER
            y: 20
            width: 180
            height: 50
            bg_color: 0x00FF00
            widgets:
              - label:
                  id: voltage_label
                  text: "Voltage: --"
                  align: CENTER
                  text_color: 0x000000

        - button:
            id: blue_button
            align: CENTER
            y: 80
            width: 180
            height: 50
            bg_color: 0x0000FF
            widgets:
              - label:
                  text: "Lilka LVGL"
                  align: CENTER
                  text_color: 0xFFFFFF

    # ---------------- SWITCH PAGE -----------------
    - id: switch_page
      bg_color: 0x000000
      widgets:

        - button:
            id: sw_btn1
            x: 10
            y: 100
            width: 80
            height: 80
            bg_color: 0x303030
            radius: 20
            widgets:
              - label:
                  id: sw_label1
                  text: "Вана"
                  align: CENTER

        - button:
            id: sw_btn2
            x: 100
            y: 100
            width: 80
            height: 80
            bg_color: 0x303030
            radius: 20
            widgets:
              - label:
                  id: sw_label2
                  text: "Комора"
                  align: CENTER

        - button:
            id: sw_btn3
            x: 190
            y: 100
            width: 80
            height: 80
            bg_color: 0x303030
            radius: 20
            widgets:
              - label:
                  id: sw_label3
                  text: "Кухня"
                  align: CENTER

# ---------------------------------------------------
# HA LIGHTS AS SWITCHES
# ---------------------------------------------------

switch:
  - platform: homeassistant
    id: sw1
    entity_id: light.tz3000_qewo8dlz_ts0013_light

  - platform: homeassistant
    id: sw2
    entity_id: light.tz3000_qewo8dlz_ts0013_light_2

  - platform: homeassistant
    id: sw3
    entity_id: light.tz3000_qewo8dlz_ts0013_light_3

# ---------------------------------------------------
# ГЛОБАЛЬНІ ЗМІННІ
# ---------------------------------------------------

globals:
  - id: current_main_index
    type: int
    initial_value: '0'

  - id: current_switch_index
    type: int
    initial_value: '0'

  - id: current_page
    type: int
    initial_value: '0'   # 0 = main_page, 1 = switch_page

# ---------------------------------------------------
# ФОКУС ДЛЯ СТОРІНОК
# ---------------------------------------------------

script:
  - id: update_main_focus
    then:
      - lvgl.widget.update:
          id: red_button
          border_width: !lambda 'return id(current_main_index)==0?3:0;'
      - lvgl.widget.update:
          id: green_button
          border_width: !lambda 'return id(current_main_index)==1?3:0;'
      - lvgl.widget.update:
          id: blue_button
          border_width: !lambda 'return id(current_main_index)==2?3:0;'

  - id: update_switch_focus
    then:
      - lvgl.widget.update:
          id: sw_btn1
          border_width: !lambda 'return id(current_switch_index)==0?3:0;'
      - lvgl.widget.update:
          id: sw_btn2
          border_width: !lambda 'return id(current_switch_index)==1?3:0;'
      - lvgl.widget.update:
          id: sw_btn3
          border_width: !lambda 'return id(current_switch_index)==2?3:0;'

# ---------------------------------------------------
# КНОПКИ
# ---------------------------------------------------

binary_sensor:

  # --- Навігація UP / DOWN тільки на головній сторінці ---
  - platform: gpio
    pin:
      number: 38
      mode: INPUT_PULLUP
      inverted: true
    id: button_up
    on_press:
      - lambda: |-
          if (id(current_page) == 0) {
            id(current_main_index)--;
            if (id(current_main_index) < 0) id(current_main_index) = 2;
          }
      - script.execute: update_main_focus

  - platform: gpio
    pin:
      number: 41
      mode: INPUT_PULLUP
      inverted: true
    id: button_down
    on_press:
      - lambda: |-
          if (id(current_page) == 0) {
            id(current_main_index)++;
            if (id(current_main_index) > 2) id(current_main_index) = 0;
          }
      - script.execute: update_main_focus

  # --- Ліво/право для сторінки світла ---
  - platform: gpio
    pin:
      number: 39
      mode: INPUT_PULLUP
      inverted: true
    id: button_left
    on_press:
      - lambda: |-
          if (id(current_page) == 1) {
            id(current_switch_index)--;
            if (id(current_switch_index) < 0) id(current_switch_index) = 2;
          }
      - script.execute: update_switch_focus

  - platform: gpio
    pin:
      number: 40
      mode: INPUT_PULLUP
      inverted: true
    id: button_right
    on_press:
      - lambda: |-
          if (id(current_page) == 1) {
            id(current_switch_index)++;
            if (id(current_switch_index) > 2) id(current_switch_index) = 0;
          }
      - script.execute: update_switch_focus

  # --- A: сторінка вперед ---
  - platform: gpio
    pin:
      number: 5
      mode: INPUT_PULLUP
      inverted: true
    id: button_a
    on_press:
      - lambda: |-
          id(current_page)++;
          if (id(current_page) > 1) id(current_page) = 0;
      - if:
          condition:
            lambda: 'return id(current_page)==0;'
          then:
            - lvgl.page.show: main_page
          else:
            - lvgl.page.show: switch_page

  # --- D: сторінка назад ---
  - platform: gpio
    pin:
      number: 9
      mode: INPUT_PULLUP
      inverted: true
    id: button_d
    on_press:
      - lambda: |-
          id(current_page)--;
          if (id(current_page) < 0) id(current_page) = 1;
      - if:
          condition:
            lambda: 'return id(current_page)==0;'
          then:
            - lvgl.page.show: main_page
          else:
            - lvgl.page.show: switch_page

  # --- SELECT → toggle вибраного світла ---
  - platform: gpio
    pin:
      number: 0
      mode: INPUT_PULLUP
      inverted: true
    id: button_select
    on_press:
      - lambda: |-
          if (id(current_page) == 1) {
            if (id(current_switch_index) == 0) id(sw1).toggle();
            if (id(current_switch_index) == 1) id(sw2).toggle();
            if (id(current_switch_index) == 2) id(sw3).toggle();
          }

# ---------------------------------------------------
# ОНОВЛЕННЯ БАТАРЕЇ
# ---------------------------------------------------

interval:
  - interval: 5s
    then:
      - lvgl.label.update:
          id: battery_label
          text: !lambda |-
            static char buf[32];
            int perc = (int) id(battery_level).state;
            if (perc < 0) perc = 0;
            if (perc > 100) perc = 100;
            snprintf(buf, sizeof(buf), "Battery: %d%%", perc);
            return buf;

      - lvgl.label.update:
          id: voltage_label
          text: !lambda |-
            static char buf2[32];
            snprintf(buf2, sizeof(buf2), "Voltage: %.2fV", id(battery_voltage).state);
            return buf2;