Refactor chore tracker configuration for improved consistency and clarity
This commit is contained in:
@@ -4,19 +4,30 @@
|
|||||||
#
|
#
|
||||||
# HOME SCREEN BEHAVIOUR:
|
# HOME SCREEN BEHAVIOUR:
|
||||||
# Red outline = chores incomplete
|
# Red outline = chores incomplete
|
||||||
# Solid green = all chores done ✓
|
# Solid green = all chores done
|
||||||
# Resets to red automatically at midnight
|
# Resets to red automatically at midnight
|
||||||
|
#
|
||||||
|
# Hardware: Waveshare ESP32-S3-Touch-LCD-7 (800x480)
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
esphome:
|
esphome:
|
||||||
name: chore-tracker
|
name: chore-tracker
|
||||||
friendly_name: "Chore Tracker"
|
friendly_name: "Chore Tracker"
|
||||||
|
on_boot:
|
||||||
|
priority: -10
|
||||||
|
then:
|
||||||
|
- light.turn_on: backlight
|
||||||
|
- lvgl.page.show: page_home
|
||||||
|
|
||||||
esp32:
|
esp32:
|
||||||
board: esp32-s3-devkitc-1
|
board: esp32-s3-devkitc-1
|
||||||
framework:
|
framework:
|
||||||
type: esp-idf
|
type: esp-idf
|
||||||
|
|
||||||
|
psram:
|
||||||
|
mode: octal
|
||||||
|
speed: 80MHz
|
||||||
|
|
||||||
wifi:
|
wifi:
|
||||||
ssid: !secret wifi_iot_ssid
|
ssid: !secret wifi_iot_ssid
|
||||||
password: !secret wifi_password
|
password: !secret wifi_password
|
||||||
@@ -36,50 +47,58 @@ ota:
|
|||||||
- platform: esphome
|
- platform: esphome
|
||||||
password: !secret ota_password
|
password: !secret ota_password
|
||||||
|
|
||||||
# ── Display — Waveshare ESP32-S3 7" (adjust pins for your board revision) ─────
|
# ── I2C ───────────────────────────────────────────────────────────────────────
|
||||||
display:
|
|
||||||
- platform: rpi_dpi_rgb
|
|
||||||
id: main_display
|
|
||||||
auto_clear_enabled: false
|
|
||||||
color_order: RGB
|
|
||||||
dimensions:
|
|
||||||
width: 800
|
|
||||||
height: 480
|
|
||||||
de_pin: GPIO40
|
|
||||||
hsync_pin: GPIO39
|
|
||||||
vsync_pin:
|
|
||||||
number: GPIO41
|
|
||||||
pclk_pin: GPIO42
|
|
||||||
data_pins:
|
|
||||||
red: [GPIO45, GPIO48, GPIO47, GPIO21, GPIO14]
|
|
||||||
green: [GPIO5, GPIO6, GPIO7, GPIO15, GPIO16, GPIO4]
|
|
||||||
blue: [GPIO8, GPIO3, GPIO46, GPIO9, GPIO1]
|
|
||||||
|
|
||||||
touchscreen:
|
|
||||||
- platform: gt911
|
|
||||||
id: touch
|
|
||||||
display: main_display
|
|
||||||
i2c_id: i2c_touch
|
|
||||||
interrupt_pin: GPIO2
|
|
||||||
reset_pin: GPIO38
|
|
||||||
|
|
||||||
i2c:
|
i2c:
|
||||||
- id: i2c_touch
|
sda: 8
|
||||||
sda: GPIO19
|
scl: 9
|
||||||
scl: GPIO20
|
|
||||||
frequency: 400kHz
|
|
||||||
|
|
||||||
|
# ── CH422G IO Expander (controls LCD reset, touch reset, backlight) ───────────
|
||||||
|
ch422g:
|
||||||
|
- id: ch422g_hub
|
||||||
|
|
||||||
|
# ── Display ───────────────────────────────────────────────────────────────────
|
||||||
|
display:
|
||||||
|
- platform: mipi_rgb
|
||||||
|
model: ESP32-S3-TOUCH-LCD-7-800X480
|
||||||
|
id: main_display
|
||||||
|
update_interval: never
|
||||||
|
auto_clear_enabled: false
|
||||||
|
reset_pin:
|
||||||
|
ch422g: ch422g_hub
|
||||||
|
number: 3
|
||||||
|
mode:
|
||||||
|
output: true
|
||||||
|
|
||||||
|
# ── Touchscreen ───────────────────────────────────────────────────────────────
|
||||||
|
touchscreen:
|
||||||
|
platform: gt911
|
||||||
|
id: touch
|
||||||
|
update_interval: 120ms
|
||||||
|
reset_pin:
|
||||||
|
ch422g: ch422g_hub
|
||||||
|
number: 1
|
||||||
|
mode:
|
||||||
|
output: true
|
||||||
|
|
||||||
|
# ── Backlight ─────────────────────────────────────────────────────────────────
|
||||||
output:
|
output:
|
||||||
- platform: ledc
|
- platform: template
|
||||||
pin: GPIO17
|
id: lcd_backlight_out
|
||||||
id: backlight_output
|
type: binary
|
||||||
|
write_action:
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: return state;
|
||||||
|
then:
|
||||||
|
- switch.turn_on: lcd_backlight_raw
|
||||||
|
else:
|
||||||
|
- switch.turn_off: lcd_backlight_raw
|
||||||
|
|
||||||
light:
|
light:
|
||||||
- platform: monochromatic
|
- platform: binary
|
||||||
output: backlight_output
|
|
||||||
name: "Display Backlight"
|
name: "Display Backlight"
|
||||||
|
output: lcd_backlight_out
|
||||||
id: backlight
|
id: backlight
|
||||||
restore_mode: ALWAYS_ON
|
|
||||||
|
|
||||||
# ── Midnight reset ────────────────────────────────────────────────────────────
|
# ── Midnight reset ────────────────────────────────────────────────────────────
|
||||||
time:
|
time:
|
||||||
@@ -96,6 +115,7 @@ time:
|
|||||||
id(reset_chloe_chores).execute();
|
id(reset_chloe_chores).execute();
|
||||||
- lvgl.page.show: page_home
|
- lvgl.page.show: page_home
|
||||||
|
|
||||||
|
# ── Fonts (place files in /config/esphome/fonts/) ────────────────────────────
|
||||||
font:
|
font:
|
||||||
- file: "fonts/Nunito-Black.ttf"
|
- file: "fonts/Nunito-Black.ttf"
|
||||||
id: font_title
|
id: font_title
|
||||||
@@ -113,8 +133,17 @@ font:
|
|||||||
id: font_tiny
|
id: font_tiny
|
||||||
size: 13
|
size: 13
|
||||||
|
|
||||||
# ── Switches — one per chore per kid, synced to HA ───────────────────────────
|
# ── Switches — backlight raw + one per chore per kid ─────────────────────────
|
||||||
switch:
|
switch:
|
||||||
|
- platform: gpio
|
||||||
|
id: lcd_backlight_raw
|
||||||
|
name: "LCD Backlight Raw"
|
||||||
|
restore_mode: ALWAYS_ON
|
||||||
|
pin:
|
||||||
|
ch422g: ch422g_hub
|
||||||
|
number: 2
|
||||||
|
mode:
|
||||||
|
output: true
|
||||||
|
|
||||||
# ── Jordyn's chores ──────────────────────────
|
# ── Jordyn's chores ──────────────────────────
|
||||||
- platform: template
|
- platform: template
|
||||||
@@ -497,9 +526,9 @@ script:
|
|||||||
lv_label_set_text(id(progress_label_jordyn), buf);
|
lv_label_set_text(id(progress_label_jordyn), buf);
|
||||||
|
|
||||||
// All-done message in sidebar
|
// All-done message in sidebar
|
||||||
lv_label_set_text(id(all_done_label_jordyn), done == total ? "\U0001F389 All done!" : "");
|
lv_label_set_text(id(all_done_label_jordyn), done == total ? "All done!" : "");
|
||||||
|
|
||||||
// Home button colour
|
// Home button: RED outline = incomplete, SOLID GREEN = all done
|
||||||
if (done == total) {
|
if (done == total) {
|
||||||
lv_obj_set_style_bg_opa(id(home_btn_jordyn), LV_OPA_COVER, LV_PART_MAIN);
|
lv_obj_set_style_bg_opa(id(home_btn_jordyn), LV_OPA_COVER, LV_PART_MAIN);
|
||||||
lv_obj_set_style_bg_color(id(home_btn_jordyn), lv_color_hex(0x6BCB77), LV_PART_MAIN);
|
lv_obj_set_style_bg_color(id(home_btn_jordyn), lv_color_hex(0x6BCB77), LV_PART_MAIN);
|
||||||
@@ -598,9 +627,9 @@ script:
|
|||||||
lv_label_set_text(id(progress_label_declan), buf);
|
lv_label_set_text(id(progress_label_declan), buf);
|
||||||
|
|
||||||
// All-done message in sidebar
|
// All-done message in sidebar
|
||||||
lv_label_set_text(id(all_done_label_declan), done == total ? "\U0001F389 All done!" : "");
|
lv_label_set_text(id(all_done_label_declan), done == total ? "All done!" : "");
|
||||||
|
|
||||||
// Home button colour
|
// Home button: RED outline = incomplete, SOLID GREEN = all done
|
||||||
if (done == total) {
|
if (done == total) {
|
||||||
lv_obj_set_style_bg_opa(id(home_btn_declan), LV_OPA_COVER, LV_PART_MAIN);
|
lv_obj_set_style_bg_opa(id(home_btn_declan), LV_OPA_COVER, LV_PART_MAIN);
|
||||||
lv_obj_set_style_bg_color(id(home_btn_declan), lv_color_hex(0x6BCB77), LV_PART_MAIN);
|
lv_obj_set_style_bg_color(id(home_btn_declan), lv_color_hex(0x6BCB77), LV_PART_MAIN);
|
||||||
@@ -690,9 +719,9 @@ script:
|
|||||||
lv_label_set_text(id(progress_label_chloe), buf);
|
lv_label_set_text(id(progress_label_chloe), buf);
|
||||||
|
|
||||||
// All-done message in sidebar
|
// All-done message in sidebar
|
||||||
lv_label_set_text(id(all_done_label_chloe), done == total ? "\U0001F389 All done!" : "");
|
lv_label_set_text(id(all_done_label_chloe), done == total ? "All done!" : "");
|
||||||
|
|
||||||
// Home button colour
|
// Home button: RED outline = incomplete, SOLID GREEN = all done
|
||||||
if (done == total) {
|
if (done == total) {
|
||||||
lv_obj_set_style_bg_opa(id(home_btn_chloe), LV_OPA_COVER, LV_PART_MAIN);
|
lv_obj_set_style_bg_opa(id(home_btn_chloe), LV_OPA_COVER, LV_PART_MAIN);
|
||||||
lv_obj_set_style_bg_color(id(home_btn_chloe), lv_color_hex(0x6BCB77), LV_PART_MAIN);
|
lv_obj_set_style_bg_color(id(home_btn_chloe), lv_color_hex(0x6BCB77), LV_PART_MAIN);
|
||||||
@@ -823,7 +852,7 @@ lvgl:
|
|||||||
widgets:
|
widgets:
|
||||||
- label:
|
- label:
|
||||||
align: CENTER
|
align: CENTER
|
||||||
text: "↺ Reset All"
|
text: "Reset All"
|
||||||
text_color: 0xFFFFFF
|
text_color: 0xFFFFFF
|
||||||
text_font: font_tiny
|
text_font: font_tiny
|
||||||
- button:
|
- button:
|
||||||
@@ -1002,7 +1031,7 @@ lvgl:
|
|||||||
widgets:
|
widgets:
|
||||||
- label:
|
- label:
|
||||||
align: CENTER
|
align: CENTER
|
||||||
text: "↺ Reset"
|
text: "Reset"
|
||||||
text_color: 0xFFFFFF
|
text_color: 0xFFFFFF
|
||||||
text_font: font_small
|
text_font: font_small
|
||||||
- button:
|
- button:
|
||||||
@@ -1018,7 +1047,7 @@ lvgl:
|
|||||||
widgets:
|
widgets:
|
||||||
- label:
|
- label:
|
||||||
align: CENTER
|
align: CENTER
|
||||||
text: "◀ Home"
|
text: "Home"
|
||||||
text_color: 0xFFFFFF
|
text_color: 0xFFFFFF
|
||||||
text_font: font_small
|
text_font: font_small
|
||||||
|
|
||||||
@@ -1277,7 +1306,7 @@ lvgl:
|
|||||||
widgets:
|
widgets:
|
||||||
- label:
|
- label:
|
||||||
align: CENTER
|
align: CENTER
|
||||||
text: "↺ Reset"
|
text: "Reset"
|
||||||
text_color: 0xFFFFFF
|
text_color: 0xFFFFFF
|
||||||
text_font: font_small
|
text_font: font_small
|
||||||
- button:
|
- button:
|
||||||
@@ -1293,7 +1322,7 @@ lvgl:
|
|||||||
widgets:
|
widgets:
|
||||||
- label:
|
- label:
|
||||||
align: CENTER
|
align: CENTER
|
||||||
text: "◀ Home"
|
text: "Home"
|
||||||
text_color: 0xFFFFFF
|
text_color: 0xFFFFFF
|
||||||
text_font: font_small
|
text_font: font_small
|
||||||
|
|
||||||
@@ -1516,7 +1545,7 @@ lvgl:
|
|||||||
widgets:
|
widgets:
|
||||||
- label:
|
- label:
|
||||||
align: CENTER
|
align: CENTER
|
||||||
text: "↺ Reset"
|
text: "Reset"
|
||||||
text_color: 0xFFFFFF
|
text_color: 0xFFFFFF
|
||||||
text_font: font_small
|
text_font: font_small
|
||||||
- button:
|
- button:
|
||||||
@@ -1532,7 +1561,7 @@ lvgl:
|
|||||||
widgets:
|
widgets:
|
||||||
- label:
|
- label:
|
||||||
align: CENTER
|
align: CENTER
|
||||||
text: "◀ Home"
|
text: "Home"
|
||||||
text_color: 0xFFFFFF
|
text_color: 0xFFFFFF
|
||||||
text_font: font_small
|
text_font: font_small
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ views:
|
|||||||
content: >
|
content: >
|
||||||
### 😺 Jordyn
|
### 😺 Jordyn
|
||||||
{{
|
{{
|
||||||
'✅ All done!' if states('sensor.jordyn_all_chores_done') == 'True'
|
'All done!' if states('sensor.jordyn_all_chores_done') == 'True'
|
||||||
else states('sensor.jordyn_chores_done_today') ~ '/5 chores done'
|
else states('sensor.jordyn_chores_done_today') ~ '/5 chores done'
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ views:
|
|||||||
content: >
|
content: >
|
||||||
### 🤓 Declan
|
### 🤓 Declan
|
||||||
{{
|
{{
|
||||||
'✅ All done!' if states('sensor.declan_all_chores_done') == 'True'
|
'All done!' if states('sensor.declan_all_chores_done') == 'True'
|
||||||
else states('sensor.declan_chores_done_today') ~ '/4 chores done'
|
else states('sensor.declan_chores_done_today') ~ '/4 chores done'
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@@ -31,12 +31,12 @@ views:
|
|||||||
content: >
|
content: >
|
||||||
### 🌝 Chloe
|
### 🌝 Chloe
|
||||||
{{
|
{{
|
||||||
'✅ All done!' if states('sensor.chloe_all_chores_done') == 'True'
|
'All done!' if states('sensor.chloe_all_chores_done') == 'True'
|
||||||
else states('sensor.chloe_chores_done_today') ~ '/6 chores done'
|
else states('sensor.chloe_chores_done_today') ~ '/6 chores done'
|
||||||
}}
|
}}
|
||||||
|
|
||||||
- type: button
|
- type: button
|
||||||
name: "↺ Reset ALL Chores"
|
name: "Reset ALL Chores"
|
||||||
icon: mdi:restart-alert
|
icon: mdi:restart-alert
|
||||||
tap_action:
|
tap_action:
|
||||||
action: call-service
|
action: call-service
|
||||||
@@ -64,9 +64,9 @@ views:
|
|||||||
- entity: sensor.jordyn_chores_done_today
|
- entity: sensor.jordyn_chores_done_today
|
||||||
name: "Chores done today"
|
name: "Chores done today"
|
||||||
- entity: sensor.jordyn_all_chores_done
|
- entity: sensor.jordyn_all_chores_done
|
||||||
name: "✅ All Done?"
|
name: "All Done?"
|
||||||
- type: button
|
- type: button
|
||||||
name: "↺ Reset Jordyn's Chores"
|
name: "Reset Jordyn's Chores"
|
||||||
tap_action:
|
tap_action:
|
||||||
action: call-service
|
action: call-service
|
||||||
service: input_button.press
|
service: input_button.press
|
||||||
@@ -90,9 +90,9 @@ views:
|
|||||||
- entity: sensor.declan_chores_done_today
|
- entity: sensor.declan_chores_done_today
|
||||||
name: "Chores done today"
|
name: "Chores done today"
|
||||||
- entity: sensor.declan_all_chores_done
|
- entity: sensor.declan_all_chores_done
|
||||||
name: "✅ All Done?"
|
name: "All Done?"
|
||||||
- type: button
|
- type: button
|
||||||
name: "↺ Reset Declan's Chores"
|
name: "Reset Declan's Chores"
|
||||||
tap_action:
|
tap_action:
|
||||||
action: call-service
|
action: call-service
|
||||||
service: input_button.press
|
service: input_button.press
|
||||||
@@ -122,9 +122,9 @@ views:
|
|||||||
- entity: sensor.chloe_chores_done_today
|
- entity: sensor.chloe_chores_done_today
|
||||||
name: "Chores done today"
|
name: "Chores done today"
|
||||||
- entity: sensor.chloe_all_chores_done
|
- entity: sensor.chloe_all_chores_done
|
||||||
name: "✅ All Done?"
|
name: "All Done?"
|
||||||
- type: button
|
- type: button
|
||||||
name: "↺ Reset Chloe's Chores"
|
name: "Reset Chloe's Chores"
|
||||||
tap_action:
|
tap_action:
|
||||||
action: call-service
|
action: call-service
|
||||||
service: input_button.press
|
service: input_button.press
|
||||||
|
|||||||
@@ -7,12 +7,14 @@ Reads chores_config.yaml and generates:
|
|||||||
• chore-tracker-ha.yaml (Home Assistant config)
|
• chore-tracker-ha.yaml (Home Assistant config)
|
||||||
• chore-tracker-dashboard.yaml (Lovelace dashboard)
|
• chore-tracker-dashboard.yaml (Lovelace dashboard)
|
||||||
|
|
||||||
|
Target hardware: Waveshare ESP32-S3-Touch-LCD-7 (800x480)
|
||||||
|
|
||||||
Home screen behaviour:
|
Home screen behaviour:
|
||||||
- Each kid's button has a RED outline while any chores remain undone
|
- Each kid's button has a RED outline while any chores remain undone
|
||||||
- Button turns SOLID GREEN when ALL chores are complete
|
- Button turns SOLID GREEN when ALL chores are complete
|
||||||
- Resets to red automatically at midnight
|
- Resets to red automatically at midnight
|
||||||
|
|
||||||
No star tracking — chores are simply done or not done.
|
Each kid must define their own chores list in chores_config.yaml.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
python3 generate.py
|
python3 generate.py
|
||||||
@@ -48,7 +50,6 @@ def ha_switch(kid: dict, chore: dict) -> str:
|
|||||||
return f"switch.chore_tracker_{eid(kid, chore)}"
|
return f"switch.chore_tracker_{eid(kid, chore)}"
|
||||||
|
|
||||||
def get_chores(kid: dict) -> list:
|
def get_chores(kid: dict) -> list:
|
||||||
"""Each kid must define their own chore list."""
|
|
||||||
return kid["chores"]
|
return kid["chores"]
|
||||||
|
|
||||||
|
|
||||||
@@ -57,10 +58,10 @@ def get_chores(kid: dict) -> list:
|
|||||||
# ─────────────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
def gen_esphome(cfg: dict) -> str:
|
def gen_esphome(cfg: dict) -> str:
|
||||||
s = cfg["settings"]
|
s = cfg["settings"]
|
||||||
kids = cfg["kids"]
|
kids = cfg["kids"]
|
||||||
|
|
||||||
# ── Switches ──────────────────────────────────────────────────────────────
|
# ── Switches (one per chore per kid) ──────────────────────────────────────
|
||||||
switch_blocks = []
|
switch_blocks = []
|
||||||
for kid in kids:
|
for kid in kids:
|
||||||
chores = get_chores(kid)
|
chores = get_chores(kid)
|
||||||
@@ -91,7 +92,7 @@ def gen_esphome(cfg: dict) -> str:
|
|||||||
entity_id: switch.chore_tracker_{e}
|
entity_id: switch.chore_tracker_{e}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
# ── Sensors (chores-done count only) ──────────────────────────────────────
|
# ── Sensors (chores-done count only — no stars) ────────────────────────
|
||||||
sensor_blocks = []
|
sensor_blocks = []
|
||||||
for kid in kids:
|
for kid in kids:
|
||||||
chores = get_chores(kid)
|
chores = get_chores(kid)
|
||||||
@@ -112,7 +113,7 @@ def gen_esphome(cfg: dict) -> str:
|
|||||||
|
|
||||||
""")
|
""")
|
||||||
|
|
||||||
# ── Midnight reset ────────────────────────────────────────────────────────
|
# ── Midnight reset calls ──────────────────────────────────────────────────
|
||||||
reset_calls = "\n".join(
|
reset_calls = "\n".join(
|
||||||
f" id(reset_{kid_slug(k)}_chores).execute();"
|
f" id(reset_{kid_slug(k)}_chores).execute();"
|
||||||
for k in kids
|
for k in kids
|
||||||
@@ -128,19 +129,30 @@ def gen_esphome(cfg: dict) -> str:
|
|||||||
#
|
#
|
||||||
# HOME SCREEN BEHAVIOUR:
|
# HOME SCREEN BEHAVIOUR:
|
||||||
# Red outline = chores incomplete
|
# Red outline = chores incomplete
|
||||||
# Solid green = all chores done ✓
|
# Solid green = all chores done
|
||||||
# Resets to red automatically at midnight
|
# Resets to red automatically at midnight
|
||||||
|
#
|
||||||
|
# Hardware: Waveshare ESP32-S3-Touch-LCD-7 (800x480)
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
esphome:
|
esphome:
|
||||||
name: {s["device_name"]}
|
name: {s["device_name"]}
|
||||||
friendly_name: "{s["friendly_name"]}"
|
friendly_name: "{s["friendly_name"]}"
|
||||||
|
on_boot:
|
||||||
|
priority: -10
|
||||||
|
then:
|
||||||
|
- light.turn_on: backlight
|
||||||
|
- lvgl.page.show: page_home
|
||||||
|
|
||||||
esp32:
|
esp32:
|
||||||
board: esp32-s3-devkitc-1
|
board: esp32-s3-devkitc-1
|
||||||
framework:
|
framework:
|
||||||
type: esp-idf
|
type: esp-idf
|
||||||
|
|
||||||
|
psram:
|
||||||
|
mode: octal
|
||||||
|
speed: 80MHz
|
||||||
|
|
||||||
wifi:
|
wifi:
|
||||||
ssid: {s["wifi_ssid"]}
|
ssid: {s["wifi_ssid"]}
|
||||||
password: {s["wifi_password"]}
|
password: {s["wifi_password"]}
|
||||||
@@ -160,50 +172,58 @@ ota:
|
|||||||
- platform: esphome
|
- platform: esphome
|
||||||
password: {s["ota_password"]}
|
password: {s["ota_password"]}
|
||||||
|
|
||||||
# ── Display — Waveshare ESP32-S3 7" (adjust pins for your board revision) ─────
|
# ── I2C ───────────────────────────────────────────────────────────────────────
|
||||||
display:
|
|
||||||
- platform: rpi_dpi_rgb
|
|
||||||
id: main_display
|
|
||||||
auto_clear_enabled: false
|
|
||||||
color_order: RGB
|
|
||||||
dimensions:
|
|
||||||
width: 800
|
|
||||||
height: 480
|
|
||||||
de_pin: GPIO40
|
|
||||||
hsync_pin: GPIO39
|
|
||||||
vsync_pin:
|
|
||||||
number: GPIO41
|
|
||||||
pclk_pin: GPIO42
|
|
||||||
data_pins:
|
|
||||||
red: [GPIO45, GPIO48, GPIO47, GPIO21, GPIO14]
|
|
||||||
green: [GPIO5, GPIO6, GPIO7, GPIO15, GPIO16, GPIO4]
|
|
||||||
blue: [GPIO8, GPIO3, GPIO46, GPIO9, GPIO1]
|
|
||||||
|
|
||||||
touchscreen:
|
|
||||||
- platform: gt911
|
|
||||||
id: touch
|
|
||||||
display: main_display
|
|
||||||
i2c_id: i2c_touch
|
|
||||||
interrupt_pin: GPIO2
|
|
||||||
reset_pin: GPIO38
|
|
||||||
|
|
||||||
i2c:
|
i2c:
|
||||||
- id: i2c_touch
|
sda: 8
|
||||||
sda: GPIO19
|
scl: 9
|
||||||
scl: GPIO20
|
|
||||||
frequency: 400kHz
|
|
||||||
|
|
||||||
|
# ── CH422G IO Expander (controls LCD reset, touch reset, backlight) ───────────
|
||||||
|
ch422g:
|
||||||
|
- id: ch422g_hub
|
||||||
|
|
||||||
|
# ── Display ───────────────────────────────────────────────────────────────────
|
||||||
|
display:
|
||||||
|
- platform: mipi_rgb
|
||||||
|
model: ESP32-S3-TOUCH-LCD-7-800X480
|
||||||
|
id: main_display
|
||||||
|
update_interval: never
|
||||||
|
auto_clear_enabled: false
|
||||||
|
reset_pin:
|
||||||
|
ch422g: ch422g_hub
|
||||||
|
number: 3
|
||||||
|
mode:
|
||||||
|
output: true
|
||||||
|
|
||||||
|
# ── Touchscreen ───────────────────────────────────────────────────────────────
|
||||||
|
touchscreen:
|
||||||
|
platform: gt911
|
||||||
|
id: touch
|
||||||
|
update_interval: 120ms
|
||||||
|
reset_pin:
|
||||||
|
ch422g: ch422g_hub
|
||||||
|
number: 1
|
||||||
|
mode:
|
||||||
|
output: true
|
||||||
|
|
||||||
|
# ── Backlight ─────────────────────────────────────────────────────────────────
|
||||||
output:
|
output:
|
||||||
- platform: ledc
|
- platform: template
|
||||||
pin: GPIO17
|
id: lcd_backlight_out
|
||||||
id: backlight_output
|
type: binary
|
||||||
|
write_action:
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: return state;
|
||||||
|
then:
|
||||||
|
- switch.turn_on: lcd_backlight_raw
|
||||||
|
else:
|
||||||
|
- switch.turn_off: lcd_backlight_raw
|
||||||
|
|
||||||
light:
|
light:
|
||||||
- platform: monochromatic
|
- platform: binary
|
||||||
output: backlight_output
|
|
||||||
name: "Display Backlight"
|
name: "Display Backlight"
|
||||||
|
output: lcd_backlight_out
|
||||||
id: backlight
|
id: backlight
|
||||||
restore_mode: ALWAYS_ON
|
|
||||||
|
|
||||||
# ── Midnight reset ────────────────────────────────────────────────────────────
|
# ── Midnight reset ────────────────────────────────────────────────────────────
|
||||||
time:
|
time:
|
||||||
@@ -218,6 +238,7 @@ time:
|
|||||||
{reset_calls}
|
{reset_calls}
|
||||||
- lvgl.page.show: page_home
|
- lvgl.page.show: page_home
|
||||||
|
|
||||||
|
# ── Fonts (place files in /config/esphome/fonts/) ────────────────────────────
|
||||||
font:
|
font:
|
||||||
- file: "fonts/Nunito-Black.ttf"
|
- file: "fonts/Nunito-Black.ttf"
|
||||||
id: font_title
|
id: font_title
|
||||||
@@ -235,8 +256,17 @@ font:
|
|||||||
id: font_tiny
|
id: font_tiny
|
||||||
size: 13
|
size: 13
|
||||||
|
|
||||||
# ── Switches — one per chore per kid, synced to HA ───────────────────────────
|
# ── Switches — backlight raw + one per chore per kid ─────────────────────────
|
||||||
switch:
|
switch:
|
||||||
|
- platform: gpio
|
||||||
|
id: lcd_backlight_raw
|
||||||
|
name: "LCD Backlight Raw"
|
||||||
|
restore_mode: ALWAYS_ON
|
||||||
|
pin:
|
||||||
|
ch422g: ch422g_hub
|
||||||
|
number: 2
|
||||||
|
mode:
|
||||||
|
output: true
|
||||||
{"".join(switch_blocks)}
|
{"".join(switch_blocks)}
|
||||||
|
|
||||||
# ── Sensors — reported to HA ─────────────────────────────────────────────────
|
# ── Sensors — reported to HA ─────────────────────────────────────────────────
|
||||||
@@ -270,8 +300,8 @@ def _gen_lvgl_pages(kids: list) -> str:
|
|||||||
pages = []
|
pages = []
|
||||||
|
|
||||||
# ── HOME PAGE ─────────────────────────────────────────────────────────────
|
# ── HOME PAGE ─────────────────────────────────────────────────────────────
|
||||||
n = len(kids)
|
n = len(kids)
|
||||||
btn_w = min(200, max(140, (760 - 20 * (n - 1)) // n))
|
btn_w = min(200, max(140, (760 - 20 * (n - 1)) // n))
|
||||||
total_w = btn_w * n + 20 * (n - 1)
|
total_w = btn_w * n + 20 * (n - 1)
|
||||||
start_x = (800 - total_w) // 2
|
start_x = (800 - total_w) // 2
|
||||||
btn_y = 130
|
btn_y = 130
|
||||||
@@ -356,7 +386,7 @@ def _gen_lvgl_pages(kids: list) -> str:
|
|||||||
widgets:
|
widgets:
|
||||||
- label:
|
- label:
|
||||||
align: CENTER
|
align: CENTER
|
||||||
text: "↺ Reset All"
|
text: "Reset All"
|
||||||
text_color: 0xFFFFFF
|
text_color: 0xFFFFFF
|
||||||
text_font: font_tiny
|
text_font: font_tiny
|
||||||
{home_btns}""")
|
{home_btns}""")
|
||||||
@@ -497,7 +527,7 @@ def _gen_lvgl_pages(kids: list) -> str:
|
|||||||
widgets:
|
widgets:
|
||||||
- label:
|
- label:
|
||||||
align: CENTER
|
align: CENTER
|
||||||
text: "↺ Reset"
|
text: "Reset"
|
||||||
text_color: 0xFFFFFF
|
text_color: 0xFFFFFF
|
||||||
text_font: font_small
|
text_font: font_small
|
||||||
- button:
|
- button:
|
||||||
@@ -513,7 +543,7 @@ def _gen_lvgl_pages(kids: list) -> str:
|
|||||||
widgets:
|
widgets:
|
||||||
- label:
|
- label:
|
||||||
align: CENTER
|
align: CENTER
|
||||||
text: "◀ Home"
|
text: "Home"
|
||||||
text_color: 0xFFFFFF
|
text_color: 0xFFFFFF
|
||||||
text_font: font_small
|
text_font: font_small
|
||||||
|
|
||||||
@@ -556,7 +586,6 @@ def _gen_scripts(kids: list) -> str:
|
|||||||
f" id({eid(kid,c)}).turn_off();" for c in chores
|
f" id({eid(kid,c)}).turn_off();" for c in chores
|
||||||
)
|
)
|
||||||
|
|
||||||
# Reset script
|
|
||||||
blocks.append(f"""\
|
blocks.append(f"""\
|
||||||
- id: reset_{ks}_chores
|
- id: reset_{ks}_chores
|
||||||
mode: single
|
mode: single
|
||||||
@@ -567,7 +596,6 @@ def _gen_scripts(kids: list) -> str:
|
|||||||
|
|
||||||
""")
|
""")
|
||||||
|
|
||||||
# UI update script
|
|
||||||
blocks.append(f"""\
|
blocks.append(f"""\
|
||||||
- id: update_{ks}_ui
|
- id: update_{ks}_ui
|
||||||
mode: single
|
mode: single
|
||||||
@@ -583,9 +611,9 @@ def _gen_scripts(kids: list) -> str:
|
|||||||
lv_label_set_text(id(progress_label_{ks}), buf);
|
lv_label_set_text(id(progress_label_{ks}), buf);
|
||||||
|
|
||||||
// All-done message in sidebar
|
// All-done message in sidebar
|
||||||
lv_label_set_text(id(all_done_label_{ks}), done == total ? "\\U0001F389 All done!" : "");
|
lv_label_set_text(id(all_done_label_{ks}), done == total ? "All done!" : "");
|
||||||
|
|
||||||
// Home button colour
|
// Home button: RED outline = incomplete, SOLID GREEN = all done
|
||||||
if (done == total) {{
|
if (done == total) {{
|
||||||
lv_obj_set_style_bg_opa(id(home_btn_{ks}), LV_OPA_COVER, LV_PART_MAIN);
|
lv_obj_set_style_bg_opa(id(home_btn_{ks}), LV_OPA_COVER, LV_PART_MAIN);
|
||||||
lv_obj_set_style_bg_color(id(home_btn_{ks}), lv_color_hex(0x6BCB77), LV_PART_MAIN);
|
lv_obj_set_style_bg_color(id(home_btn_{ks}), lv_color_hex(0x6BCB77), LV_PART_MAIN);
|
||||||
@@ -613,7 +641,7 @@ def _gen_scripts(kids: list) -> str:
|
|||||||
# ─────────────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
def gen_ha(cfg: dict) -> str:
|
def gen_ha(cfg: dict) -> str:
|
||||||
s = cfg["settings"]
|
s = cfg["settings"]
|
||||||
kids = cfg["kids"]
|
kids = cfg["kids"]
|
||||||
|
|
||||||
sensor_blocks = []
|
sensor_blocks = []
|
||||||
@@ -639,7 +667,6 @@ def gen_ha(cfg: dict) -> str:
|
|||||||
|
|
||||||
""")
|
""")
|
||||||
|
|
||||||
# input_button helpers
|
|
||||||
input_buttons = "".join(f"""\
|
input_buttons = "".join(f"""\
|
||||||
{kid_slug(k)}_reset_chores:
|
{kid_slug(k)}_reset_chores:
|
||||||
name: "Reset {k['name']}'s Chores"
|
name: "Reset {k['name']}'s Chores"
|
||||||
@@ -651,10 +678,8 @@ def gen_ha(cfg: dict) -> str:
|
|||||||
icon: mdi:restart-alert
|
icon: mdi:restart-alert
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Automations
|
|
||||||
auto_blocks = []
|
auto_blocks = []
|
||||||
|
|
||||||
# Per-kid HA reset button
|
|
||||||
for kid in kids:
|
for kid in kids:
|
||||||
ks = kid_slug(kid)
|
ks = kid_slug(kid)
|
||||||
off_calls = "\n".join(
|
off_calls = "\n".join(
|
||||||
@@ -663,7 +688,7 @@ def gen_ha(cfg: dict) -> str:
|
|||||||
)
|
)
|
||||||
auto_blocks.append(f"""\
|
auto_blocks.append(f"""\
|
||||||
- id: {ks}_reset_from_ha
|
- id: {ks}_reset_from_ha
|
||||||
alias: "Chore Tracker — Reset {kid['name']}'s chores from HA"
|
alias: "Chore Tracker - Reset {kid['name']}'s chores from HA"
|
||||||
trigger:
|
trigger:
|
||||||
- platform: state
|
- platform: state
|
||||||
entity_id: input_button.{ks}_reset_chores
|
entity_id: input_button.{ks}_reset_chores
|
||||||
@@ -672,29 +697,27 @@ def gen_ha(cfg: dict) -> str:
|
|||||||
|
|
||||||
""")
|
""")
|
||||||
|
|
||||||
# Reset All from HA
|
all_off = "\n".join(
|
||||||
all_off_calls = "\n".join(
|
|
||||||
f" - service: switch.turn_off\n target:\n entity_id: {ha_switch(kid, c)}"
|
f" - service: switch.turn_off\n target:\n entity_id: {ha_switch(kid, c)}"
|
||||||
for kid in kids for c in get_chores(kid)
|
for kid in kids for c in get_chores(kid)
|
||||||
)
|
)
|
||||||
auto_blocks.append(f"""\
|
auto_blocks.append(f"""\
|
||||||
- id: reset_all_from_ha
|
- id: reset_all_from_ha
|
||||||
alias: "Chore Tracker — Reset ALL chores from HA"
|
alias: "Chore Tracker - Reset ALL chores from HA"
|
||||||
trigger:
|
trigger:
|
||||||
- platform: state
|
- platform: state
|
||||||
entity_id: input_button.reset_all_chores
|
entity_id: input_button.reset_all_chores
|
||||||
action:
|
action:
|
||||||
{all_off_calls}
|
{all_off}
|
||||||
|
|
||||||
""")
|
""")
|
||||||
|
|
||||||
# All-done notification
|
|
||||||
for kid in kids:
|
for kid in kids:
|
||||||
ks = kid_slug(kid)
|
ks = kid_slug(kid)
|
||||||
n = len(get_chores(kid))
|
n = len(get_chores(kid))
|
||||||
auto_blocks.append(f"""\
|
auto_blocks.append(f"""\
|
||||||
- id: {ks}_all_done_notify
|
- id: {ks}_all_done_notify
|
||||||
alias: "Chore Tracker — {kid['name']} all done!"
|
alias: "Chore Tracker - {kid['name']} all done!"
|
||||||
trigger:
|
trigger:
|
||||||
- platform: state
|
- platform: state
|
||||||
entity_id: sensor.{ks}_all_chores_done
|
entity_id: sensor.{ks}_all_chores_done
|
||||||
@@ -702,12 +725,11 @@ def gen_ha(cfg: dict) -> str:
|
|||||||
action:
|
action:
|
||||||
- service: {s['notify_service']}
|
- service: {s['notify_service']}
|
||||||
data:
|
data:
|
||||||
title: "🎉 {kid['name']} finished all chores!"
|
title: "{kid['name']} finished all chores!"
|
||||||
message: "{kid['name']} completed all {n} chores today!"
|
message: "{kid['name']} completed all {n} chores today!"
|
||||||
|
|
||||||
""")
|
""")
|
||||||
|
|
||||||
# Evening reminder
|
|
||||||
reminder_actions = "".join(f"""\
|
reminder_actions = "".join(f"""\
|
||||||
- if:
|
- if:
|
||||||
condition: template
|
condition: template
|
||||||
@@ -715,7 +737,7 @@ def gen_ha(cfg: dict) -> str:
|
|||||||
then:
|
then:
|
||||||
- service: {s['notify_service']}
|
- service: {s['notify_service']}
|
||||||
data:
|
data:
|
||||||
title: "📋 {k['name']} has unfinished chores"
|
title: "{k['name']} has unfinished chores"
|
||||||
message: >
|
message: >
|
||||||
{k['name']} has done
|
{k['name']} has done
|
||||||
{{{{ states('sensor.{kid_slug(k)}_chores_done_today') }}}}/{len(get_chores(k))} chores today.
|
{{{{ states('sensor.{kid_slug(k)}_chores_done_today') }}}}/{len(get_chores(k))} chores today.
|
||||||
@@ -723,7 +745,7 @@ def gen_ha(cfg: dict) -> str:
|
|||||||
|
|
||||||
auto_blocks.append(f"""\
|
auto_blocks.append(f"""\
|
||||||
- id: chore_reminder_evening
|
- id: chore_reminder_evening
|
||||||
alias: "Chore Tracker — Evening reminder"
|
alias: "Chore Tracker - Evening reminder"
|
||||||
trigger:
|
trigger:
|
||||||
- platform: time
|
- platform: time
|
||||||
at: "{s['reminder_time']}:00"
|
at: "{s['reminder_time']}:00"
|
||||||
@@ -737,8 +759,8 @@ def gen_ha(cfg: dict) -> str:
|
|||||||
# Kids: {", ".join(k["name"] for k in kids)}
|
# Kids: {", ".join(k["name"] for k in kids)}
|
||||||
#
|
#
|
||||||
# BIDIRECTIONAL SYNC:
|
# BIDIRECTIONAL SYNC:
|
||||||
# Screen → HA: Each switch calls homeassistant.service on toggle
|
# Screen to HA: Each switch calls homeassistant.service on toggle
|
||||||
# HA → Screen: ESPHome native API handles this automatically
|
# HA to Screen: ESPHome native API handles this automatically
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
input_button:
|
input_button:
|
||||||
@@ -763,7 +785,7 @@ def gen_dashboard(cfg: dict) -> str:
|
|||||||
content: >
|
content: >
|
||||||
### {kid['avatar']} {kid['name']}
|
### {kid['avatar']} {kid['name']}
|
||||||
{{{{
|
{{{{
|
||||||
'✅ All done!' if states('sensor.{kid_slug(kid)}_all_chores_done') == 'True'
|
'All done!' if states('sensor.{kid_slug(kid)}_all_chores_done') == 'True'
|
||||||
else states('sensor.{kid_slug(kid)}_chores_done_today') ~ '/{len(get_chores(kid))} chores done'
|
else states('sensor.{kid_slug(kid)}_chores_done_today') ~ '/{len(get_chores(kid))} chores done'
|
||||||
}}}}
|
}}}}
|
||||||
""" for kid in kids)
|
""" for kid in kids)
|
||||||
@@ -785,9 +807,9 @@ def gen_dashboard(cfg: dict) -> str:
|
|||||||
- entity: sensor.{ks}_chores_done_today
|
- entity: sensor.{ks}_chores_done_today
|
||||||
name: "Chores done today"
|
name: "Chores done today"
|
||||||
- entity: sensor.{ks}_all_chores_done
|
- entity: sensor.{ks}_all_chores_done
|
||||||
name: "✅ All Done?"
|
name: "All Done?"
|
||||||
- type: button
|
- type: button
|
||||||
name: "↺ Reset {kid['name']}'s Chores"
|
name: "Reset {kid['name']}'s Chores"
|
||||||
tap_action:
|
tap_action:
|
||||||
action: call-service
|
action: call-service
|
||||||
service: input_button.press
|
service: input_button.press
|
||||||
@@ -811,7 +833,7 @@ views:
|
|||||||
cards:
|
cards:
|
||||||
{summary_cards}
|
{summary_cards}
|
||||||
- type: button
|
- type: button
|
||||||
name: "↺ Reset ALL Chores"
|
name: "Reset ALL Chores"
|
||||||
icon: mdi:restart-alert
|
icon: mdi:restart-alert
|
||||||
tap_action:
|
tap_action:
|
||||||
action: call-service
|
action: call-service
|
||||||
@@ -855,7 +877,6 @@ def main():
|
|||||||
print("❌ No kids defined in config!")
|
print("❌ No kids defined in config!")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Validate every kid has their own chore list
|
|
||||||
errors = [k["name"] for k in kids if "chores" not in k or not k["chores"]]
|
errors = [k["name"] for k in kids if "chores" not in k or not k["chores"]]
|
||||||
if errors:
|
if errors:
|
||||||
print(f"❌ These kids have no chores defined: {', '.join(errors)}")
|
print(f"❌ These kids have no chores defined: {', '.join(errors)}")
|
||||||
@@ -866,7 +887,8 @@ def main():
|
|||||||
print(f"✅ Config loaded: {len(kids)} kid(s), {total_chores} total chores")
|
print(f"✅ Config loaded: {len(kids)} kid(s), {total_chores} total chores")
|
||||||
for k in kids:
|
for k in kids:
|
||||||
chores = get_chores(k)
|
chores = get_chores(k)
|
||||||
print(f" {k['avatar']} {k['name']}: {len(chores)} chores — {', '.join(c['name'] for c in chores)}")
|
print(f" {k['avatar']} {k['name']}: {len(chores)} chores"
|
||||||
|
f" — {', '.join(c['name'] for c in chores)}")
|
||||||
print()
|
print()
|
||||||
|
|
||||||
files = {
|
files = {
|
||||||
@@ -882,9 +904,9 @@ def main():
|
|||||||
|
|
||||||
print()
|
print()
|
||||||
print("✅ Done!")
|
print("✅ Done!")
|
||||||
print(" 1. Flash chore-tracker-esphome.yaml → ESPHome dashboard")
|
print(" 1. Flash chore-tracker-esphome.yaml -> ESPHome dashboard")
|
||||||
print(" 2. Merge chore-tracker-ha.yaml → HA config + restart HA")
|
print(" 2. Merge chore-tracker-ha.yaml -> HA config + restart HA")
|
||||||
print(" 3. Paste chore-tracker-dashboard.yaml → New HA dashboard")
|
print(" 3. Paste chore-tracker-dashboard.yaml -> New HA dashboard")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
# Kids: Jordyn, Declan, Chloe
|
# Kids: Jordyn, Declan, Chloe
|
||||||
#
|
#
|
||||||
# BIDIRECTIONAL SYNC:
|
# BIDIRECTIONAL SYNC:
|
||||||
# Screen → HA: Each switch calls homeassistant.service on toggle
|
# Screen to HA: Each switch calls homeassistant.service on toggle
|
||||||
# HA → Screen: ESPHome native API handles this automatically
|
# HA to Screen: ESPHome native API handles this automatically
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
input_button:
|
input_button:
|
||||||
@@ -65,7 +65,7 @@ template:
|
|||||||
|
|
||||||
automation:
|
automation:
|
||||||
- id: jordyn_reset_from_ha
|
- id: jordyn_reset_from_ha
|
||||||
alias: "Chore Tracker — Reset Jordyn's chores from HA"
|
alias: "Chore Tracker - Reset Jordyn's chores from HA"
|
||||||
trigger:
|
trigger:
|
||||||
- platform: state
|
- platform: state
|
||||||
entity_id: input_button.jordyn_reset_chores
|
entity_id: input_button.jordyn_reset_chores
|
||||||
@@ -87,7 +87,7 @@ automation:
|
|||||||
entity_id: switch.chore_tracker_jordyn_feed_dog
|
entity_id: switch.chore_tracker_jordyn_feed_dog
|
||||||
|
|
||||||
- id: declan_reset_from_ha
|
- id: declan_reset_from_ha
|
||||||
alias: "Chore Tracker — Reset Declan's chores from HA"
|
alias: "Chore Tracker - Reset Declan's chores from HA"
|
||||||
trigger:
|
trigger:
|
||||||
- platform: state
|
- platform: state
|
||||||
entity_id: input_button.declan_reset_chores
|
entity_id: input_button.declan_reset_chores
|
||||||
@@ -106,7 +106,7 @@ automation:
|
|||||||
entity_id: switch.chore_tracker_declan_take_out_trash
|
entity_id: switch.chore_tracker_declan_take_out_trash
|
||||||
|
|
||||||
- id: chloe_reset_from_ha
|
- id: chloe_reset_from_ha
|
||||||
alias: "Chore Tracker — Reset Chloe's chores from HA"
|
alias: "Chore Tracker - Reset Chloe's chores from HA"
|
||||||
trigger:
|
trigger:
|
||||||
- platform: state
|
- platform: state
|
||||||
entity_id: input_button.chloe_reset_chores
|
entity_id: input_button.chloe_reset_chores
|
||||||
@@ -131,7 +131,7 @@ automation:
|
|||||||
entity_id: switch.chore_tracker_chloe_practice_piano
|
entity_id: switch.chore_tracker_chloe_practice_piano
|
||||||
|
|
||||||
- id: reset_all_from_ha
|
- id: reset_all_from_ha
|
||||||
alias: "Chore Tracker — Reset ALL chores from HA"
|
alias: "Chore Tracker - Reset ALL chores from HA"
|
||||||
trigger:
|
trigger:
|
||||||
- platform: state
|
- platform: state
|
||||||
entity_id: input_button.reset_all_chores
|
entity_id: input_button.reset_all_chores
|
||||||
@@ -183,7 +183,7 @@ automation:
|
|||||||
entity_id: switch.chore_tracker_chloe_practice_piano
|
entity_id: switch.chore_tracker_chloe_practice_piano
|
||||||
|
|
||||||
- id: jordyn_all_done_notify
|
- id: jordyn_all_done_notify
|
||||||
alias: "Chore Tracker — Jordyn all done!"
|
alias: "Chore Tracker - Jordyn all done!"
|
||||||
trigger:
|
trigger:
|
||||||
- platform: state
|
- platform: state
|
||||||
entity_id: sensor.jordyn_all_chores_done
|
entity_id: sensor.jordyn_all_chores_done
|
||||||
@@ -191,11 +191,11 @@ automation:
|
|||||||
action:
|
action:
|
||||||
- service: notify.notify
|
- service: notify.notify
|
||||||
data:
|
data:
|
||||||
title: "🎉 Jordyn finished all chores!"
|
title: "Jordyn finished all chores!"
|
||||||
message: "Jordyn completed all 5 chores today!"
|
message: "Jordyn completed all 5 chores today!"
|
||||||
|
|
||||||
- id: declan_all_done_notify
|
- id: declan_all_done_notify
|
||||||
alias: "Chore Tracker — Declan all done!"
|
alias: "Chore Tracker - Declan all done!"
|
||||||
trigger:
|
trigger:
|
||||||
- platform: state
|
- platform: state
|
||||||
entity_id: sensor.declan_all_chores_done
|
entity_id: sensor.declan_all_chores_done
|
||||||
@@ -203,11 +203,11 @@ automation:
|
|||||||
action:
|
action:
|
||||||
- service: notify.notify
|
- service: notify.notify
|
||||||
data:
|
data:
|
||||||
title: "🎉 Declan finished all chores!"
|
title: "Declan finished all chores!"
|
||||||
message: "Declan completed all 4 chores today!"
|
message: "Declan completed all 4 chores today!"
|
||||||
|
|
||||||
- id: chloe_all_done_notify
|
- id: chloe_all_done_notify
|
||||||
alias: "Chore Tracker — Chloe all done!"
|
alias: "Chore Tracker - Chloe all done!"
|
||||||
trigger:
|
trigger:
|
||||||
- platform: state
|
- platform: state
|
||||||
entity_id: sensor.chloe_all_chores_done
|
entity_id: sensor.chloe_all_chores_done
|
||||||
@@ -215,11 +215,11 @@ automation:
|
|||||||
action:
|
action:
|
||||||
- service: notify.notify
|
- service: notify.notify
|
||||||
data:
|
data:
|
||||||
title: "🎉 Chloe finished all chores!"
|
title: "Chloe finished all chores!"
|
||||||
message: "Chloe completed all 6 chores today!"
|
message: "Chloe completed all 6 chores today!"
|
||||||
|
|
||||||
- id: chore_reminder_evening
|
- id: chore_reminder_evening
|
||||||
alias: "Chore Tracker — Evening reminder"
|
alias: "Chore Tracker - Evening reminder"
|
||||||
trigger:
|
trigger:
|
||||||
- platform: time
|
- platform: time
|
||||||
at: "18:00:00"
|
at: "18:00:00"
|
||||||
@@ -230,7 +230,7 @@ automation:
|
|||||||
then:
|
then:
|
||||||
- service: notify.notify
|
- service: notify.notify
|
||||||
data:
|
data:
|
||||||
title: "📋 Jordyn has unfinished chores"
|
title: "Jordyn has unfinished chores"
|
||||||
message: >
|
message: >
|
||||||
Jordyn has done
|
Jordyn has done
|
||||||
{{ states('sensor.jordyn_chores_done_today') }}/5 chores today.
|
{{ states('sensor.jordyn_chores_done_today') }}/5 chores today.
|
||||||
@@ -240,7 +240,7 @@ automation:
|
|||||||
then:
|
then:
|
||||||
- service: notify.notify
|
- service: notify.notify
|
||||||
data:
|
data:
|
||||||
title: "📋 Declan has unfinished chores"
|
title: "Declan has unfinished chores"
|
||||||
message: >
|
message: >
|
||||||
Declan has done
|
Declan has done
|
||||||
{{ states('sensor.declan_chores_done_today') }}/4 chores today.
|
{{ states('sensor.declan_chores_done_today') }}/4 chores today.
|
||||||
@@ -250,7 +250,7 @@ automation:
|
|||||||
then:
|
then:
|
||||||
- service: notify.notify
|
- service: notify.notify
|
||||||
data:
|
data:
|
||||||
title: "📋 Chloe has unfinished chores"
|
title: "Chloe has unfinished chores"
|
||||||
message: >
|
message: >
|
||||||
Chloe has done
|
Chloe has done
|
||||||
{{ states('sensor.chloe_chores_done_today') }}/6 chores today.
|
{{ states('sensor.chloe_chores_done_today') }}/6 chores today.
|
||||||
|
|||||||
Reference in New Issue
Block a user