273 lines
7.3 KiB
YAML
273 lines
7.3 KiB
YAML
# TODO:
|
|
# - auto turn off
|
|
# - navigation bar at bottom
|
|
# - buttons for home assistant actions
|
|
|
|
|
|
substitutions:
|
|
device_name: kinderhandy
|
|
friendly_name: Kinder Handy
|
|
|
|
esphome:
|
|
name: $device_name
|
|
friendly_name: $friendly_name
|
|
|
|
esp32:
|
|
board: esp32dev
|
|
framework:
|
|
type: arduino
|
|
|
|
logger:
|
|
api:
|
|
encryption:
|
|
key: !secret api_encryption_key
|
|
|
|
wifi:
|
|
ssid: WLAN
|
|
password: !secret wifi_password
|
|
|
|
# ============================================================
|
|
# Hardware
|
|
# ============================================================
|
|
|
|
light:
|
|
- platform: monochromatic
|
|
output: backlight_pwm
|
|
name: Display Backlight
|
|
id: display_backlight
|
|
restore_mode: ALWAYS_ON
|
|
|
|
|
|
spi:
|
|
- id: tft
|
|
clk_pin: GPIO14
|
|
mosi_pin: GPIO13
|
|
miso_pin: GPIO12
|
|
- id: touch
|
|
clk_pin: GPIO25
|
|
mosi_pin: GPIO32
|
|
miso_pin: GPIO39
|
|
|
|
# Setup a pin to control the backlight
|
|
output:
|
|
- platform: ledc
|
|
pin: GPIO21
|
|
id: backlight_pwm
|
|
|
|
display:
|
|
- platform: ili9xxx
|
|
model: ili9341
|
|
spi_id: tft
|
|
cs_pin: GPIO15
|
|
dc_pin: GPIO2
|
|
invert_colors: false
|
|
color_palette: 8BIT
|
|
|
|
# Set up the xpt2046 touch platform
|
|
touchscreen:
|
|
platform: xpt2046
|
|
spi_id: touch
|
|
cs_pin: GPIO33
|
|
interrupt_pin: GPIO36
|
|
update_interval: never
|
|
threshold: 400
|
|
calibration:
|
|
x_min: 280
|
|
x_max: 3850
|
|
y_min: 190
|
|
y_max: 3765
|
|
transform:
|
|
swap_xy: false
|
|
mirror_x: true
|
|
on_release:
|
|
- if:
|
|
condition: lvgl.is_paused
|
|
then:
|
|
- logger.log: "LVGL resuming"
|
|
- lvgl.resume:
|
|
- lvgl.widget.redraw:
|
|
- light.turn_on: display_backlight
|
|
# on_touch:
|
|
# - lambda: |-
|
|
# ESP_LOGI("cal", "x=%d, y=%d, x_raw=%d, y_raw=%0d",
|
|
# touch.x,
|
|
# touch.y,
|
|
# touch.x_raw,
|
|
# touch.y_raw
|
|
# );
|
|
|
|
# ============================================================
|
|
# Globals
|
|
# ============================================================
|
|
|
|
globals:
|
|
- id: timer_seconds
|
|
type: int
|
|
initial_value: '120'
|
|
- id: timer_running
|
|
type: bool
|
|
initial_value: 'false'
|
|
|
|
# ============================================================
|
|
# Variables
|
|
# ============================================================
|
|
|
|
number:
|
|
- platform: template
|
|
name: LVGL Screen timeout
|
|
optimistic: true
|
|
id: display_timeout
|
|
unit_of_measurement: "s"
|
|
initial_value: 45
|
|
restore_value: true
|
|
min_value: 10
|
|
max_value: 180
|
|
step: 5
|
|
mode: box
|
|
|
|
# ============================================================
|
|
# Display
|
|
# ============================================================
|
|
|
|
lvgl:
|
|
on_idle:
|
|
timeout: !lambda "return (id(display_timeout).state * 1000);"
|
|
then:
|
|
- logger.log: "LVGL is idle"
|
|
- light.turn_off: display_backlight
|
|
- lvgl.pause:
|
|
buffer_size: 50%
|
|
widgets:
|
|
- label:
|
|
align: TOP_MID
|
|
y: 10
|
|
text: "Lukas und Hannas\nZahnputz Timer"
|
|
text_font: montserrat_20
|
|
- container:
|
|
id: arc_container
|
|
align: CENTER
|
|
y: 20
|
|
width: 240
|
|
height: 240
|
|
on_press:
|
|
then:
|
|
- if:
|
|
condition:
|
|
lambda: 'return id(timer_running);'
|
|
then:
|
|
- globals.set:
|
|
id: timer_running
|
|
value: 'false'
|
|
- logger.log:
|
|
format: "Pause"
|
|
- lvgl.arc.update:
|
|
id: arc_timer
|
|
indicator:
|
|
arc_color: 0x0000EE
|
|
else:
|
|
- globals.set:
|
|
id: timer_running
|
|
value: 'true'
|
|
- logger.log:
|
|
format: "Gestartet"
|
|
- lvgl.arc.update:
|
|
id: arc_timer
|
|
value: !lambda return id(timer_seconds);
|
|
indicator:
|
|
arc_color: 0xFF0000
|
|
on_long_press:
|
|
then:
|
|
- globals.set:
|
|
id: timer_seconds
|
|
value: '120'
|
|
- globals.set:
|
|
id: timer_running
|
|
value: 'false'
|
|
- lvgl.arc.update:
|
|
id: arc_timer
|
|
value: 0
|
|
indicator:
|
|
arc_color: 0xFF0000
|
|
- lvgl.label.update:
|
|
id: timer_label
|
|
text: !lambda 'return std::string("02:00");'
|
|
- logger.log:
|
|
format: "Timer reset (long press)"
|
|
widgets:
|
|
- arc:
|
|
id: arc_timer
|
|
align: CENTER
|
|
width: 220
|
|
height: 220
|
|
min_value: 0
|
|
max_value: 120
|
|
value: 0
|
|
arc_width: 8
|
|
arc_color: 0x404040
|
|
# Indicator arc styling (the progress)
|
|
indicator:
|
|
arc_width: 20
|
|
arc_opa: COVER
|
|
arc_color: 0xFF0000 # Start with red
|
|
- label:
|
|
id: timer_label
|
|
align: CENTER
|
|
text_font: montserrat_28
|
|
text: "02:00"
|
|
|
|
interval:
|
|
- interval: 1s
|
|
then:
|
|
- if:
|
|
condition:
|
|
lambda: 'return id(timer_running);'
|
|
then:
|
|
- globals.set:
|
|
id: timer_seconds
|
|
value: !lambda 'return max(0, (int)id(timer_seconds) - 1);'
|
|
- lvgl.arc.update:
|
|
id: arc_timer
|
|
value: !lambda 'return (int)(id(timer_seconds));'
|
|
indicator:
|
|
arc_color: !lambda |
|
|
float f = (120.0 - (float)id(timer_seconds)) / 120.0;
|
|
if (f < 0) f = 0;
|
|
if (f > 1) f = 1;
|
|
if (f <= 0.5) {
|
|
// Red to Yellow (f: 0.0 to 0.5)
|
|
float t = f / 0.5;
|
|
int r = 255;
|
|
int g = (int)(255 * t + 0.5);
|
|
int b = 0;
|
|
int hex = (r << 16) | (g << 8) | b;
|
|
return lv_color_hex(hex);
|
|
} else {
|
|
// Yellow to Green (f: 0.5 to 1.0)
|
|
float t = (f - 0.5) / 0.5;
|
|
int r = (int)(255 * (1.0 - t) + 0.5);
|
|
int g = 255;
|
|
int b = 0;
|
|
int hex = (r << 16) | (g << 8) | b;
|
|
return lv_color_hex(hex);
|
|
}
|
|
- lambda: |-
|
|
ESP_LOGI("timer", "timer_seconds=%d fraction=%.2f", id(timer_seconds), (float)id(timer_seconds)/120.0);
|
|
- lvgl.label.update:
|
|
id: timer_label
|
|
text: !lambda 'char buf[6]; sprintf(buf, "%02d:%02d", id(timer_seconds)/60, id(timer_seconds)%60); return std::string(buf);'
|
|
- if:
|
|
condition:
|
|
lambda: 'return id(timer_seconds) <= 0;'
|
|
then:
|
|
- globals.set:
|
|
id: timer_running
|
|
value: 'false'
|
|
- logger.log:
|
|
format: "Timer finished"
|
|
- lvgl.arc.update:
|
|
id: arc_timer
|
|
value: 120
|
|
indicator:
|
|
arc_color: 0x00FF00
|
|
|