configs/sthome-ut9-bak.yml

1529 lines
43 KiB
YAML

substitutions:
name: sthome-ut9
friendly_name: "sthome-ut9"
#ALLOWED_CHARACTERS_FULL: " !#%\"'()+,-./0123456789:;<>?@ABCDEFGHIJKLMNOPQRSTUVWYZ[]_abcdefghijklmnopqrstuvwxyz{|}°²³µ¿ÁÂÄÅÉÖÚßàáâãäåæçèéêëìíîðñòóôõöøùúûüýþāăąćčďĐđēėęěğĮįıļľŁłńňőřśšťũūůűųźŻżŽžơưșțΆΈΌΐΑΒΓΔΕΖΗΘΚΜΝΠΡΣΤΥΦάέήίαβγδεζηθικλμνξοπρςστυφχψωϊόύώАБВГДЕЖЗИКЛМНОПРСТУХЦЧШЪЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяёђєіїјљњћ"
ALLOWED_CHARACTERS: " !#%\"'()+,-./0123456789:;<>?@ABCDEFGHIJKLMNOPQRSTUVWYZ[]_abcdefghijklmnopqrstuvwxyz{|}°²³µ•"
DD_MAX_YEARS: "5"
esphome:
name: "${name}"
friendly_name: "${friendly_name}"
on_boot:
- lambda: |-
char yearstr[8];
lv_dropdown_set_selected(cal_dd_year->obj, 0);
lv_dropdown_set_selected(cal_dd_month->obj, 0);
lv_dropdown_get_selected_str(cal_dd_year->obj, yearstr, sizeof(yearstr));
int year = atoi(yearstr);
id(update_calendar).execute(year, 1);
- lvgl.widget.hide: ind_geyser_on
- delay: 5s
- lvgl.widget.hide: boot_screen
esp32:
board: esp32dev
framework:
type: arduino
#type: esp-idf
#debug:
# update_interval: 5s
# Enable logging
logger:
level: info
# Enable Home Assistant API
api:
encryption:
key: "LI7j37zs9HsWNsUZ5c83leThmhHsgIVReAPoc9U6pVU="
on_client_connected:
- if:
condition:
lambda: 'return (0 == client_info.find("Home Assistant "));'
then:
- lvgl.widget.show: lbl_hastatus
- lvgl.widget.show: lbl_degree
on_client_disconnected:
- if:
condition:
lambda: 'return (0 == client_info.find("Home Assistant "));'
then:
- lvgl.widget.hide: lbl_hastatus
- lvgl.widget.hide: ind_geyser_on
- lvgl.widget.hide: lbl_degree
ota:
- platform: esphome
password: "8ebd5bcefbdc833a5f6ddc4e8ba56e39"
wifi:
#ssid: !secret wifi_ssid
#password: !secret wifi_password
# we will use local dns server for local dns resolution
power_save_mode: none
domain: ".sthome.org"
networks:
- ssid: !secret wifi_ssid1
password: !secret wifi_password1
- ssid: !secret wifi_ssid2
password: !secret wifi_password2
- ssid: !secret wifi_ssid3
password: !secret wifi_password3
- ssid: !secret wifi_ssid4
password: !secret wifi_password4
- ssid: !secret wifi_ssid5
password: !secret wifi_password5
manual_ip:
# For faster connection startup, set a static IP address
# Set this to the IP of the ESP
static_ip: 10.0.2.9
gateway: 10.0.0.2
subnet: 255.255.240.0
dns1: 10.0.0.1
dns2: 1.1.1.1
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "${name} Fallback Hotspot"
password: "iZxjpw7ucRs4"
captive_portal:
#psram:
one_wire:
- platform: gpio
pin: GPIO4
id: temperature_sensors
#i2c:
# sda: GPIO21
# scl: GPIO22
font:
# - file: "fonts/Windows/comic.ttf"
# id: comic
# size: 20
# bpp: 4 #2
# - file: "fonts/misc/tom-thumb.bdf"
# id: tomthumb
#
# # gfonts://family[@weight]
# - file: "gfonts://Roboto"
# id: roboto_20
# size: 20
#
# - file:
# type: gfonts
# family: Roboto
# weight: 900
# id: roboto_20
# size: 20
#
# - file: "fonts/Windows/arial.ttf"
# id: arial_14
# size: 14
# # gfonts://family[@weight]
# - file: "gfonts://Roboto"
# id: roboto
# size: 20
- file: "gfonts://Carrois Gothic"
id: Carrois_Gothic
size: 20
bpp: 4
- file: "gfonts://Roboto"
id: roboto_200
size: 200
bpp: 4
glyphs: [
0123456789,.,°,a,n,
"\u0020", # space
"\u003A", # colon
]
- file: "gfonts://Roboto"
id: roboto_192
size: 192
bpp: 4
glyphs: [
0123456789,.,°,a,n,
"\u0020", # space
"\u003A", # colon
]
- file: "gfonts://Roboto"
id: geyser_temperature_font2
size: 60
bpp: 4
glyphs: [
°,C,
]
- file: "gfonts://Roboto"
id: geyser_temperature_font3
size: 30
bpp: 4
glyphs: [
b,o,m,p,t,
]
- file: "gfonts://Roboto"
id: roboto_100
size: 100
bpp: 4
glyphs: [
0123456789,.,a,n,
"\u0020", # space
"\u003A", # colon
]
# - file: "gfonts://Merriweather"
# id: Merriweather
# size: 30
#
# - file: "gfonts://Material+Symbols+Outlined"
# id: icons_50
# size: 50
# glyphs: ["\U0000e425"] # mdi-timer
#
# - file: "https://github.com/AlmostInteractive/ESP32-S3-Box-3-Voice-Assistant-Sensor-Dock/raw/master/fonts/materialdesignicons-webfont.ttf"
# id: font_icon_tiny
# size: 30
# glyphs: [
# "\U000F009A",#bell
# "\U000F009C",#bell-outline
# "\U000F00AD",#block-helper
# "\U000F01F2",#emoticon-outline
# "\U000F0375",#minus-box
# "\U000F0416",#plus-box
# ]
#
- file: "fonts/misc/materialdesignicons-webfont.ttf"
id: font_icon_small
size: 24 #45
glyphs: [
"\U0000F5A9",
]
# - file: "https://github.com/AlmostInteractive/ESP32-S3-Box-3-Voice-Assistant-Sensor-Dock/raw/master/fonts/materialdesignicons-webfont.ttf"
# id: font_icon_large
# size: 65
# glyphs: [
# "\U000F004F",#arrow-left-bold-circle
# "\U000F0056",#arrow-right-bold-circle
# ]
image:
- file: https://esphome.io/_static/favicon-512x512.png
id: boot_logo
resize: 200x200
type: RGB565
transparency: alpha_channel
- file: mdi:fire
id: icon_fire
resize: 100x100
type: BINARY #RGB565
# - file: "images/fire.svg"
# id: img_fire
# resize: 100x100
# type: RGB565
# transparency: alpha_channel
# - file: "images/fire-red.svg"
# id: img_fire_red
# resize: 100x100 # 25x25
# type: RGB565
# transparency: alpha_channel
# - file: "images/thermometer2.png"
# id: thermometer_img
# type: RGB565
# transparency: alpha_channel
color:
- id: green
hex: '75D15F'
- id: red
hex: 'FF3131'
- id: light_red
hex: 'FF3340'
- id: blue
hex: '47B7E9'
- id: blue_light
hex: 'CFE2F3'
- id: blue_dark
hex: '085296'
- id: amber
hex: 'FBAB35'
- id: lime
hex: '20FC30'
- id: pink
hex: 'D92BBC'
- id: yellow
hex: 'FFC000'
- id: black
hex: '000000'
- id: white
hex: 'ffffff'
- id: purple
hex: '73264D'
- id: grey_dark
hex: '202020'
- id: grey_light
hex: 'e0e0e0'
sun:
id: sun_sensor
latitude: !secret latitude
longitude: !secret longitude
#time:
# - platform: sntp
# timezone: Africa/Johannesburg
# servers:
# - ntp1.meraka.csir.co.za # 146.64.24.58
# - ntp.as3741.net # 196.4.160.4
# - ntp1.inx.net.za # 196.10.52.57
time:
- platform: homeassistant
id: time_source
update_interval: 360min # Change sync interval from default 5min to 6 hours
on_time_sync:
then:
- if: # Publish the time the device was last restarted, but only once.
condition:
lambda: 'return id(device_last_restart).state == "";'
then:
- text_sensor.template.publish:
id: device_last_restart
state: !lambda 'return id(time_source).now().strftime("%a %d %b %Y - %I:%M:%S %p");'
- script.execute: ind_heating_update
- script.execute: time_update
- script.execute: init_calendar
on_time:
- minutes: '*'
seconds: '*'
then:
- script.execute: ind_heating_update
- script.execute: time_update
- hours: 1,2,3,4
minutes: 5
seconds: 0
then:
- switch.turn_on: switch_antiburn
- hours: 1,2,3,4
minutes: 35
seconds: 0
then:
- switch.turn_off: switch_antiburn
spi:
- id: spi_bus0
clk_pin: GPIO18
mosi_pin: GPIO23
miso_pin: GPIO19
interface: any
display:
- platform: ili9xxx
model: ili9488
id: tft_display
color_palette: 8BIT
data_rate: 40MHz
cs_pin: GPIO15
dc_pin: GPIO2
reset_pin: GPIO27
auto_clear_enabled: false
update_interval: never
invert_colors: false
show_test_card: true
transform:
swap_xy: true # landscape
# mirror_x: true # landscape
dimensions:
height: 480
width: 320
# Define a PWM output on the ESP32
output:
- platform: ledc
pin: GPIO26
id: backlight_pwm
# Define a monochromatic, dimmable light for the backlight
light:
- platform: monochromatic
output: backlight_pwm
name: "Display Backlight"
id: back_light
restore_mode: ALWAYS_ON
touchscreen:
platform: xpt2046
id: touch_screen
cs_pin: GPIO33
transform:
swap_xy: true # landscape
# mirror_y: true # portrait
calibration:
x_min: 231 #201 #281
x_max: 3878 #3793 #3848
y_min: 221 #228 #347
y_max: 3861 #3914 #3878
# 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
# );
# on_release:
# then:
# - if:
# condition: lvgl.is_paused
# then:
# - lvgl.resume:
# - lvgl.widget.redraw:
lvgl:
# color_depth: 16
# bg_color: 0x0F0F0F
default_font: unscii_8
# align: center
theme:
button:
bg_color: grey_light #0x2F8CD8
# bg_grad_color: 0x005782
# bg_grad_dir: VER
bg_opa: COVER
border_color: 0x0077b3
border_width: 1
text_color: 0xFFFFFF
pressed: # set some button colors to be different in pressed state
bg_color: 0x006699
bg_grad_color: 0x00334d
checked: # set some button colors to be different in checked state
bg_color: 0x1d5f96
bg_grad_color: 0x03324A
text_color: 0xfff300
switch:
bg_color: 0xC0C0C0
bg_grad_color: 0xb0b0b0
bg_grad_dir: VER
bg_opa: COVER
checked:
bg_color: 0x1d5f96
bg_grad_color: 0x03324A
bg_grad_dir: VER
bg_opa: COVER
knob:
bg_color: 0xFFFFFF
bg_grad_color: 0xC0C0C0
bg_grad_dir: VER
bg_opa: COVER
slider:
border_width: 1
border_opa: 15%
bg_color: 0xcccaca
bg_opa: 15%
indicator:
bg_color: 0x1d5f96
bg_grad_color: 0x03324A
bg_grad_dir: VER
bg_opa: COVER
knob:
bg_color: 0x2F8CD8
bg_grad_color: 0x005782
bg_grad_dir: VER
bg_opa: COVER
border_color: 0x0077b3
border_width: 1
text_color: 0xFFFFFF
style_definitions:
- id: header_footer
bg_color: darkgrey #0x2F8CD8
bg_opa: COVER
border_opa: TRANSP
radius: 0
pad_all: 0
pad_row: 0
pad_column: 0
border_color: 0x0077b3
text_color: 0xFFFFFF
width: 100%
height: 30
- id: clockdate_style
text_font: montserrat_20 #roboto_20 #unscii_8
text_align: center
text_color: 0x000000
radius: 4
pad_all: 2
- id: sty_calendar_small
radius: 0
pad_all: 0
pad_row: 0
pad_column: 0
text_font: unscii_8
shadow_opa: TRANSP
text_color: black
bg_color: white
bg_opa: COVER
border_color: grey_light
border_width: 1
border_opa: cover #TRANSP
- id: sty_calendar_small_noborders
radius: 0
pad_all: 0
pad_row: 0
pad_column: 0
text_font: unscii_8
shadow_opa: TRANSP
text_color: black
bg_color: white
bg_opa: COVER
border_color: grey_light
border_width: 0
border_opa: cover #TRANSP
displays:
- tft_display
buffer_size: 20%
top_layer:
widgets:
- label:
text: "\U0000F5A9" # "\uF1EB"
id: lbl_hastatus
hidden: true
align: top_right
x: -2
y: 1
text_font: font_icon_small #montserrat_16
text_align: right
text_color: 0x202020 # 0xFFFFFF
- obj: # clipping rectangle
x: 0 #15
y: -24 #7
pad_all: 0
height: 90
width: 65
align: BOTTOM_RIGHT
bg_color: 0x000000
border_color: 0xFFFFFF
border_width: 0
radius: 0
bg_opa: LV_OPA_TRANSP
scrollbar_mode: "OFF"
widgets:
- image:
id: ind_geyser_on
align: CENTER #BOTTOM_RIGHT #TOP_RIGHT
src: icon_fire
image_recolor: RED
image_recolor_opa: 100%
x: 0 #15 #15
y: 0 #-22 #7
height: 100 #25
width: 100 #25
- obj:
id: boot_screen
x: 0
y: 0
width: 100%
height: 100%
bg_color: 0xffffff
bg_opa: COVER
radius: 0
pad_all: 0
border_width: 0
widgets:
- image:
align: CENTER
src: boot_logo
y: -40
- spinner:
align: CENTER
y: 95
height: 50
width: 50
spin_time: 1s
arc_length: 60deg
arc_width: 8
indicator:
arc_color: 0x18bcf2
arc_width: 8
on_press:
- lvgl.widget.hide: boot_screen
- buttonmatrix:
text_font: montserrat_16
align: bottom_mid
styles: header_footer
pad_all: 0
outline_width: 0
id: footer
width: 480
items:
styles: header_footer
rows:
- buttons:
- id: page_prev
text: "\uF053"
on_press:
then:
lvgl.page.previous:
- id: page_home
text: "\uF015"
on_press:
then:
lvgl.page.show: main_page
- id: page_next
text: "\uF054"
on_press:
then:
lvgl.page.next:
pages:
- id: pg_calendar
widgets:
- button:
id: cal_btn_prev_month
styles: sty_calendar_small
align: TOP_MID
pad_all: 0
outline_width: 0
border_color: black
border_width: 0 #1
border_opa: TRANSP
x: -75
y: 30
width: 20
height: 20
bg_color: grey_light
text_color: 0xD3D3D3
text_font: montserrat_14
widgets:
- label:
align: center
text_font: montserrat_14
text: "<"
on_press:
then:
lambda: |-
id(update_calendar_month).execute(-1);
- dropdown:
id: cal_dd_year
styles: sty_calendar_small
text_font: montserrat_12
height: 20
width: 55
radius: 0
align_to:
id: cal_btn_prev_month
align: out_right_top
x: 80
y: 0 #12.5%
options:
- 2024
- 2025
selected_index: 0
dropdown_list:
text_line_space: 3
pad_all: 1
text_font: unscii_8
max_height: 260
radius: 0
selected:
checked:
text_color: 0xFF0000
on_value:
then:
- lambda: |-
char yearstr[8];
lv_dropdown_get_selected_str(cal_dd_year->obj, yearstr, sizeof(yearstr));
int month = 1 + lv_dropdown_get_selected(cal_dd_month->obj);
auto year = atoi(yearstr);
id(update_calendar).execute(year, month);
- dropdown:
id: cal_dd_month
styles: sty_calendar_small
text_font: montserrat_12
height: 20
width: 55
radius: 0
align_to:
id: cal_dd_year
align: out_right_top
x: 0
y: 0 #12.5%
options:
- Jan
- Feb
- Mar
- Apr
- May
- Jun
- Jul
- Aug
- Sep
- Oct
- Nov
- Dec
selected_index: 0
dropdown_list:
text_line_space: 3
pad_all: 1
text_font: unscii_8
max_height: 260
radius: 0
selected:
checked:
text_color: 0xFF0000
on_value:
then:
- lambda: |-
char yearstr[8];
lv_dropdown_get_selected_str(cal_dd_year->obj, yearstr, sizeof(yearstr));
auto year = atoi(yearstr);
id(update_calendar).execute(year, x + 1);
- button:
id: cal_btn_next_month
styles: sty_calendar_small
align_to:
id: cal_dd_month
align: out_right_top
x: 0
y: 0
pad_all: 0
outline_width: 0
border_color: black
border_width: 0 #1
border_opa: TRANSP
x: -75
y: 30
width: 20
height: 20
bg_color: grey_light
text_color: 0xD3D3D3
text_font: montserrat_14
widgets:
- label:
align: center
text_font: montserrat_14
text: ">"
on_press:
then:
lambda: |-
id(update_calendar_month).execute(1);
- buttonmatrix:
id: bmx_cal_header_dow
styles: sty_calendar_small_noborders
align_to:
id: cal_btn_prev_month
align: out_bottom_left
x: 80
y: 0 #12.5%
pad_all: 0
outline_width: 0
border_color: black
border_width: 0 #1
border_opa: TRANSP
x: 0
y: 0
width: 150
height: 20
bg_color: black
text_color: 0xD3D3D3
items:
styles: sty_calendar_small_noborders
pressed:
bg_color: 0x006699
bg_grad_color: 0x00334d
checked:
bg_color: 0x1d5f96
bg_grad_color: 0x03324A
rows:
- buttons:
- id: r0c1
text: "Su"
width: 1
- id: r0c2
text: "Mo"
width: 1
- id: r0c3
text: "Tu"
width: 1
- id: r0c4
text: "We"
width: 1
- id: r0c5
text: "Th"
width: 1
- id: r0c6
text: "Fr"
width: 1
- id: r0c7
text: "Sa"
width: 1
on_press:
then:
- lambda: |-
ESP_LOGI("lvgl", "%d", x);
- buttonmatrix:
id: bmx_calendar
styles: sty_calendar_small
align_to:
id: bmx_cal_header_dow
align: out_bottom_left
x: 0
y: 0 #12.5%
pad_all: 0
outline_width: 0
border_color: black
border_width: 0 #1
border_opa: TRANSP
x: 0
y: 0
width: 150
height: 100
bg_color: black
text_color: 0xD3D3D3
items:
styles: sty_calendar_small
pressed:
bg_color: 0x006699
bg_grad_color: 0x00334d
checked:
bg_color: 0x1d5f96
bg_grad_color: 0x03324A
rows:
- buttons:
- id: r1c1
text: " "
width: 1
control:
recolor: true
- id: r1c2
text: " "
width: 1
- id: r1c3
text: "1"
width: 1
- id: r1c4
text: "2"
width: 1
- id: r1c5
text: "3"
width: 1
- id: r1c6
text: "4"
width: 1
- id: r1c7
text: "5"
width: 1
# - buttons:
# - id: r2c1
# text: "6"
# width: 1
# control:
# recolor: true
# - id: r2c2
# text: "7"
# width: 1
# - id: r2c3
# text: "8"
# width: 1
# - id: r2c4
# text: "9"
# width: 1
# - id: r2c5
# text: "10"
# width: 1
# - id: r2c6
# text: "11"
# width: 1
# - id: r2c7
# text: "12"
# width: 1
# - buttons:
# - id: r3c1
# text: "13"
# width: 1
# - id: r3c2
# text: "14"
# width: 1
# - id: r3c3
# text: "15"
# width: 1
# - id: r3c4
# text: "16"
# width: 1
# - id: r3c5
# text: "17"
# width: 1
# - id: r3c6
# text: "18"
# width: 1
# - id: r3c7
# text: "19"
# width: 1
# - buttons:
# - id: r4c1
# text: "20"
# width: 1
# - id: r4c2
# text: "21"
# width: 1
# - id: r4c3
# text: "22"
# width: 1
# - id: r4c4
# text: "23"
# width: 1
# - id: r4c5
# text: "24"
# width: 1
# - id: r4c6
# text: "25"
# width: 1
# - id: r4c7
# text: "26"
# width: 1
# - buttons:
# - id: r5c1
# text: "27"
# width: 1
# - id: r5c2
# text: "28"
# width: 1
# - id: r5c3
# text: "29"
# width: 1
# - id: r5c4
# text: "30"
# width: 1
# - id: r5c5
# text: "31"
# width: 1
# - id: r5c6
# text: " "
# width: 1
# - id: r5c7
# text: " "
# width: 1
# Define actions on button press
on_press:
then:
lambda: |-
auto stat = lv_btnmatrix_has_btn_ctrl(bmx_calendar->obj, x, LV_BTNMATRIX_CTRL_CHECKED);
auto day = lv_btnmatrix_get_btn_text(bmx_calendar->obj, x);
ESP_LOGI("lvgl", "%d (%s) [%d]", x, day, stat);
if(stat) {
lv_btnmatrix_clear_btn_ctrl(bmx_calendar->obj, x, LV_BTNMATRIX_CTRL_CHECKED);
}
else {
lv_btnmatrix_set_btn_ctrl(bmx_calendar->obj, x, LV_BTNMATRIX_CTRL_CHECKED);
}
- id: main_page #pg_geyser_temp
widgets:
- obj:
id: rect_gtoptemp
x: 0
y: 0 #30
pad_all: 0
height: 290
width: 240
align: TOP_LEFT
bg_color: 0x000000
border_color: 0xFFFFFF
border_width: 0
radius: 0
bg_opa: COVER
- obj:
id: rect_gbottemp
y: 0
pad_all: 0
height: 290
width: 240
align_to:
id: rect_gtoptemp
align: out_right_top
x: 0
y: 0 #12.5%
bg_color: 0x000000 #0xFF4500
border_color: 0xFFFFFF
border_width: 0
radius: 0
bg_opa: COVER
- label:
text: " "
id: lbl_gtoptemp
hidden: false
align: LEFT_MID
x: 0
y: -10
text_font: roboto_200
text_align: center
text_color: 0x0
bg_opa: LV_OPA_TRANSP
bg_color: 0xffffff
- label:
text: " "
id: lbl_gbottemp
hidden: false
align: RIGHT_MID
x: 0
y: -10
text_font: roboto_200
text_align: center
text_color: 0x0
bg_opa: LV_OPA_TRANSP
bg_color: 0xffffff
- label:
text: "°C"
id: lbl_degree
hidden: false
align: BOTTOM_MID
x: 0
y: -30
text_font: geyser_temperature_font2
text_align: center
text_color: 0x0
bg_opa: LV_OPA_TRANSP
bg_color: 0xffffff
- label:
text: "top"
id: lbl_top
hidden: false
align: TOP_MID
x: -120
y: 20
text_font: geyser_temperature_font3
text_align: center
text_color: 0x0
bg_opa: LV_OPA_TRANSP
bg_color: 0xffffff
- label:
text: "bottom"
id: lbl_bottom
hidden: false
align: TOP_MID
x: 120
y: 20
text_font: geyser_temperature_font3
text_align: center
text_color: 0x0
bg_opa: LV_OPA_TRANSP
bg_color: 0xffffff
- id: pg_settings
widgets:
- textarea:
id: geyser_schedule
one_line: true
placeholder_text: "Enter text here"
- keyboard:
id: keyboard_id
textarea: geyser_schedule
mode: TEXT_UPPER
text_font: montserrat_20
on_focus:
then:
- lvgl.keyboard.update:
id: keyboard_id
mode: number
textarea: geyser_schedule
on_ready:
then:
- logger.log: Keyboard is ready
on_cancel:
then:
- logger.log: Keyboard cancelled
- id: pg_clock
widgets:
- obj: # clock container
height: 300 #SIZE_CONTENT
width: 300 # 100%
align: TOP_MID
pad_all: 0
border_width: 0
bg_color: 0xFFFFFF
widgets:
- meter: # clock face
height: 300
width: 300
align: TOP_MID
bg_opa: TRANSP
border_width: 0
text_color: 0x000000
scales:
- range_from: 0 # minutes scale
range_to: 720
angle_range: 360
rotation: 270
ticks:
width: 1
count: 61
length: 10
color: 0x000000
indicators:
- line:
id: minute_hand
width: 3
color: 0xa6a6a6
r_mod: -4
value: 0
- range_from: 1 # hours scale for labels
range_to: 12
angle_range: 330
rotation: 300
ticks:
width: 1
count: 12
length: 1
major:
stride: 1
width: 4
length: 10
color: 0xC0C0C0
label_gap: 12
- range_from: 0 # hi-res hours scale for hand
range_to: 720
angle_range: 360
rotation: 270
ticks:
count: 0
indicators:
- line:
id: hour_hand
width: 5
color: 0xa6a6a6
r_mod: -30
value: 0
# Second hand
- angle_range: 360
rotation: 270
range_from: 0
range_to: 60
indicators:
- line:
id: second_hand
width: 2
color: Red
r_mod: -10
- label:
align: CENTER
styles: clockdate_style
id: day_label
y: -50
- label:
align: CENTER
id: date_label
styles: clockdate_style
y: 50
- id: pg_digital_clock
widgets:
- obj:
id: rect_gtoptemp1
x: 0
y: 0 #30
pad_all: 0
height: 290
width: 240
align: TOP_LEFT
bg_color: 0x000000
border_color: 0xFFFFFF
border_width: 0
radius: 0
bg_opa: COVER
- obj:
id: rect_gbottemp1
y: 0
pad_all: 0
height: 290
width: 240
align_to:
id: rect_gtoptemp
align: out_right_top
x: 0
y: 0 #12.5%
bg_color: 0x000000 #0xFF4500
border_color: 0xFFFFFF
border_width: 0
radius: 0
bg_opa: COVER
- label:
text: " "
id: lbl_digitalclock
hidden: false
align: TOP_MID
x: 0
y: 20
text_font: roboto_192
text_align: center
text_color: RED
bg_opa: LV_OPA_TRANSP
bg_color: 0xffffff
#interval:
# - interval: 30s
# then:
# - lvgl.page.next
switch:
- platform: restart
name: "${name} Restart"
id: "restart_switch"
- platform: template
name: Antiburn
id: switch_antiburn
icon: mdi:television-shimmer
optimistic: true
entity_category: "config"
turn_on_action:
- logger.log: "Starting Antiburn"
- if:
condition: lvgl.is_paused
then:
- lvgl.resume:
- lvgl.widget.redraw:
- lvgl.pause:
show_snow: true
turn_off_action:
- logger.log: "Stopping Antiburn"
- if:
condition: lvgl.is_paused
then:
- lvgl.resume:
- lvgl.widget.redraw:
binary_sensor:
- platform: homeassistant
name: "Geyser Heating"
entity_id: binary_sensor.sthome_ut8_heating
id: geyser_heating
on_press:
then:
- lvgl.widget.show: ind_geyser_on
on_release:
then:
- lvgl.widget.hide: ind_geyser_on
sensor:
- platform: dallas_temp
address: 0xfe00000037b3d528
name: "Study Temperature"
id: study_temperature
update_interval: "60s"
resolution: 12
one_wire_id: temperature_sensors
unit_of_measurement: "°C"
#icon: "mdi:water-thermometer"
device_class: "temperature"
state_class: "measurement"
accuracy_decimals: 1
filters:
- filter_out: nan
# - sliding_window_moving_average:
# window_size: 120 # averages over 120 update intervals
# send_every: 60 # reports every 60 update intervals
# Report wifi signal strength every 5 min if changed
- platform: wifi_signal
name: WiFi Signal
id: wifi_sig
update_interval: 300s
filters:
- delta: 10%
# human readable uptime sensor output to the text sensor above
- platform: uptime
name: Uptime in Days
id: uptime_sensor_days
update_interval: 10s
on_raw_value:
then:
- text_sensor.template.publish:
id: uptime_human
state: !lambda |-
int seconds = round(id(uptime_sensor_days).raw_state);
int days = seconds / (24 * 3600);
seconds = seconds % (24 * 3600);
int hours = seconds / 3600;
seconds = seconds % 3600;
int minutes = seconds / 60;
seconds = seconds % 60;
auto days_str = std::to_string(days);
auto hours_str = std::to_string(hours);
auto minutes_str = std::to_string(minutes);
auto seconds_str = std::to_string(seconds);
return (
(days ? days_str + "d " : "") +
(hours ? hours_str + "h " : "") +
(minutes ? minutes_str + "m " : "") +
(seconds_str + "s")
).c_str();
# number of seconds since midnight
- platform: template
id: time_of_day
name: "Time of day"
accuracy_decimals: 0
unit_of_measurement: "s"
lambda: |-
auto currenttime = id(time_source).now();
ESPTime time_obj = currenttime;
time_obj.second = 0;
time_obj.minute = 0;
time_obj.hour = 0;
time_obj.recalc_timestamp_local();
return currenttime.timestamp - time_obj.timestamp;
update_interval: 10s
- platform: homeassistant
name: "Geyser Top Temperature"
entity_id: sensor.sthome_ut8_geyser_top_temperature
id: geyser_top_temperature
on_raw_value:
then:
- lvgl.label.update:
id: lbl_gtoptemp
text: !lambda |-
if(isnan(x)) {
return ".";
}
else {
char buffer [10];
buffer[0] = '\0';
snprintf (buffer, 10, "%.0f", x);
return buffer;
}
- lvgl.widget.update:
id: rect_gtoptemp
bg_color: !lambda |-
if(isnan(x)) {
return lv_color_hex(0x000000);
}
if(x >= 60) {
return lv_color_hex(0xFF0000);
}
if(x >= 50) {
return lv_color_hex(0xFFFF00);
}
if(x >= 40) {
return lv_color_hex(0x00FF00);
}
return lv_color_hex(0x0000FF);
- platform: homeassistant
name: "Geyser Bottom Temperature"
entity_id: sensor.sthome_ut8_geyser_bottom_temperature
id: geyser_bottom_temperature
on_raw_value:
then:
- lvgl.label.update:
id: lbl_gbottemp
text: !lambda |-
if(isnan(x)) {
return ".";
}
else {
char buffer [10];
buffer[0] = '\0';
snprintf (buffer, 10, "%.0f", x);
return buffer;
}
- lvgl.widget.update:
id: rect_gbottemp
bg_color: !lambda |-
if(isnan(x)) {
return lv_color_hex(0x000000);
}
if(x < 40) {
return lv_color_hex(0x0000FF);
}
if(x < 50) {
return lv_color_hex(0x00FF00);
}
if(x < 60) {
return lv_color_hex(0xFFFF00);
}
return lv_color_hex(0xFF0000);
text_sensor:
- platform: template
id: module_time
name: "Module time"
icon: mdi:clock
lambda: |-
auto time_obj = id(time_source).now();
return time_obj.strftime("%Y-%m-%d %H:%M:%S");
update_interval: 1s
# Expose WiFi information as sensors
- platform: wifi_info
ip_address:
name: IP
mac_address:
name: Mac Address
entity_category: diagnostic
ssid:
name: "Connected SSID"
id: ssid
entity_category: diagnostic
# human readable update text sensor from sensor:uptime
- platform: template
name: Uptime
id: uptime_human
icon: mdi:clock-start
- platform: template
name: 'Last Restart'
id: device_last_restart
icon: mdi:clock
entity_category: diagnostic
script:
- id: time_update
then:
- lvgl.indicator.update:
id: minute_hand
value: !lambda |-
auto now = id(time_source).now();
return now.minute * 12 + now.second/5;
- lvgl.indicator.update:
id: hour_hand
value: !lambda |-
auto now = id(time_source).now();
return std::fmod(now.hour, 12) * 60 + now.minute;
- lvgl.indicator.update:
id: second_hand
value: !lambda |-
auto now = id(time_source).now();
return now.second;
- lvgl.label.update:
id: date_label
text: !lambda |-
static const char * const mon_names[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
static char date_buf[8];
auto now = id(time_source).now();
snprintf(date_buf, sizeof(date_buf), "%s %2d", mon_names[now.month-1], now.day_of_month);
return date_buf;
- lvgl.label.update:
id: day_label
text: !lambda |-
static const char * const day_names[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
return day_names[id(time_source).now().day_of_week - 1];
- lvgl.label.update:
id: lbl_digitalclock
text: !lambda |-
auto time_obj = id(time_source).now();
return time_obj.strftime("%H:%M");
- id: ind_heating_update
then:
- lvgl.widget.update:
id: ind_geyser_on
hidden: !lambda return !id(geyser_heating).state;
- id: init_calendar
then:
- lambda: |-
auto now = id(time_source).now();
//ESP_LOGI("yopts before", stroptions.c_str());
int y = 0;
std::string stroptions = to_string(now.year + y);
while(++y < ${DD_MAX_YEARS}) {
stroptions += "\n" + to_string(now.year + y);
}
//ESP_LOGI("yopts after", stroptions.c_str());
lv_dropdown_set_options(cal_dd_year->obj, stroptions.c_str());
lv_dropdown_set_selected(cal_dd_year->obj, 0); // this year is first index
lv_dropdown_set_selected(cal_dd_month->obj, now.month-1);
id(update_calendar).execute(now.year, now.month);
- id: update_calendar_month
parameters:
increment : int
then:
- lambda: |-
char yearstr[8];
lv_dropdown_get_selected_str(cal_dd_year->obj, yearstr, sizeof(yearstr));
auto year = atoi(yearstr);
int year_idx = lv_dropdown_get_selected(cal_dd_year->obj);
int month_idx = increment + lv_dropdown_get_selected(cal_dd_month->obj);
int month = 1 + month_idx;
if(month > 12 && year_idx < ${DD_MAX_YEARS} - 1) {
month -= 12;
month_idx -= 12;
year++;
year_idx++;
}
else if(month < 1 && year_idx > 0) {
month += 12;
month_idx += 12;
year--;
year_idx--;
}
ESP_LOGI("cm", "month: %d, year: %d", month, year);
if(month < 13 && month > 0) {
lv_dropdown_set_selected(cal_dd_year->obj, year_idx);
lv_dropdown_set_selected(cal_dd_month->obj, month_idx);
id(update_calendar).execute(year, month);
}
- id: update_calendar
parameters:
year : int
month : int
then:
lambda: |-
int monthdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static std::string strdays[44];
static const char *pstrdays[49]; // including newline at end of week
static const char *newline = "\n";
bool isLeapYear = (year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0));
monthdays[1] = (isLeapYear) ? 29 : 28;
// calculate day of week of 1st of month using Zeller's rule
// https://beginnersbook.com/2013/04/calculating-day-given-date
// modified month, year
int mM = month - 2;
int m = mM < 1 ? 12 + mM : mM;
int mY = mM < 1 ? year - 1 : year;
int k = 1; // day of month
int D = mY % 100; // last two digits of the year
int C = trunc(mY / 100); // first two digits of the year
int F = k + trunc((13 * m - 1) / 5) + D + trunc(D / 4) + trunc(C / 4) - 2 * C;
int Z = F % 7;
int start_of_month = Z < 0 ? Z + 7 : Z;
// end of Zeller's rule
lv_btnmatrix_set_btn_ctrl_all(bmx_calendar->obj, LV_BTNMATRIX_CTRL_CHECKABLE | LV_BTNMATRIX_CTRL_RECOLOR);
int previous_month = (month == 1) ? 12 : month - 1;
int month_days = monthdays[month - 1];
int prev_month_days = monthdays[previous_month - 1];
int i = 0;
int j = -1;
//ESP_LOGI("vals", "start_of_month: %d, previous_month: %d, month_days: %d, prev_month_days: %d", start_of_month, previous_month, month_days, prev_month_days);
for (int w = 0; w < 6 && i < (month_days + start_of_month); w++) {
for(int wd = 0; wd < 7; wd++) {
int day = i + 1 - start_of_month;
if (i < start_of_month) {
day += prev_month_days;
strdays[i] = "#e0e0e0 " + to_string(day) + "#";
}
else if (i >= (month_days + start_of_month)) {
day -= month_days;
strdays[i] = "#e0e0e0 " + to_string(day) + "#";
}
else {
strdays[i] = to_string(day);
}
pstrdays[++j] = strdays[i].c_str();
//ESP_LOGI("bmx", "%s, i: %d, j: %d", pstrdays[j], i, j);
i++;
}
pstrdays[++j] = newline;
//ESP_LOGI("bmxnl", "%s, i: %d, j: %d", pstrdays[j], i, j);
}
pstrdays[j] = NULL; // overwrites last newline
lv_btnmatrix_set_map(bmx_calendar->obj, pstrdays);
lv_btnmatrix_set_btn_ctrl_all(bmx_calendar->obj, LV_BTNMATRIX_CTRL_CHECKABLE | LV_BTNMATRIX_CTRL_RECOLOR);