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;