382 lines
10 KiB
YAML
382 lines
10 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
|
|
actions:
|
|
- action: rtttl_play
|
|
variables:
|
|
song_str: string
|
|
then:
|
|
- rtttl.play:
|
|
rtttl: !lambda 'return song_str;'
|
|
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
|
|
- platform: ledc
|
|
pin: GPIO1
|
|
id: buzzer_output
|
|
|
|
display:
|
|
- platform: ili9xxx
|
|
model: ili9341
|
|
spi_id: tft
|
|
cs_pin: GPIO15
|
|
dc_pin: GPIO2
|
|
invert_colors: false
|
|
auto_clear_enabled: false
|
|
update_interval: never
|
|
|
|
# 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
|
|
# ============================================================
|
|
|
|
font:
|
|
- file: "fonts/RobotoCondensed-Regular.ttf"
|
|
id: roboto_icons_42
|
|
size: 42
|
|
bpp: 4
|
|
extras:
|
|
- file: "fonts/materialdesignicons-webfont.ttf"
|
|
glyphs: [
|
|
"\U000F0335", # mdi-lightbulb
|
|
"\U000F0954", # mdi-clock
|
|
"\U000F0142", # mdi-chevron-right
|
|
"\U000F004C", # mdi-bed
|
|
"\U000F0761", # mdi-window-shutter-open
|
|
"\U000F075E", # mdi-window-shutter
|
|
]
|
|
|
|
|
|
lvgl:
|
|
on_idle:
|
|
timeout: !lambda "return id(timer_running) ? 60 * 5 * 1000: (id(display_timeout).state * 1000);"
|
|
then:
|
|
- logger.log: "LVGL is idle"
|
|
- light.turn_off: display_backlight
|
|
- lvgl.pause:
|
|
buffer_size: 50%
|
|
style_definitions:
|
|
- id: header_footer
|
|
bg_color: 0x2F8CD8
|
|
bg_grad_color: 0x005782
|
|
bg_grad_dir: VER
|
|
bg_opa: COVER
|
|
border_opa: TRANSP
|
|
border_width: 0
|
|
outline_width: 0
|
|
radius: 0
|
|
pad_all: 0
|
|
pad_row: 0
|
|
pad_column: 0
|
|
border_color: 0x0077b3
|
|
text_color: 0xFFFFFF
|
|
width: 100%
|
|
height: 60
|
|
|
|
top_layer:
|
|
widgets:
|
|
- buttonmatrix:
|
|
align: bottom_mid
|
|
styles: header_footer
|
|
pad_all: 0
|
|
outline_width: 0
|
|
id: top_layer
|
|
items:
|
|
styles: header_footer
|
|
text_font: roboto_icons_42
|
|
rows:
|
|
- buttons:
|
|
- id: page_light
|
|
text: "\U000F0335"
|
|
on_press:
|
|
then:
|
|
- lvgl.page.show: kinderzimmer_page
|
|
- id: page_timer
|
|
text: "\U000F0954"
|
|
on_press:
|
|
then:
|
|
- lvgl.page.show: timer_page
|
|
|
|
pages:
|
|
- id: timer_page
|
|
widgets:
|
|
- label:
|
|
align: TOP_MID
|
|
y: 10
|
|
text: "Lukas und Hannas\nZahnputz Timer"
|
|
text_font: montserrat_20
|
|
text_align: CENTER
|
|
- container:
|
|
id: arc_container
|
|
align: CENTER
|
|
y: 15
|
|
width: 200
|
|
height: 200
|
|
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: 0x888888
|
|
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: 180
|
|
height: 180
|
|
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"
|
|
|
|
- id: kinderzimmer_page
|
|
widgets:
|
|
- label:
|
|
align: TOP_MID
|
|
y: 10
|
|
text: "Kinderzimmer"
|
|
text_font: montserrat_20
|
|
text_align: CENTER
|
|
- buttonmatrix:
|
|
align: CENTER
|
|
width: 280
|
|
height: 200
|
|
items:
|
|
text_font: roboto_icons_42
|
|
rows:
|
|
- buttons:
|
|
- id: btn_shelf_light
|
|
text: "\U000F0335"
|
|
- id: btn_cover_open
|
|
text: "\U000F0761"
|
|
- buttons:
|
|
- id: btn_cover_close
|
|
text: "\U000F075E"
|
|
- id: btn_bed
|
|
text: "\U000F004C"
|
|
|
|
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
|
|
|
|
|
|
# Buzzer
|
|
rtttl:
|
|
output: buzzer_output
|
|
id: my_buzzer_rtttl
|
|
gain: 60%
|
|
on_finished_playback:
|
|
- logger.log: 'Song ended!'
|
|
|
|
|
|
#Entchen:d=4,o=5,b=120:c,d,e,f,2g,2g,a,a,a,a,1g,a,a,a,a,1g,f,f,f,f,2e,2e,g,g,g,g,1c
|
|
#MissionImp:d=16,o=6,b=95:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d#,32e,32f,32f#,32g,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,a#,g,2d,32p,a#,g,2c#,32p,a#,g,2c,a#5,8c,2p,32p,a#5,g5,2f#,32p,a#5,g5,2f,32p,a#5,g5,2e,d#,8d |