From 0a66aa438cb51adf83e3d6455c9e4a6f8c3ddae9 Mon Sep 17 00:00:00 2001 From: Joshua King Date: Fri, 27 Feb 2026 21:53:45 -0500 Subject: [PATCH 1/2] Add chore tracker configuration and generator scripts - Created `chores_config.yaml` for defining kids, chores, and settings. - Implemented `generate.py` to generate ESPHome, Home Assistant, and Lovelace dashboard configurations based on the YAML file. - Added `chore-tracker-ha.yaml` for Home Assistant integration, including sensors and automation for tracking chores and notifications. --- .gitignore | 11 + configuration.yaml | 2 + esphome/.gitignore | 5 - esphome/chore-tracker-esphome.yaml | 2948 +++++++++++++++++ .../chore-tracker-dashboard.yaml | 133 + .../chore-tracker/chore-tracker-esphome.yaml | 1757 ++++++++++ esphome/chore-tracker/chores_config.yaml | 70 + esphome/chore-tracker/generate.py | 895 +++++ packages/chore-tracker-ha.yaml | 258 ++ 9 files changed, 6074 insertions(+), 5 deletions(-) delete mode 100644 esphome/.gitignore create mode 100644 esphome/chore-tracker-esphome.yaml create mode 100644 esphome/chore-tracker/chore-tracker-dashboard.yaml create mode 100644 esphome/chore-tracker/chore-tracker-esphome.yaml create mode 100644 esphome/chore-tracker/chores_config.yaml create mode 100644 esphome/chore-tracker/generate.py create mode 100644 packages/chore-tracker-ha.yaml diff --git a/.gitignore b/.gitignore index 56649e0..930ed0f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ !*.txt* !*.json* !*.ui.yaml +!*.py # Whitelist subdirectory yaml files !*/*.yaml @@ -23,10 +24,14 @@ !*/*.ui.yaml !*/*.h !*/*.py +!*/*/*.py +!*/*/*.yaml # Whitelist specific folders (uncomment as needed) !automations/ +!packages/ +!scenes/ !scripts/ !blueprints/ !esphome/ @@ -37,6 +42,12 @@ !esphome/components/** !esphome/components/max17043/** !custom_components/** +!esphome/chore-tracker/*.py +!esphome/chore-tracker/*.yaml +!esphome/chore-tracker/ +!esphome/chore-tracker/** +!esphome/chore-tracker-esphome.yaml +!chore-tracker-ha.yaml # !packages/ # !themes/ # !node-red/ diff --git a/configuration.yaml b/configuration.yaml index 0096c64..dc0b5c0 100644 --- a/configuration.yaml +++ b/configuration.yaml @@ -1,3 +1,5 @@ +homeassistant: + packages: !include_dir_named packages/ # Loads default set of integrations. Do not remove. default_config: diff --git a/esphome/.gitignore b/esphome/.gitignore deleted file mode 100644 index d8b4157..0000000 --- a/esphome/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Gitignore settings for ESPHome -# This is an example and may include too much for your use-case. -# You can modify this file to suit your needs. -/.esphome/ -/secrets.yaml diff --git a/esphome/chore-tracker-esphome.yaml b/esphome/chore-tracker-esphome.yaml new file mode 100644 index 0000000..8ceaa22 --- /dev/null +++ b/esphome/chore-tracker-esphome.yaml @@ -0,0 +1,2948 @@ +################################################################################ +# chore-tracker-esphome.yaml (AUTO-GENERATED — edit chores_config.yaml) +# Kids: Emma, Liam, Zoe +# +# HOME SCREEN BEHAVIOUR: +# Red outline = chores incomplete +# Solid green = all chores done ✓ +# Resets to red automatically at midnight +################################################################################ + +esphome: + name: chore-tracker + friendly_name: "Chore Tracker" + +esp32: + board: esp32s3box + framework: + type: esp-idf + +wifi: + ssid: !secret wifi_ssid + password: !secret wifi_password + ap: + ssid: "Chore Tracker Hotspot" + password: "choretracker" + +captive_portal: +logger: + level: INFO + +api: + encryption: + key: !secret api_encryption_key + +ota: + - platform: esphome + password: !secret ota_password + +# ── Display — Waveshare ESP32-S3 7" (adjust pins for your board revision) ───── +display: + - platform: rpi_dpi_rgb + id: main_display + auto_clear_enabled: false + color_order: RGB + dimensions: + width: 800 + height: 480 + de_pin: + number: GPIO40 + ignore_strapping_warning: true + hsync_pin: + number: GPIO39 + ignore_strapping_warning: true + 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: + - id: i2c_touch + sda: GPIO19 + scl: GPIO20 + frequency: 400kHz + +output: + - platform: ledc + pin: GPIO17 + id: backlight_output + +light: + - platform: monochromatic + output: backlight_output + name: "Display Backlight" + id: backlight + restore_mode: ALWAYS_ON + +# ── Time: drives the daily reset ───────────────────────────────────────────── +time: + - platform: homeassistant + id: ha_time + on_time: + - hours: 0 + minutes: 0 + seconds: 0 + then: + - lambda: |- + // Reset all kids via named scripts (resets switches + refreshes UI) + id(reset_emma_chores).execute(); + id(reset_liam_chores).execute(); + id(reset_zoe_chores).execute(); + - lvgl.page.show: page_home + +fonts: + - file: "gfonts://Nunito:wght@900" + id: font_title + size: 40 + - file: "gfonts://Nunito:wght@800" + id: font_name + size: 30 + - file: "gfonts://Nunito:wght@700" + id: font_med + size: 22 + - file: "gfonts://Nunito:wght@600" + id: font_small + size: 17 + - file: "gfonts://Nunito:wght@600" + id: font_tiny + size: 13 + +# ── Switches — one per chore per kid, synced to HA ─────────────────────────── +switch: + + # ── Emma's chores ────────────────────────── - platform: template + name: "Emma - Make Bed" + id: emma_make_bed + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_emma_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_emma_make_bed + on_turn_off: + then: + - script.execute: update_emma_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_emma_make_bed + - platform: template + name: "Emma - Brush Teeth" + id: emma_brush_teeth + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_emma_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_emma_brush_teeth + on_turn_off: + then: + - script.execute: update_emma_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_emma_brush_teeth + - platform: template + name: "Emma - Tidy Room" + id: emma_tidy_room + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_emma_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_emma_tidy_room + on_turn_off: + then: + - script.execute: update_emma_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_emma_tidy_room + - platform: template + name: "Emma - Homework" + id: emma_homework + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_emma_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_emma_homework + on_turn_off: + then: + - script.execute: update_emma_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_emma_homework + - platform: template + name: "Emma - Set Table" + id: emma_set_table + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_emma_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_emma_set_table + on_turn_off: + then: + - script.execute: update_emma_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_emma_set_table + - platform: template + name: "Emma - Take Out Trash" + id: emma_take_out_trash + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_emma_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_emma_take_out_trash + on_turn_off: + then: + - script.execute: update_emma_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_emma_take_out_trash + - platform: template + name: "Emma - Feed Pet" + id: emma_feed_pet + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_emma_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_emma_feed_pet + on_turn_off: + then: + - script.execute: update_emma_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_emma_feed_pet + - platform: template + name: "Emma - Water Plants" + id: emma_water_plants + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_emma_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_emma_water_plants + on_turn_off: + then: + - script.execute: update_emma_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_emma_water_plants + + # ── Liam's chores ────────────────────────── - platform: template + name: "Liam - Make Bed" + id: liam_make_bed + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_liam_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_liam_make_bed + on_turn_off: + then: + - script.execute: update_liam_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_liam_make_bed + - platform: template + name: "Liam - Brush Teeth" + id: liam_brush_teeth + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_liam_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_liam_brush_teeth + on_turn_off: + then: + - script.execute: update_liam_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_liam_brush_teeth + - platform: template + name: "Liam - Tidy Room" + id: liam_tidy_room + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_liam_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_liam_tidy_room + on_turn_off: + then: + - script.execute: update_liam_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_liam_tidy_room + - platform: template + name: "Liam - Homework" + id: liam_homework + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_liam_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_liam_homework + on_turn_off: + then: + - script.execute: update_liam_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_liam_homework + - platform: template + name: "Liam - Set Table" + id: liam_set_table + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_liam_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_liam_set_table + on_turn_off: + then: + - script.execute: update_liam_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_liam_set_table + - platform: template + name: "Liam - Take Out Trash" + id: liam_take_out_trash + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_liam_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_liam_take_out_trash + on_turn_off: + then: + - script.execute: update_liam_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_liam_take_out_trash + - platform: template + name: "Liam - Feed Pet" + id: liam_feed_pet + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_liam_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_liam_feed_pet + on_turn_off: + then: + - script.execute: update_liam_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_liam_feed_pet + - platform: template + name: "Liam - Water Plants" + id: liam_water_plants + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_liam_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_liam_water_plants + on_turn_off: + then: + - script.execute: update_liam_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_liam_water_plants + + # ── Zoe's chores ────────────────────────── - platform: template + name: "Zoe - Make Bed" + id: zoe_make_bed + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_zoe_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_zoe_make_bed + on_turn_off: + then: + - script.execute: update_zoe_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_zoe_make_bed + - platform: template + name: "Zoe - Brush Teeth" + id: zoe_brush_teeth + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_zoe_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_zoe_brush_teeth + on_turn_off: + then: + - script.execute: update_zoe_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_zoe_brush_teeth + - platform: template + name: "Zoe - Tidy Room" + id: zoe_tidy_room + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_zoe_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_zoe_tidy_room + on_turn_off: + then: + - script.execute: update_zoe_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_zoe_tidy_room + - platform: template + name: "Zoe - Homework" + id: zoe_homework + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_zoe_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_zoe_homework + on_turn_off: + then: + - script.execute: update_zoe_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_zoe_homework + - platform: template + name: "Zoe - Set Table" + id: zoe_set_table + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_zoe_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_zoe_set_table + on_turn_off: + then: + - script.execute: update_zoe_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_zoe_set_table + - platform: template + name: "Zoe - Take Out Trash" + id: zoe_take_out_trash + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_zoe_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_zoe_take_out_trash + on_turn_off: + then: + - script.execute: update_zoe_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_zoe_take_out_trash + - platform: template + name: "Zoe - Feed Pet" + id: zoe_feed_pet + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_zoe_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_zoe_feed_pet + on_turn_off: + then: + - script.execute: update_zoe_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_zoe_feed_pet + - platform: template + name: "Zoe - Water Plants" + id: zoe_water_plants + icon: mdi:star + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_zoe_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_zoe_water_plants + on_turn_off: + then: + - script.execute: update_zoe_ui + # Push to HA so it stays in sync when toggled on the screen + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_zoe_water_plants + + +# ── Sensors — reported to HA ───────────────────────────────────────────────── +sensor: + - platform: template + name: "Emma Chores Done" + id: emma_chores_done + accuracy_decimals: 0 + update_interval: 2s + lambda: |- + int done = 0; + if (id(emma_make_bed).state) done++; + if (id(emma_brush_teeth).state) done++; + if (id(emma_tidy_room).state) done++; + if (id(emma_homework).state) done++; + if (id(emma_set_table).state) done++; + if (id(emma_take_out_trash).state) done++; + if (id(emma_feed_pet).state) done++; + if (id(emma_water_plants).state) done++; + return done; + + - platform: template + name: "Emma Stars Today" + id: emma_stars + unit_of_measurement: "stars" + accuracy_decimals: 0 + update_interval: 2s + lambda: |- + int stars = 0; + if (id(emma_make_bed).state) stars += 1; + if (id(emma_brush_teeth).state) stars += 1; + if (id(emma_tidy_room).state) stars += 2; + if (id(emma_homework).state) stars += 3; + if (id(emma_set_table).state) stars += 1; + if (id(emma_take_out_trash).state) stars += 2; + if (id(emma_feed_pet).state) stars += 1; + if (id(emma_water_plants).state) stars += 1; + return stars; + + - platform: template + name: "Liam Chores Done" + id: liam_chores_done + accuracy_decimals: 0 + update_interval: 2s + lambda: |- + int done = 0; + if (id(liam_make_bed).state) done++; + if (id(liam_brush_teeth).state) done++; + if (id(liam_tidy_room).state) done++; + if (id(liam_homework).state) done++; + if (id(liam_set_table).state) done++; + if (id(liam_take_out_trash).state) done++; + if (id(liam_feed_pet).state) done++; + if (id(liam_water_plants).state) done++; + return done; + + - platform: template + name: "Liam Stars Today" + id: liam_stars + unit_of_measurement: "stars" + accuracy_decimals: 0 + update_interval: 2s + lambda: |- + int stars = 0; + if (id(liam_make_bed).state) stars += 1; + if (id(liam_brush_teeth).state) stars += 1; + if (id(liam_tidy_room).state) stars += 2; + if (id(liam_homework).state) stars += 3; + if (id(liam_set_table).state) stars += 1; + if (id(liam_take_out_trash).state) stars += 2; + if (id(liam_feed_pet).state) stars += 1; + if (id(liam_water_plants).state) stars += 1; + return stars; + + - platform: template + name: "Zoe Chores Done" + id: zoe_chores_done + accuracy_decimals: 0 + update_interval: 2s + lambda: |- + int done = 0; + if (id(zoe_make_bed).state) done++; + if (id(zoe_brush_teeth).state) done++; + if (id(zoe_tidy_room).state) done++; + if (id(zoe_homework).state) done++; + if (id(zoe_set_table).state) done++; + if (id(zoe_take_out_trash).state) done++; + if (id(zoe_feed_pet).state) done++; + if (id(zoe_water_plants).state) done++; + return done; + + - platform: template + name: "Zoe Stars Today" + id: zoe_stars + unit_of_measurement: "stars" + accuracy_decimals: 0 + update_interval: 2s + lambda: |- + int stars = 0; + if (id(zoe_make_bed).state) stars += 1; + if (id(zoe_brush_teeth).state) stars += 1; + if (id(zoe_tidy_room).state) stars += 2; + if (id(zoe_homework).state) stars += 3; + if (id(zoe_set_table).state) stars += 1; + if (id(zoe_take_out_trash).state) stars += 2; + if (id(zoe_feed_pet).state) stars += 1; + if (id(zoe_water_plants).state) stars += 1; + return stars; + + + +# ── Scripts — update LVGL visuals when chore state changes ─────────────────── +script: + # Reset all of Emma's chores (used by manual reset button + midnight) + - id: reset_emma_chores + mode: single + then: + - lambda: |- + id(emma_make_bed).turn_off(); + id(emma_brush_teeth).turn_off(); + id(emma_tidy_room).turn_off(); + id(emma_homework).turn_off(); + id(emma_set_table).turn_off(); + id(emma_take_out_trash).turn_off(); + id(emma_feed_pet).turn_off(); + id(emma_water_plants).turn_off(); + - script.execute: update_emma_ui + + + - id: update_emma_ui + mode: single + then: + - lambda: |- + int done = (id(emma_make_bed).state ? 1 : 0) + (id(emma_brush_teeth).state ? 1 : 0) + (id(emma_tidy_room).state ? 1 : 0) + (id(emma_homework).state ? 1 : 0) + (id(emma_set_table).state ? 1 : 0) + (id(emma_take_out_trash).state ? 1 : 0) + (id(emma_feed_pet).state ? 1 : 0) + (id(emma_water_plants).state ? 1 : 0); + int stars = (id(emma_make_bed).state ? 1 : 0) + (id(emma_brush_teeth).state ? 1 : 0) + (id(emma_tidy_room).state ? 2 : 0) + (id(emma_homework).state ? 3 : 0) + (id(emma_set_table).state ? 1 : 0) + (id(emma_take_out_trash).state ? 2 : 0) + (id(emma_feed_pet).state ? 1 : 0) + (id(emma_water_plants).state ? 1 : 0); + int total = 8; + + // ── Sidebar progress & stars ────────────────────────────────────── + lv_bar_set_value(id(progress_bar_emma), done, LV_ANIM_ON); + char buf[32]; + snprintf(buf, sizeof(buf), "%d / 8", done); + lv_label_set_text(id(progress_label_emma), buf); + snprintf(buf, sizeof(buf), "⭐ %d star%s", stars, stars == 1 ? "" : "s"); + lv_label_set_text(id(sidebar_stars_emma), buf); + + // ── All-done celebration text ───────────────────────────────────── + if (done == total) { + lv_label_set_text(id(all_done_label_emma), "🎉 All done!"); + } else { + lv_label_set_text(id(all_done_label_emma), ""); + } + + // ── Home screen button: RED outline = incomplete, GREEN = complete ─ + if (done == total) { + // Solid green — all chores done + lv_obj_set_style_bg_opa(id(home_btn_emma), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_bg_color(id(home_btn_emma), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(home_btn_emma), 0, LV_PART_MAIN); + lv_label_set_text(id(home_status_emma), "✓ all done!"); + lv_obj_set_style_text_color(id(home_status_emma), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + } else { + // Transparent fill with red border — incomplete + lv_obj_set_style_bg_opa(id(home_btn_emma), LV_OPA_TRANSP, LV_PART_MAIN); + lv_obj_set_style_border_color(id(home_btn_emma), lv_color_hex(0xFF4757), LV_PART_MAIN); + lv_obj_set_style_border_width(id(home_btn_emma), 5, LV_PART_MAIN); + snprintf(buf, sizeof(buf), "%d left", total - done); + lv_label_set_text(id(home_status_emma), buf); + lv_obj_set_style_text_color(id(home_status_emma), lv_color_hex(0xFF4757), LV_PART_MAIN); + } + + // ── Individual chore card colours ───────────────────────────────── + // Make Bed + if (id(emma_make_bed).state) { + lv_obj_set_style_bg_color(id(card_emma_make_bed), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_emma_make_bed), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_emma_make_bed), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_emma_make_bed), 3, LV_PART_MAIN); + lv_label_set_text(id(check_emma_make_bed), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_emma_make_bed), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_emma_make_bed), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_emma_make_bed), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_emma_make_bed), 2, LV_PART_MAIN); + lv_label_set_text(id(check_emma_make_bed), ""); + } + // Brush Teeth + if (id(emma_brush_teeth).state) { + lv_obj_set_style_bg_color(id(card_emma_brush_teeth), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_emma_brush_teeth), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_emma_brush_teeth), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_emma_brush_teeth), 3, LV_PART_MAIN); + lv_label_set_text(id(check_emma_brush_teeth), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_emma_brush_teeth), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_emma_brush_teeth), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_emma_brush_teeth), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_emma_brush_teeth), 2, LV_PART_MAIN); + lv_label_set_text(id(check_emma_brush_teeth), ""); + } + // Tidy Room + if (id(emma_tidy_room).state) { + lv_obj_set_style_bg_color(id(card_emma_tidy_room), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_emma_tidy_room), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_emma_tidy_room), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_emma_tidy_room), 3, LV_PART_MAIN); + lv_label_set_text(id(check_emma_tidy_room), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_emma_tidy_room), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_emma_tidy_room), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_emma_tidy_room), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_emma_tidy_room), 2, LV_PART_MAIN); + lv_label_set_text(id(check_emma_tidy_room), ""); + } + // Homework + if (id(emma_homework).state) { + lv_obj_set_style_bg_color(id(card_emma_homework), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_emma_homework), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_emma_homework), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_emma_homework), 3, LV_PART_MAIN); + lv_label_set_text(id(check_emma_homework), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_emma_homework), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_emma_homework), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_emma_homework), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_emma_homework), 2, LV_PART_MAIN); + lv_label_set_text(id(check_emma_homework), ""); + } + // Set Table + if (id(emma_set_table).state) { + lv_obj_set_style_bg_color(id(card_emma_set_table), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_emma_set_table), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_emma_set_table), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_emma_set_table), 3, LV_PART_MAIN); + lv_label_set_text(id(check_emma_set_table), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_emma_set_table), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_emma_set_table), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_emma_set_table), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_emma_set_table), 2, LV_PART_MAIN); + lv_label_set_text(id(check_emma_set_table), ""); + } + // Take Out Trash + if (id(emma_take_out_trash).state) { + lv_obj_set_style_bg_color(id(card_emma_take_out_trash), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_emma_take_out_trash), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_emma_take_out_trash), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_emma_take_out_trash), 3, LV_PART_MAIN); + lv_label_set_text(id(check_emma_take_out_trash), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_emma_take_out_trash), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_emma_take_out_trash), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_emma_take_out_trash), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_emma_take_out_trash), 2, LV_PART_MAIN); + lv_label_set_text(id(check_emma_take_out_trash), ""); + } + // Feed Pet + if (id(emma_feed_pet).state) { + lv_obj_set_style_bg_color(id(card_emma_feed_pet), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_emma_feed_pet), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_emma_feed_pet), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_emma_feed_pet), 3, LV_PART_MAIN); + lv_label_set_text(id(check_emma_feed_pet), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_emma_feed_pet), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_emma_feed_pet), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_emma_feed_pet), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_emma_feed_pet), 2, LV_PART_MAIN); + lv_label_set_text(id(check_emma_feed_pet), ""); + } + // Water Plants + if (id(emma_water_plants).state) { + lv_obj_set_style_bg_color(id(card_emma_water_plants), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_emma_water_plants), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_emma_water_plants), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_emma_water_plants), 3, LV_PART_MAIN); + lv_label_set_text(id(check_emma_water_plants), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_emma_water_plants), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_emma_water_plants), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_emma_water_plants), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_emma_water_plants), 2, LV_PART_MAIN); + lv_label_set_text(id(check_emma_water_plants), ""); + } + + + # Reset all of Liam's chores (used by manual reset button + midnight) + - id: reset_liam_chores + mode: single + then: + - lambda: |- + id(liam_make_bed).turn_off(); + id(liam_brush_teeth).turn_off(); + id(liam_tidy_room).turn_off(); + id(liam_homework).turn_off(); + id(liam_set_table).turn_off(); + id(liam_take_out_trash).turn_off(); + id(liam_feed_pet).turn_off(); + id(liam_water_plants).turn_off(); + - script.execute: update_liam_ui + + + - id: update_liam_ui + mode: single + then: + - lambda: |- + int done = (id(liam_make_bed).state ? 1 : 0) + (id(liam_brush_teeth).state ? 1 : 0) + (id(liam_tidy_room).state ? 1 : 0) + (id(liam_homework).state ? 1 : 0) + (id(liam_set_table).state ? 1 : 0) + (id(liam_take_out_trash).state ? 1 : 0) + (id(liam_feed_pet).state ? 1 : 0) + (id(liam_water_plants).state ? 1 : 0); + int stars = (id(liam_make_bed).state ? 1 : 0) + (id(liam_brush_teeth).state ? 1 : 0) + (id(liam_tidy_room).state ? 2 : 0) + (id(liam_homework).state ? 3 : 0) + (id(liam_set_table).state ? 1 : 0) + (id(liam_take_out_trash).state ? 2 : 0) + (id(liam_feed_pet).state ? 1 : 0) + (id(liam_water_plants).state ? 1 : 0); + int total = 8; + + // ── Sidebar progress & stars ────────────────────────────────────── + lv_bar_set_value(id(progress_bar_liam), done, LV_ANIM_ON); + char buf[32]; + snprintf(buf, sizeof(buf), "%d / 8", done); + lv_label_set_text(id(progress_label_liam), buf); + snprintf(buf, sizeof(buf), "⭐ %d star%s", stars, stars == 1 ? "" : "s"); + lv_label_set_text(id(sidebar_stars_liam), buf); + + // ── All-done celebration text ───────────────────────────────────── + if (done == total) { + lv_label_set_text(id(all_done_label_liam), "🎉 All done!"); + } else { + lv_label_set_text(id(all_done_label_liam), ""); + } + + // ── Home screen button: RED outline = incomplete, GREEN = complete ─ + if (done == total) { + // Solid green — all chores done + lv_obj_set_style_bg_opa(id(home_btn_liam), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_bg_color(id(home_btn_liam), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(home_btn_liam), 0, LV_PART_MAIN); + lv_label_set_text(id(home_status_liam), "✓ all done!"); + lv_obj_set_style_text_color(id(home_status_liam), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + } else { + // Transparent fill with red border — incomplete + lv_obj_set_style_bg_opa(id(home_btn_liam), LV_OPA_TRANSP, LV_PART_MAIN); + lv_obj_set_style_border_color(id(home_btn_liam), lv_color_hex(0xFF4757), LV_PART_MAIN); + lv_obj_set_style_border_width(id(home_btn_liam), 5, LV_PART_MAIN); + snprintf(buf, sizeof(buf), "%d left", total - done); + lv_label_set_text(id(home_status_liam), buf); + lv_obj_set_style_text_color(id(home_status_liam), lv_color_hex(0xFF4757), LV_PART_MAIN); + } + + // ── Individual chore card colours ───────────────────────────────── + // Make Bed + if (id(liam_make_bed).state) { + lv_obj_set_style_bg_color(id(card_liam_make_bed), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_liam_make_bed), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_liam_make_bed), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_liam_make_bed), 3, LV_PART_MAIN); + lv_label_set_text(id(check_liam_make_bed), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_liam_make_bed), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_liam_make_bed), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_liam_make_bed), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_liam_make_bed), 2, LV_PART_MAIN); + lv_label_set_text(id(check_liam_make_bed), ""); + } + // Brush Teeth + if (id(liam_brush_teeth).state) { + lv_obj_set_style_bg_color(id(card_liam_brush_teeth), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_liam_brush_teeth), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_liam_brush_teeth), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_liam_brush_teeth), 3, LV_PART_MAIN); + lv_label_set_text(id(check_liam_brush_teeth), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_liam_brush_teeth), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_liam_brush_teeth), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_liam_brush_teeth), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_liam_brush_teeth), 2, LV_PART_MAIN); + lv_label_set_text(id(check_liam_brush_teeth), ""); + } + // Tidy Room + if (id(liam_tidy_room).state) { + lv_obj_set_style_bg_color(id(card_liam_tidy_room), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_liam_tidy_room), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_liam_tidy_room), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_liam_tidy_room), 3, LV_PART_MAIN); + lv_label_set_text(id(check_liam_tidy_room), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_liam_tidy_room), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_liam_tidy_room), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_liam_tidy_room), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_liam_tidy_room), 2, LV_PART_MAIN); + lv_label_set_text(id(check_liam_tidy_room), ""); + } + // Homework + if (id(liam_homework).state) { + lv_obj_set_style_bg_color(id(card_liam_homework), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_liam_homework), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_liam_homework), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_liam_homework), 3, LV_PART_MAIN); + lv_label_set_text(id(check_liam_homework), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_liam_homework), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_liam_homework), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_liam_homework), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_liam_homework), 2, LV_PART_MAIN); + lv_label_set_text(id(check_liam_homework), ""); + } + // Set Table + if (id(liam_set_table).state) { + lv_obj_set_style_bg_color(id(card_liam_set_table), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_liam_set_table), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_liam_set_table), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_liam_set_table), 3, LV_PART_MAIN); + lv_label_set_text(id(check_liam_set_table), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_liam_set_table), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_liam_set_table), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_liam_set_table), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_liam_set_table), 2, LV_PART_MAIN); + lv_label_set_text(id(check_liam_set_table), ""); + } + // Take Out Trash + if (id(liam_take_out_trash).state) { + lv_obj_set_style_bg_color(id(card_liam_take_out_trash), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_liam_take_out_trash), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_liam_take_out_trash), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_liam_take_out_trash), 3, LV_PART_MAIN); + lv_label_set_text(id(check_liam_take_out_trash), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_liam_take_out_trash), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_liam_take_out_trash), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_liam_take_out_trash), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_liam_take_out_trash), 2, LV_PART_MAIN); + lv_label_set_text(id(check_liam_take_out_trash), ""); + } + // Feed Pet + if (id(liam_feed_pet).state) { + lv_obj_set_style_bg_color(id(card_liam_feed_pet), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_liam_feed_pet), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_liam_feed_pet), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_liam_feed_pet), 3, LV_PART_MAIN); + lv_label_set_text(id(check_liam_feed_pet), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_liam_feed_pet), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_liam_feed_pet), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_liam_feed_pet), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_liam_feed_pet), 2, LV_PART_MAIN); + lv_label_set_text(id(check_liam_feed_pet), ""); + } + // Water Plants + if (id(liam_water_plants).state) { + lv_obj_set_style_bg_color(id(card_liam_water_plants), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_liam_water_plants), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_liam_water_plants), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_liam_water_plants), 3, LV_PART_MAIN); + lv_label_set_text(id(check_liam_water_plants), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_liam_water_plants), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_liam_water_plants), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_liam_water_plants), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_liam_water_plants), 2, LV_PART_MAIN); + lv_label_set_text(id(check_liam_water_plants), ""); + } + + + # Reset all of Zoe's chores (used by manual reset button + midnight) + - id: reset_zoe_chores + mode: single + then: + - lambda: |- + id(zoe_make_bed).turn_off(); + id(zoe_brush_teeth).turn_off(); + id(zoe_tidy_room).turn_off(); + id(zoe_homework).turn_off(); + id(zoe_set_table).turn_off(); + id(zoe_take_out_trash).turn_off(); + id(zoe_feed_pet).turn_off(); + id(zoe_water_plants).turn_off(); + - script.execute: update_zoe_ui + + + - id: update_zoe_ui + mode: single + then: + - lambda: |- + int done = (id(zoe_make_bed).state ? 1 : 0) + (id(zoe_brush_teeth).state ? 1 : 0) + (id(zoe_tidy_room).state ? 1 : 0) + (id(zoe_homework).state ? 1 : 0) + (id(zoe_set_table).state ? 1 : 0) + (id(zoe_take_out_trash).state ? 1 : 0) + (id(zoe_feed_pet).state ? 1 : 0) + (id(zoe_water_plants).state ? 1 : 0); + int stars = (id(zoe_make_bed).state ? 1 : 0) + (id(zoe_brush_teeth).state ? 1 : 0) + (id(zoe_tidy_room).state ? 2 : 0) + (id(zoe_homework).state ? 3 : 0) + (id(zoe_set_table).state ? 1 : 0) + (id(zoe_take_out_trash).state ? 2 : 0) + (id(zoe_feed_pet).state ? 1 : 0) + (id(zoe_water_plants).state ? 1 : 0); + int total = 8; + + // ── Sidebar progress & stars ────────────────────────────────────── + lv_bar_set_value(id(progress_bar_zoe), done, LV_ANIM_ON); + char buf[32]; + snprintf(buf, sizeof(buf), "%d / 8", done); + lv_label_set_text(id(progress_label_zoe), buf); + snprintf(buf, sizeof(buf), "⭐ %d star%s", stars, stars == 1 ? "" : "s"); + lv_label_set_text(id(sidebar_stars_zoe), buf); + + // ── All-done celebration text ───────────────────────────────────── + if (done == total) { + lv_label_set_text(id(all_done_label_zoe), "🎉 All done!"); + } else { + lv_label_set_text(id(all_done_label_zoe), ""); + } + + // ── Home screen button: RED outline = incomplete, GREEN = complete ─ + if (done == total) { + // Solid green — all chores done + lv_obj_set_style_bg_opa(id(home_btn_zoe), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_bg_color(id(home_btn_zoe), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(home_btn_zoe), 0, LV_PART_MAIN); + lv_label_set_text(id(home_status_zoe), "✓ all done!"); + lv_obj_set_style_text_color(id(home_status_zoe), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + } else { + // Transparent fill with red border — incomplete + lv_obj_set_style_bg_opa(id(home_btn_zoe), LV_OPA_TRANSP, LV_PART_MAIN); + lv_obj_set_style_border_color(id(home_btn_zoe), lv_color_hex(0xFF4757), LV_PART_MAIN); + lv_obj_set_style_border_width(id(home_btn_zoe), 5, LV_PART_MAIN); + snprintf(buf, sizeof(buf), "%d left", total - done); + lv_label_set_text(id(home_status_zoe), buf); + lv_obj_set_style_text_color(id(home_status_zoe), lv_color_hex(0xFF4757), LV_PART_MAIN); + } + + // ── Individual chore card colours ───────────────────────────────── + // Make Bed + if (id(zoe_make_bed).state) { + lv_obj_set_style_bg_color(id(card_zoe_make_bed), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_zoe_make_bed), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_zoe_make_bed), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_zoe_make_bed), 3, LV_PART_MAIN); + lv_label_set_text(id(check_zoe_make_bed), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_zoe_make_bed), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_zoe_make_bed), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_zoe_make_bed), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_zoe_make_bed), 2, LV_PART_MAIN); + lv_label_set_text(id(check_zoe_make_bed), ""); + } + // Brush Teeth + if (id(zoe_brush_teeth).state) { + lv_obj_set_style_bg_color(id(card_zoe_brush_teeth), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_zoe_brush_teeth), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_zoe_brush_teeth), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_zoe_brush_teeth), 3, LV_PART_MAIN); + lv_label_set_text(id(check_zoe_brush_teeth), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_zoe_brush_teeth), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_zoe_brush_teeth), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_zoe_brush_teeth), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_zoe_brush_teeth), 2, LV_PART_MAIN); + lv_label_set_text(id(check_zoe_brush_teeth), ""); + } + // Tidy Room + if (id(zoe_tidy_room).state) { + lv_obj_set_style_bg_color(id(card_zoe_tidy_room), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_zoe_tidy_room), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_zoe_tidy_room), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_zoe_tidy_room), 3, LV_PART_MAIN); + lv_label_set_text(id(check_zoe_tidy_room), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_zoe_tidy_room), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_zoe_tidy_room), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_zoe_tidy_room), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_zoe_tidy_room), 2, LV_PART_MAIN); + lv_label_set_text(id(check_zoe_tidy_room), ""); + } + // Homework + if (id(zoe_homework).state) { + lv_obj_set_style_bg_color(id(card_zoe_homework), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_zoe_homework), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_zoe_homework), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_zoe_homework), 3, LV_PART_MAIN); + lv_label_set_text(id(check_zoe_homework), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_zoe_homework), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_zoe_homework), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_zoe_homework), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_zoe_homework), 2, LV_PART_MAIN); + lv_label_set_text(id(check_zoe_homework), ""); + } + // Set Table + if (id(zoe_set_table).state) { + lv_obj_set_style_bg_color(id(card_zoe_set_table), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_zoe_set_table), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_zoe_set_table), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_zoe_set_table), 3, LV_PART_MAIN); + lv_label_set_text(id(check_zoe_set_table), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_zoe_set_table), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_zoe_set_table), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_zoe_set_table), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_zoe_set_table), 2, LV_PART_MAIN); + lv_label_set_text(id(check_zoe_set_table), ""); + } + // Take Out Trash + if (id(zoe_take_out_trash).state) { + lv_obj_set_style_bg_color(id(card_zoe_take_out_trash), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_zoe_take_out_trash), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_zoe_take_out_trash), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_zoe_take_out_trash), 3, LV_PART_MAIN); + lv_label_set_text(id(check_zoe_take_out_trash), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_zoe_take_out_trash), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_zoe_take_out_trash), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_zoe_take_out_trash), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_zoe_take_out_trash), 2, LV_PART_MAIN); + lv_label_set_text(id(check_zoe_take_out_trash), ""); + } + // Feed Pet + if (id(zoe_feed_pet).state) { + lv_obj_set_style_bg_color(id(card_zoe_feed_pet), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_zoe_feed_pet), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_zoe_feed_pet), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_zoe_feed_pet), 3, LV_PART_MAIN); + lv_label_set_text(id(check_zoe_feed_pet), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_zoe_feed_pet), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_zoe_feed_pet), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_zoe_feed_pet), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_zoe_feed_pet), 2, LV_PART_MAIN); + lv_label_set_text(id(check_zoe_feed_pet), ""); + } + // Water Plants + if (id(zoe_water_plants).state) { + lv_obj_set_style_bg_color(id(card_zoe_water_plants), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_zoe_water_plants), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_zoe_water_plants), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_zoe_water_plants), 3, LV_PART_MAIN); + lv_label_set_text(id(check_zoe_water_plants), "✅"); + } else { + lv_obj_set_style_bg_color(id(card_zoe_water_plants), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(card_zoe_water_plants), LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_zoe_water_plants), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_zoe_water_plants), 2, LV_PART_MAIN); + lv_label_set_text(id(check_zoe_water_plants), ""); + } + + + +# ── LVGL UI ─────────────────────────────────────────────────────────────────── +lvgl: + displays: + - main_display + touchscreens: + - touch + theme: + btn: + radius: 20 + border_width: 0 + pages: + - id: page_home + bg_color: 0xFFF9F0 + widgets: + - label: + x: 0 + y: 38 + width: 800 + align: TOP_MID + text: "⭐ Chore Tracker" + text_font: font_title + text_color: 0x2D3436 + - label: + x: 0 + y: 96 + width: 800 + align: TOP_MID + text: "Tap a name to check off chores" + text_font: font_small + text_color: 0xB2BEC3 + # Reset All button — bottom right, subtle red + - btn: + x: 660 + y: 428 + width: 130 + height: 40 + bg_color: 0xFF4757 + radius: 12 + on_click: + then: + - script.execute: reset_emma_chores + - script.execute: reset_liam_chores + - script.execute: reset_zoe_chores + widgets: + - label: + align: CENTER + text: "↺ Reset All" + text_color: 0xFFFFFF + text_font: font_tiny + # Emma — starts red (incomplete), turns green when all done + - btn: + id: home_btn_emma + x: 80 + y: 140 + width: 200 + height: 200 + bg_color: 0xFFFFFF + bg_opa: TRANSP + border_color: 0xFF4757 + border_width: 5 + radius: 24 + on_click: + then: + - lvgl.page.show: page_emma + widgets: + - label: + align: CENTER + y: -38 + text: "🐶" + text_font: font_title + - label: + align: CENTER + y: 28 + text: "Emma" + text_font: font_name + text_color: 0x2D3436 + - label: + id: home_status_emma + align: CENTER + y: 68 + text: "not done" + text_font: font_tiny + text_color: 0xFF4757 + + # Liam — starts red (incomplete), turns green when all done + - btn: + id: home_btn_liam + x: 300 + y: 140 + width: 200 + height: 200 + bg_color: 0xFFFFFF + bg_opa: TRANSP + border_color: 0xFF4757 + border_width: 5 + radius: 24 + on_click: + then: + - lvgl.page.show: page_liam + widgets: + - label: + align: CENTER + y: -38 + text: "🐱" + text_font: font_title + - label: + align: CENTER + y: 28 + text: "Liam" + text_font: font_name + text_color: 0x2D3436 + - label: + id: home_status_liam + align: CENTER + y: 68 + text: "not done" + text_font: font_tiny + text_color: 0xFF4757 + + # Zoe — starts red (incomplete), turns green when all done + - btn: + id: home_btn_zoe + x: 520 + y: 140 + width: 200 + height: 200 + bg_color: 0xFFFFFF + bg_opa: TRANSP + border_color: 0xFF4757 + border_width: 5 + radius: 24 + on_click: + then: + - lvgl.page.show: page_zoe + widgets: + - label: + align: CENTER + y: -38 + text: "🐻" + text_font: font_title + - label: + align: CENTER + y: 28 + text: "Zoe" + text_font: font_name + text_color: 0x2D3436 + - label: + id: home_status_zoe + align: CENTER + y: 68 + text: "not done" + text_font: font_tiny + text_color: 0xFF4757 + + + - id: page_emma + bg_color: 0xFFF9F0 + widgets: + + # ── Sidebar ────────────────────────────────────────────────────────── + - obj: + x: 0 + y: 0 + width: 180 + height: 480 + bg_color: 0x4D96FF + border_width: 0 + radius: 0 + pad_all: 0 + widgets: + - label: + x: 0 + y: 20 + width: 180 + align: TOP_MID + text: "🐶" + text_font: font_title + - label: + x: 0 + y: 74 + width: 180 + align: TOP_MID + text: "Emma" + text_font: font_name + text_color: 0xFFFFFF + - label: + id: sidebar_stars_emma + x: 0 + y: 120 + width: 180 + align: TOP_MID + text: "⭐ 0 stars" + text_font: font_med + text_color: 0xFFD93D + + # Progress bar + - bar: + id: progress_bar_emma + x: 16 + y: 164 + width: 148 + height: 16 + bg_color: 0x2A6FCC + indicator: + bg_color: 0xFFFFFF + value: 0 + min_value: 0 + max_value: 8 + - label: + id: progress_label_emma + x: 0 + y: 188 + width: 180 + align: TOP_MID + text: "0 / 8" + text_font: font_tiny + text_color: 0xDDEEFF + + # All-done celebration label (hidden until complete) + - label: + id: all_done_label_emma + x: 0 + y: 214 + width: 180 + align: TOP_MID + text: "" + text_font: font_small + text_color: 0xFFFFFF + + # Manual reset button (parent use — above back button) + - btn: + x: 16 + y: 362 + width: 148 + height: 44 + bg_color: 0xFF4757 + radius: 14 + on_click: + then: + - script.execute: reset_emma_chores + widgets: + - label: + align: CENTER + text: "↺ Reset" + text_color: 0xFFFFFF + text_font: font_small + + # Back button + - btn: + x: 16 + y: 418 + width: 148 + height: 46 + bg_color: 0x2A6FCC + radius: 14 + on_click: + then: + - lvgl.page.show: page_home + widgets: + - label: + align: CENTER + text: "◀ Home" + text_color: 0xFFFFFF + text_font: font_small + + # ── Chore cards ─────────────────────────────────────────────────────── + # Make Bed + - btn: + id: card_emma_make_bed + x: 190 + y: 10 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: emma_make_bed + widgets: + - label: + id: check_emma_make_bed + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🛏️" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Make Bed" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 1" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Brush Teeth + - btn: + id: card_emma_brush_teeth + x: 393 + y: 10 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: emma_brush_teeth + widgets: + - label: + id: check_emma_brush_teeth + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🦷" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Brush Teeth" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 1" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Tidy Room + - btn: + id: card_emma_tidy_room + x: 596 + y: 10 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: emma_tidy_room + widgets: + - label: + id: check_emma_tidy_room + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🧹" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Tidy Room" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 2" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Homework + - btn: + id: card_emma_homework + x: 190 + y: 158 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: emma_homework + widgets: + - label: + id: check_emma_homework + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "📚" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Homework" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 3" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Set Table + - btn: + id: card_emma_set_table + x: 393 + y: 158 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: emma_set_table + widgets: + - label: + id: check_emma_set_table + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🍽️" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Set Table" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 1" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Take Out Trash + - btn: + id: card_emma_take_out_trash + x: 596 + y: 158 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: emma_take_out_trash + widgets: + - label: + id: check_emma_take_out_trash + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🗑️" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Take Out Trash" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 2" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Feed Pet + - btn: + id: card_emma_feed_pet + x: 190 + y: 306 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: emma_feed_pet + widgets: + - label: + id: check_emma_feed_pet + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🐾" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Feed Pet" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 1" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Water Plants + - btn: + id: card_emma_water_plants + x: 393 + y: 306 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: emma_water_plants + widgets: + - label: + id: check_emma_water_plants + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🌱" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Water Plants" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 1" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + + - id: page_liam + bg_color: 0xFFF9F0 + widgets: + + # ── Sidebar ────────────────────────────────────────────────────────── + - obj: + x: 0 + y: 0 + width: 180 + height: 480 + bg_color: 0xC77DFF + border_width: 0 + radius: 0 + pad_all: 0 + widgets: + - label: + x: 0 + y: 20 + width: 180 + align: TOP_MID + text: "🐱" + text_font: font_title + - label: + x: 0 + y: 74 + width: 180 + align: TOP_MID + text: "Liam" + text_font: font_name + text_color: 0xFFFFFF + - label: + id: sidebar_stars_liam + x: 0 + y: 120 + width: 180 + align: TOP_MID + text: "⭐ 0 stars" + text_font: font_med + text_color: 0xFFD93D + + # Progress bar + - bar: + id: progress_bar_liam + x: 16 + y: 164 + width: 148 + height: 16 + bg_color: 0x8B42CC + indicator: + bg_color: 0xFFFFFF + value: 0 + min_value: 0 + max_value: 8 + - label: + id: progress_label_liam + x: 0 + y: 188 + width: 180 + align: TOP_MID + text: "0 / 8" + text_font: font_tiny + text_color: 0xDDEEFF + + # All-done celebration label (hidden until complete) + - label: + id: all_done_label_liam + x: 0 + y: 214 + width: 180 + align: TOP_MID + text: "" + text_font: font_small + text_color: 0xFFFFFF + + # Manual reset button (parent use — above back button) + - btn: + x: 16 + y: 362 + width: 148 + height: 44 + bg_color: 0xFF4757 + radius: 14 + on_click: + then: + - script.execute: reset_liam_chores + widgets: + - label: + align: CENTER + text: "↺ Reset" + text_color: 0xFFFFFF + text_font: font_small + + # Back button + - btn: + x: 16 + y: 418 + width: 148 + height: 46 + bg_color: 0x8B42CC + radius: 14 + on_click: + then: + - lvgl.page.show: page_home + widgets: + - label: + align: CENTER + text: "◀ Home" + text_color: 0xFFFFFF + text_font: font_small + + # ── Chore cards ─────────────────────────────────────────────────────── + # Make Bed + - btn: + id: card_liam_make_bed + x: 190 + y: 10 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: liam_make_bed + widgets: + - label: + id: check_liam_make_bed + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🛏️" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Make Bed" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 1" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Brush Teeth + - btn: + id: card_liam_brush_teeth + x: 393 + y: 10 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: liam_brush_teeth + widgets: + - label: + id: check_liam_brush_teeth + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🦷" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Brush Teeth" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 1" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Tidy Room + - btn: + id: card_liam_tidy_room + x: 596 + y: 10 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: liam_tidy_room + widgets: + - label: + id: check_liam_tidy_room + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🧹" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Tidy Room" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 2" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Homework + - btn: + id: card_liam_homework + x: 190 + y: 158 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: liam_homework + widgets: + - label: + id: check_liam_homework + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "📚" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Homework" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 3" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Set Table + - btn: + id: card_liam_set_table + x: 393 + y: 158 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: liam_set_table + widgets: + - label: + id: check_liam_set_table + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🍽️" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Set Table" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 1" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Take Out Trash + - btn: + id: card_liam_take_out_trash + x: 596 + y: 158 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: liam_take_out_trash + widgets: + - label: + id: check_liam_take_out_trash + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🗑️" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Take Out Trash" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 2" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Feed Pet + - btn: + id: card_liam_feed_pet + x: 190 + y: 306 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: liam_feed_pet + widgets: + - label: + id: check_liam_feed_pet + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🐾" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Feed Pet" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 1" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Water Plants + - btn: + id: card_liam_water_plants + x: 393 + y: 306 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: liam_water_plants + widgets: + - label: + id: check_liam_water_plants + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🌱" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Water Plants" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 1" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + + - id: page_zoe + bg_color: 0xFFF9F0 + widgets: + + # ── Sidebar ────────────────────────────────────────────────────────── + - obj: + x: 0 + y: 0 + width: 180 + height: 480 + bg_color: 0xFF6B9D + border_width: 0 + radius: 0 + pad_all: 0 + widgets: + - label: + x: 0 + y: 20 + width: 180 + align: TOP_MID + text: "🐻" + text_font: font_title + - label: + x: 0 + y: 74 + width: 180 + align: TOP_MID + text: "Zoe" + text_font: font_name + text_color: 0xFFFFFF + - label: + id: sidebar_stars_zoe + x: 0 + y: 120 + width: 180 + align: TOP_MID + text: "⭐ 0 stars" + text_font: font_med + text_color: 0xFFD93D + + # Progress bar + - bar: + id: progress_bar_zoe + x: 16 + y: 164 + width: 148 + height: 16 + bg_color: 0xCC3A6F + indicator: + bg_color: 0xFFFFFF + value: 0 + min_value: 0 + max_value: 8 + - label: + id: progress_label_zoe + x: 0 + y: 188 + width: 180 + align: TOP_MID + text: "0 / 8" + text_font: font_tiny + text_color: 0xDDEEFF + + # All-done celebration label (hidden until complete) + - label: + id: all_done_label_zoe + x: 0 + y: 214 + width: 180 + align: TOP_MID + text: "" + text_font: font_small + text_color: 0xFFFFFF + + # Manual reset button (parent use — above back button) + - btn: + x: 16 + y: 362 + width: 148 + height: 44 + bg_color: 0xFF4757 + radius: 14 + on_click: + then: + - script.execute: reset_zoe_chores + widgets: + - label: + align: CENTER + text: "↺ Reset" + text_color: 0xFFFFFF + text_font: font_small + + # Back button + - btn: + x: 16 + y: 418 + width: 148 + height: 46 + bg_color: 0xCC3A6F + radius: 14 + on_click: + then: + - lvgl.page.show: page_home + widgets: + - label: + align: CENTER + text: "◀ Home" + text_color: 0xFFFFFF + text_font: font_small + + # ── Chore cards ─────────────────────────────────────────────────────── + # Make Bed + - btn: + id: card_zoe_make_bed + x: 190 + y: 10 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: zoe_make_bed + widgets: + - label: + id: check_zoe_make_bed + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🛏️" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Make Bed" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 1" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Brush Teeth + - btn: + id: card_zoe_brush_teeth + x: 393 + y: 10 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: zoe_brush_teeth + widgets: + - label: + id: check_zoe_brush_teeth + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🦷" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Brush Teeth" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 1" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Tidy Room + - btn: + id: card_zoe_tidy_room + x: 596 + y: 10 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: zoe_tidy_room + widgets: + - label: + id: check_zoe_tidy_room + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🧹" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Tidy Room" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 2" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Homework + - btn: + id: card_zoe_homework + x: 190 + y: 158 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: zoe_homework + widgets: + - label: + id: check_zoe_homework + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "📚" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Homework" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 3" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Set Table + - btn: + id: card_zoe_set_table + x: 393 + y: 158 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: zoe_set_table + widgets: + - label: + id: check_zoe_set_table + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🍽️" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Set Table" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 1" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Take Out Trash + - btn: + id: card_zoe_take_out_trash + x: 596 + y: 158 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: zoe_take_out_trash + widgets: + - label: + id: check_zoe_take_out_trash + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🗑️" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Take Out Trash" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 2" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Feed Pet + - btn: + id: card_zoe_feed_pet + x: 190 + y: 306 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: zoe_feed_pet + widgets: + - label: + id: check_zoe_feed_pet + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🐾" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Feed Pet" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 1" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 + + # Water Plants + - btn: + id: card_zoe_water_plants + x: 393 + y: 306 + width: 193 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: zoe_water_plants + widgets: + - label: + id: check_zoe_water_plants + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🌱" + text_font: font_med + - label: + align: CENTER + y: 23 + text: "Water Plants" + text_font: font_small + text_color: 0x2D3436 + - label: + align: CENTER + y: 45 + text: "⭐ 1" + text_font: font_tiny + text_color: 0x7A5900 + bg_color: 0xFFD93D + radius: 8 + pad_left: 8 + pad_right: 8 + pad_top: 2 + pad_bottom: 2 \ No newline at end of file diff --git a/esphome/chore-tracker/chore-tracker-dashboard.yaml b/esphome/chore-tracker/chore-tracker-dashboard.yaml new file mode 100644 index 0000000..9334dc7 --- /dev/null +++ b/esphome/chore-tracker/chore-tracker-dashboard.yaml @@ -0,0 +1,133 @@ +################################################################################ +# chore-tracker-dashboard.yaml (AUTO-GENERATED — edit chores_config.yaml) +# Kids: Jordyn, Declan, Chloe +################################################################################ + +title: "Chore Tracker" +views: + - title: Today + icon: mdi:checkbox-marked-circle + path: chores + cards: + - type: horizontal-stack + cards: + - type: markdown + content: > + ### 😺 Jordyn + {{ + '✅ All done!' if states('sensor.jordyn_all_chores_done') == 'True' + else states('sensor.jordyn_chores_done_today') ~ '/5 chores done' + }} + + - type: markdown + content: > + ### 🤓 Declan + {{ + '✅ All done!' if states('sensor.declan_all_chores_done') == 'True' + else states('sensor.declan_chores_done_today') ~ '/4 chores done' + }} + + - type: markdown + content: > + ### 🌝 Chloe + {{ + '✅ All done!' if states('sensor.chloe_all_chores_done') == 'True' + else states('sensor.chloe_chores_done_today') ~ '/6 chores done' + }} + + - type: button + name: "↺ Reset ALL Chores" + icon: mdi:restart-alert + tap_action: + action: call-service + service: input_button.press + target: + entity_id: input_button.reset_all_chores + - type: entities + title: "😺 Jordyn's Chores" + entities: + - entity: switch.chore_tracker_jordyn_make_bed + name: "🛏️ Make Bed" + + - entity: switch.chore_tracker_jordyn_brush_teeth + name: "🦷 Brush Teeth" + + - entity: switch.chore_tracker_jordyn_tidy_room + name: "🧹 Tidy Room" + + - entity: switch.chore_tracker_jordyn_homework + name: "📚 Homework" + + - entity: switch.chore_tracker_jordyn_feed_dog + name: "🐾 Feed Dog" + - type: divider + - entity: sensor.jordyn_chores_done_today + name: "Chores done today" + - entity: sensor.jordyn_all_chores_done + name: "✅ All Done?" + - type: button + name: "↺ Reset Jordyn's Chores" + tap_action: + action: call-service + service: input_button.press + target: + entity_id: input_button.jordyn_reset_chores + - type: entities + title: "🤓 Declan's Chores" + entities: + - entity: switch.chore_tracker_declan_make_bed + name: "🛏️ Make Bed" + + - entity: switch.chore_tracker_declan_brush_teeth + name: "🦷 Brush Teeth" + + - entity: switch.chore_tracker_declan_set_table + name: "🍽️ Set Table" + + - entity: switch.chore_tracker_declan_take_out_trash + name: "🗑️ Take Out Trash" + - type: divider + - entity: sensor.declan_chores_done_today + name: "Chores done today" + - entity: sensor.declan_all_chores_done + name: "✅ All Done?" + - type: button + name: "↺ Reset Declan's Chores" + tap_action: + action: call-service + service: input_button.press + target: + entity_id: input_button.declan_reset_chores + - type: entities + title: "🌝 Chloe's Chores" + entities: + - entity: switch.chore_tracker_chloe_make_bed + name: "🛏️ Make Bed" + + - entity: switch.chore_tracker_chloe_brush_teeth + name: "🦷 Brush Teeth" + + - entity: switch.chore_tracker_chloe_water_plants + name: "🌱 Water Plants" + + - entity: switch.chore_tracker_chloe_homework + name: "📚 Homework" + + - entity: switch.chore_tracker_chloe_tidy_room + name: "🧹 Tidy Room" + + - entity: switch.chore_tracker_chloe_practice_piano + name: "🎹 Practice Piano" + - type: divider + - entity: sensor.chloe_chores_done_today + name: "Chores done today" + - entity: sensor.chloe_all_chores_done + name: "✅ All Done?" + - type: button + name: "↺ Reset Chloe's Chores" + tap_action: + action: call-service + service: input_button.press + target: + entity_id: input_button.chloe_reset_chores + diff --git a/esphome/chore-tracker/chore-tracker-esphome.yaml b/esphome/chore-tracker/chore-tracker-esphome.yaml new file mode 100644 index 0000000..3ef805f --- /dev/null +++ b/esphome/chore-tracker/chore-tracker-esphome.yaml @@ -0,0 +1,1757 @@ +################################################################################ +# chore-tracker-esphome.yaml (AUTO-GENERATED — edit chores_config.yaml) +# Kids: Jordyn, Declan, Chloe +# +# HOME SCREEN BEHAVIOUR: +# Red outline = chores incomplete +# Solid green = all chores done ✓ +# Resets to red automatically at midnight +################################################################################ + +esphome: + name: chore-tracker + friendly_name: "Chore Tracker" + +esp32: + board: esp32s3box + framework: + type: esp-idf + +wifi: + ssid: !secret wifi_iot_ssid + password: !secret wifi_password + ap: + ssid: "Chore Tracker Hotspot" + password: "choretracker" + +captive_portal: +logger: + level: INFO + +api: + encryption: + key: !secret api_encryption_key + +ota: + - platform: esphome + password: !secret ota_password + +# ── Display — Waveshare ESP32-S3 7" (adjust pins for your board revision) ───── +display: + - platform: rpi_dpi_rgb + id: main_display + auto_clear_enabled: false + color_order: RGB + dimensions: + width: 800 + height: 480 + de_pin: + number: GPIO40 + ignore_strapping_warning: true + hsync_pin: + number: GPIO39 + ignore_strapping_warning: true + 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: + - id: i2c_touch + sda: GPIO19 + scl: GPIO20 + frequency: 400kHz + +output: + - platform: ledc + pin: GPIO17 + id: backlight_output + +light: + - platform: monochromatic + output: backlight_output + name: "Display Backlight" + id: backlight + restore_mode: ALWAYS_ON + +# ── Midnight reset ──────────────────────────────────────────────────────────── +time: + - platform: homeassistant + id: ha_time + on_time: + - hours: 0 + minutes: 0 + seconds: 0 + then: + - lambda: |- + id(reset_jordyn_chores).execute(); + id(reset_declan_chores).execute(); + id(reset_chloe_chores).execute(); + - lvgl.page.show: page_home + +fonts: + - file: "gfonts://Nunito:wght@900" + id: font_title + size: 40 + - file: "gfonts://Nunito:wght@800" + id: font_name + size: 30 + - file: "gfonts://Nunito:wght@700" + id: font_med + size: 22 + - file: "gfonts://Nunito:wght@600" + id: font_small + size: 17 + - file: "gfonts://Nunito:wght@600" + id: font_tiny + size: 13 + +# ── Switches — one per chore per kid, synced to HA ─────────────────────────── +switch: + + # ── Jordyn's chores ────────────────────────── - platform: template + name: "Jordyn - Make Bed" + id: jordyn_make_bed + icon: mdi:checkbox-marked-circle + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_jordyn_ui + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_jordyn_make_bed + on_turn_off: + then: + - script.execute: update_jordyn_ui + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_jordyn_make_bed + - platform: template + name: "Jordyn - Brush Teeth" + id: jordyn_brush_teeth + icon: mdi:checkbox-marked-circle + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_jordyn_ui + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_jordyn_brush_teeth + on_turn_off: + then: + - script.execute: update_jordyn_ui + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_jordyn_brush_teeth + - platform: template + name: "Jordyn - Tidy Room" + id: jordyn_tidy_room + icon: mdi:checkbox-marked-circle + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_jordyn_ui + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_jordyn_tidy_room + on_turn_off: + then: + - script.execute: update_jordyn_ui + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_jordyn_tidy_room + - platform: template + name: "Jordyn - Homework" + id: jordyn_homework + icon: mdi:checkbox-marked-circle + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_jordyn_ui + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_jordyn_homework + on_turn_off: + then: + - script.execute: update_jordyn_ui + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_jordyn_homework + - platform: template + name: "Jordyn - Feed Dog" + id: jordyn_feed_dog + icon: mdi:checkbox-marked-circle + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_jordyn_ui + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_jordyn_feed_dog + on_turn_off: + then: + - script.execute: update_jordyn_ui + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_jordyn_feed_dog + + # ── Declan's chores ────────────────────────── - platform: template + name: "Declan - Make Bed" + id: declan_make_bed + icon: mdi:checkbox-marked-circle + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_declan_ui + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_declan_make_bed + on_turn_off: + then: + - script.execute: update_declan_ui + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_declan_make_bed + - platform: template + name: "Declan - Brush Teeth" + id: declan_brush_teeth + icon: mdi:checkbox-marked-circle + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_declan_ui + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_declan_brush_teeth + on_turn_off: + then: + - script.execute: update_declan_ui + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_declan_brush_teeth + - platform: template + name: "Declan - Set Table" + id: declan_set_table + icon: mdi:checkbox-marked-circle + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_declan_ui + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_declan_set_table + on_turn_off: + then: + - script.execute: update_declan_ui + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_declan_set_table + - platform: template + name: "Declan - Take Out Trash" + id: declan_take_out_trash + icon: mdi:checkbox-marked-circle + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_declan_ui + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_declan_take_out_trash + on_turn_off: + then: + - script.execute: update_declan_ui + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_declan_take_out_trash + + # ── Chloe's chores ────────────────────────── - platform: template + name: "Chloe - Make Bed" + id: chloe_make_bed + icon: mdi:checkbox-marked-circle + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_chloe_ui + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_chloe_make_bed + on_turn_off: + then: + - script.execute: update_chloe_ui + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_chloe_make_bed + - platform: template + name: "Chloe - Brush Teeth" + id: chloe_brush_teeth + icon: mdi:checkbox-marked-circle + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_chloe_ui + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_chloe_brush_teeth + on_turn_off: + then: + - script.execute: update_chloe_ui + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_chloe_brush_teeth + - platform: template + name: "Chloe - Water Plants" + id: chloe_water_plants + icon: mdi:checkbox-marked-circle + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_chloe_ui + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_chloe_water_plants + on_turn_off: + then: + - script.execute: update_chloe_ui + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_chloe_water_plants + - platform: template + name: "Chloe - Homework" + id: chloe_homework + icon: mdi:checkbox-marked-circle + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_chloe_ui + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_chloe_homework + on_turn_off: + then: + - script.execute: update_chloe_ui + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_chloe_homework + - platform: template + name: "Chloe - Tidy Room" + id: chloe_tidy_room + icon: mdi:checkbox-marked-circle + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_chloe_ui + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_chloe_tidy_room + on_turn_off: + then: + - script.execute: update_chloe_ui + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_chloe_tidy_room + - platform: template + name: "Chloe - Practice Piano" + id: chloe_practice_piano + icon: mdi:checkbox-marked-circle + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_chloe_ui + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_chloe_practice_piano + on_turn_off: + then: + - script.execute: update_chloe_ui + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_chloe_practice_piano + + +# ── Sensors — reported to HA ───────────────────────────────────────────────── +sensor: + - platform: template + name: "Jordyn Chores Done" + id: jordyn_chores_done + accuracy_decimals: 0 + update_interval: 2s + lambda: |- + int done = 0; + if (id(jordyn_make_bed).state) done++; + if (id(jordyn_brush_teeth).state) done++; + if (id(jordyn_tidy_room).state) done++; + if (id(jordyn_homework).state) done++; + if (id(jordyn_feed_dog).state) done++; + return done; + + - platform: template + name: "Declan Chores Done" + id: declan_chores_done + accuracy_decimals: 0 + update_interval: 2s + lambda: |- + int done = 0; + if (id(declan_make_bed).state) done++; + if (id(declan_brush_teeth).state) done++; + if (id(declan_set_table).state) done++; + if (id(declan_take_out_trash).state) done++; + return done; + + - platform: template + name: "Chloe Chores Done" + id: chloe_chores_done + accuracy_decimals: 0 + update_interval: 2s + lambda: |- + int done = 0; + if (id(chloe_make_bed).state) done++; + if (id(chloe_brush_teeth).state) done++; + if (id(chloe_water_plants).state) done++; + if (id(chloe_homework).state) done++; + if (id(chloe_tidy_room).state) done++; + if (id(chloe_practice_piano).state) done++; + return done; + + + +# ── Scripts — reset + UI update ─────────────────────────────────────────────── +script: + - id: reset_jordyn_chores + mode: single + then: + - lambda: |- + id(jordyn_make_bed).turn_off(); + id(jordyn_brush_teeth).turn_off(); + id(jordyn_tidy_room).turn_off(); + id(jordyn_homework).turn_off(); + id(jordyn_feed_dog).turn_off(); + - script.execute: update_jordyn_ui + + + - id: update_jordyn_ui + mode: single + then: + - lambda: |- + int done = (id(jordyn_make_bed).state ? 1 : 0) + (id(jordyn_brush_teeth).state ? 1 : 0) + (id(jordyn_tidy_room).state ? 1 : 0) + (id(jordyn_homework).state ? 1 : 0) + (id(jordyn_feed_dog).state ? 1 : 0); + int total = 5; + char buf[24]; + + // Progress bar + label + lv_bar_set_value(id(progress_bar_jordyn), done, LV_ANIM_ON); + snprintf(buf, sizeof(buf), "%d / 5", done); + lv_label_set_text(id(progress_label_jordyn), buf); + + // All-done message in sidebar + lv_label_set_text(id(all_done_label_jordyn), done == total ? "\U0001F389 All done!" : ""); + + // Home button colour + if (done == total) { + 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_border_width(id(home_btn_jordyn), 0, LV_PART_MAIN); + lv_label_set_text(id(home_status_jordyn), "\u2713 all done!"); + lv_obj_set_style_text_color(id(home_status_jordyn), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + } else { + lv_obj_set_style_bg_opa(id(home_btn_jordyn), LV_OPA_TRANSP, LV_PART_MAIN); + lv_obj_set_style_border_color(id(home_btn_jordyn), lv_color_hex(0xFF4757), LV_PART_MAIN); + lv_obj_set_style_border_width(id(home_btn_jordyn), 5, LV_PART_MAIN); + snprintf(buf, sizeof(buf), "%d left", total - done); + lv_label_set_text(id(home_status_jordyn), buf); + lv_obj_set_style_text_color(id(home_status_jordyn), lv_color_hex(0xFF4757), LV_PART_MAIN); + } + + // Card colours + if (id(jordyn_make_bed).state) { + lv_obj_set_style_bg_color(id(card_jordyn_make_bed), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_make_bed), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_make_bed), 3, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_make_bed), "\u2705"); + } else { + lv_obj_set_style_bg_color(id(card_jordyn_make_bed), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_make_bed), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_make_bed), 2, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_make_bed), ""); + } + if (id(jordyn_brush_teeth).state) { + lv_obj_set_style_bg_color(id(card_jordyn_brush_teeth), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_brush_teeth), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_brush_teeth), 3, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_brush_teeth), "\u2705"); + } else { + lv_obj_set_style_bg_color(id(card_jordyn_brush_teeth), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_brush_teeth), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_brush_teeth), 2, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_brush_teeth), ""); + } + if (id(jordyn_tidy_room).state) { + lv_obj_set_style_bg_color(id(card_jordyn_tidy_room), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_tidy_room), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_tidy_room), 3, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_tidy_room), "\u2705"); + } else { + lv_obj_set_style_bg_color(id(card_jordyn_tidy_room), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_tidy_room), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_tidy_room), 2, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_tidy_room), ""); + } + if (id(jordyn_homework).state) { + lv_obj_set_style_bg_color(id(card_jordyn_homework), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_homework), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_homework), 3, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_homework), "\u2705"); + } else { + lv_obj_set_style_bg_color(id(card_jordyn_homework), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_homework), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_homework), 2, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_homework), ""); + } + if (id(jordyn_feed_dog).state) { + lv_obj_set_style_bg_color(id(card_jordyn_feed_dog), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_feed_dog), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_feed_dog), 3, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_feed_dog), "\u2705"); + } else { + lv_obj_set_style_bg_color(id(card_jordyn_feed_dog), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_feed_dog), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_feed_dog), 2, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_feed_dog), ""); + } + + + - id: reset_declan_chores + mode: single + then: + - lambda: |- + id(declan_make_bed).turn_off(); + id(declan_brush_teeth).turn_off(); + id(declan_set_table).turn_off(); + id(declan_take_out_trash).turn_off(); + - script.execute: update_declan_ui + + + - id: update_declan_ui + mode: single + then: + - lambda: |- + int done = (id(declan_make_bed).state ? 1 : 0) + (id(declan_brush_teeth).state ? 1 : 0) + (id(declan_set_table).state ? 1 : 0) + (id(declan_take_out_trash).state ? 1 : 0); + int total = 4; + char buf[24]; + + // Progress bar + label + lv_bar_set_value(id(progress_bar_declan), done, LV_ANIM_ON); + snprintf(buf, sizeof(buf), "%d / 4", done); + lv_label_set_text(id(progress_label_declan), buf); + + // All-done message in sidebar + lv_label_set_text(id(all_done_label_declan), done == total ? "\U0001F389 All done!" : ""); + + // Home button colour + if (done == total) { + 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_border_width(id(home_btn_declan), 0, LV_PART_MAIN); + lv_label_set_text(id(home_status_declan), "\u2713 all done!"); + lv_obj_set_style_text_color(id(home_status_declan), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + } else { + lv_obj_set_style_bg_opa(id(home_btn_declan), LV_OPA_TRANSP, LV_PART_MAIN); + lv_obj_set_style_border_color(id(home_btn_declan), lv_color_hex(0xFF4757), LV_PART_MAIN); + lv_obj_set_style_border_width(id(home_btn_declan), 5, LV_PART_MAIN); + snprintf(buf, sizeof(buf), "%d left", total - done); + lv_label_set_text(id(home_status_declan), buf); + lv_obj_set_style_text_color(id(home_status_declan), lv_color_hex(0xFF4757), LV_PART_MAIN); + } + + // Card colours + if (id(declan_make_bed).state) { + lv_obj_set_style_bg_color(id(card_declan_make_bed), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_declan_make_bed), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_declan_make_bed), 3, LV_PART_MAIN); + lv_label_set_text(id(check_declan_make_bed), "\u2705"); + } else { + lv_obj_set_style_bg_color(id(card_declan_make_bed), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_declan_make_bed), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_declan_make_bed), 2, LV_PART_MAIN); + lv_label_set_text(id(check_declan_make_bed), ""); + } + if (id(declan_brush_teeth).state) { + lv_obj_set_style_bg_color(id(card_declan_brush_teeth), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_declan_brush_teeth), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_declan_brush_teeth), 3, LV_PART_MAIN); + lv_label_set_text(id(check_declan_brush_teeth), "\u2705"); + } else { + lv_obj_set_style_bg_color(id(card_declan_brush_teeth), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_declan_brush_teeth), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_declan_brush_teeth), 2, LV_PART_MAIN); + lv_label_set_text(id(check_declan_brush_teeth), ""); + } + if (id(declan_set_table).state) { + lv_obj_set_style_bg_color(id(card_declan_set_table), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_declan_set_table), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_declan_set_table), 3, LV_PART_MAIN); + lv_label_set_text(id(check_declan_set_table), "\u2705"); + } else { + lv_obj_set_style_bg_color(id(card_declan_set_table), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_declan_set_table), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_declan_set_table), 2, LV_PART_MAIN); + lv_label_set_text(id(check_declan_set_table), ""); + } + if (id(declan_take_out_trash).state) { + lv_obj_set_style_bg_color(id(card_declan_take_out_trash), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_declan_take_out_trash), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_declan_take_out_trash), 3, LV_PART_MAIN); + lv_label_set_text(id(check_declan_take_out_trash), "\u2705"); + } else { + lv_obj_set_style_bg_color(id(card_declan_take_out_trash), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_declan_take_out_trash), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_declan_take_out_trash), 2, LV_PART_MAIN); + lv_label_set_text(id(check_declan_take_out_trash), ""); + } + + + - id: reset_chloe_chores + mode: single + then: + - lambda: |- + id(chloe_make_bed).turn_off(); + id(chloe_brush_teeth).turn_off(); + id(chloe_water_plants).turn_off(); + id(chloe_homework).turn_off(); + id(chloe_tidy_room).turn_off(); + id(chloe_practice_piano).turn_off(); + - script.execute: update_chloe_ui + + + - id: update_chloe_ui + mode: single + then: + - lambda: |- + int done = (id(chloe_make_bed).state ? 1 : 0) + (id(chloe_brush_teeth).state ? 1 : 0) + (id(chloe_water_plants).state ? 1 : 0) + (id(chloe_homework).state ? 1 : 0) + (id(chloe_tidy_room).state ? 1 : 0) + (id(chloe_practice_piano).state ? 1 : 0); + int total = 6; + char buf[24]; + + // Progress bar + label + lv_bar_set_value(id(progress_bar_chloe), done, LV_ANIM_ON); + snprintf(buf, sizeof(buf), "%d / 6", done); + lv_label_set_text(id(progress_label_chloe), buf); + + // All-done message in sidebar + lv_label_set_text(id(all_done_label_chloe), done == total ? "\U0001F389 All done!" : ""); + + // Home button colour + if (done == total) { + 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_border_width(id(home_btn_chloe), 0, LV_PART_MAIN); + lv_label_set_text(id(home_status_chloe), "\u2713 all done!"); + lv_obj_set_style_text_color(id(home_status_chloe), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + } else { + lv_obj_set_style_bg_opa(id(home_btn_chloe), LV_OPA_TRANSP, LV_PART_MAIN); + lv_obj_set_style_border_color(id(home_btn_chloe), lv_color_hex(0xFF4757), LV_PART_MAIN); + lv_obj_set_style_border_width(id(home_btn_chloe), 5, LV_PART_MAIN); + snprintf(buf, sizeof(buf), "%d left", total - done); + lv_label_set_text(id(home_status_chloe), buf); + lv_obj_set_style_text_color(id(home_status_chloe), lv_color_hex(0xFF4757), LV_PART_MAIN); + } + + // Card colours + if (id(chloe_make_bed).state) { + lv_obj_set_style_bg_color(id(card_chloe_make_bed), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_make_bed), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_make_bed), 3, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_make_bed), "\u2705"); + } else { + lv_obj_set_style_bg_color(id(card_chloe_make_bed), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_make_bed), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_make_bed), 2, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_make_bed), ""); + } + if (id(chloe_brush_teeth).state) { + lv_obj_set_style_bg_color(id(card_chloe_brush_teeth), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_brush_teeth), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_brush_teeth), 3, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_brush_teeth), "\u2705"); + } else { + lv_obj_set_style_bg_color(id(card_chloe_brush_teeth), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_brush_teeth), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_brush_teeth), 2, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_brush_teeth), ""); + } + if (id(chloe_water_plants).state) { + lv_obj_set_style_bg_color(id(card_chloe_water_plants), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_water_plants), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_water_plants), 3, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_water_plants), "\u2705"); + } else { + lv_obj_set_style_bg_color(id(card_chloe_water_plants), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_water_plants), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_water_plants), 2, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_water_plants), ""); + } + if (id(chloe_homework).state) { + lv_obj_set_style_bg_color(id(card_chloe_homework), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_homework), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_homework), 3, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_homework), "\u2705"); + } else { + lv_obj_set_style_bg_color(id(card_chloe_homework), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_homework), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_homework), 2, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_homework), ""); + } + if (id(chloe_tidy_room).state) { + lv_obj_set_style_bg_color(id(card_chloe_tidy_room), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_tidy_room), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_tidy_room), 3, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_tidy_room), "\u2705"); + } else { + lv_obj_set_style_bg_color(id(card_chloe_tidy_room), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_tidy_room), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_tidy_room), 2, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_tidy_room), ""); + } + if (id(chloe_practice_piano).state) { + lv_obj_set_style_bg_color(id(card_chloe_practice_piano), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_practice_piano), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_practice_piano), 3, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_practice_piano), "\u2705"); + } else { + lv_obj_set_style_bg_color(id(card_chloe_practice_piano), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_practice_piano), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_practice_piano), 2, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_practice_piano), ""); + } + + + +# ── LVGL UI ─────────────────────────────────────────────────────────────────── +lvgl: + displays: + - main_display + touchscreens: + - touch + theme: + btn: + radius: 20 + border_width: 0 + pages: + - id: page_home + bg_color: 0xFFF9F0 + widgets: + - label: + x: 0 + y: 36 + width: 800 + align: TOP_MID + text: "Chore Tracker" + text_font: font_title + text_color: 0x2D3436 + - label: + x: 0 + y: 90 + width: 800 + align: TOP_MID + text: "Tap a name to check off chores" + text_font: font_small + text_color: 0xB2BEC3 + - btn: + x: 640 + y: 424 + width: 148 + height: 40 + bg_color: 0xFF4757 + radius: 12 + on_click: + then: + - script.execute: reset_jordyn_chores + - script.execute: reset_declan_chores + - script.execute: reset_chloe_chores + widgets: + - label: + align: CENTER + text: "↺ Reset All" + text_color: 0xFFFFFF + text_font: font_tiny + - btn: + id: home_btn_jordyn + x: 80 + y: 130 + width: 200 + height: 210 + bg_color: 0xFFFFFF + bg_opa: TRANSP + border_color: 0xFF4757 + border_width: 5 + radius: 24 + on_click: + then: + - lvgl.page.show: page_jordyn + widgets: + - label: + align: CENTER + y: -45 + text: "😺" + text_font: font_title + - label: + align: CENTER + y: 22 + text: "Jordyn" + text_font: font_name + text_color: 0x2D3436 + - label: + id: home_status_jordyn + align: CENTER + y: 66 + text: "not done" + text_font: font_tiny + text_color: 0xFF4757 + + - btn: + id: home_btn_declan + x: 300 + y: 130 + width: 200 + height: 210 + bg_color: 0xFFFFFF + bg_opa: TRANSP + border_color: 0xFF4757 + border_width: 5 + radius: 24 + on_click: + then: + - lvgl.page.show: page_declan + widgets: + - label: + align: CENTER + y: -45 + text: "🤓" + text_font: font_title + - label: + align: CENTER + y: 22 + text: "Declan" + text_font: font_name + text_color: 0x2D3436 + - label: + id: home_status_declan + align: CENTER + y: 66 + text: "not done" + text_font: font_tiny + text_color: 0xFF4757 + + - btn: + id: home_btn_chloe + x: 520 + y: 130 + width: 200 + height: 210 + bg_color: 0xFFFFFF + bg_opa: TRANSP + border_color: 0xFF4757 + border_width: 5 + radius: 24 + on_click: + then: + - lvgl.page.show: page_chloe + widgets: + - label: + align: CENTER + y: -45 + text: "🌝" + text_font: font_title + - label: + align: CENTER + y: 22 + text: "Chloe" + text_font: font_name + text_color: 0x2D3436 + - label: + id: home_status_chloe + align: CENTER + y: 66 + text: "not done" + text_font: font_tiny + text_color: 0xFF4757 + + + - id: page_jordyn + bg_color: 0xFFF9F0 + widgets: + + # ── Sidebar ────────────────────────────────────────────────────────── + - obj: + x: 0 + y: 0 + width: 172 + height: 480 + bg_color: 0x4D96FF + border_width: 0 + radius: 0 + pad_all: 0 + widgets: + - label: + x: 0 + y: 22 + width: 172 + align: TOP_MID + text: "😺" + text_font: font_title + - label: + x: 0 + y: 76 + width: 172 + align: TOP_MID + text: "Jordyn" + text_font: font_name + text_color: 0xFFFFFF + - bar: + id: progress_bar_jordyn + x: 14 + y: 132 + width: 144 + height: 16 + bg_color: 0x2A6FCC + indicator: + bg_color: 0xFFFFFF + value: 0 + min_value: 0 + max_value: 5 + - label: + id: progress_label_jordyn + x: 0 + y: 156 + width: 172 + align: TOP_MID + text: "0 / 5" + text_font: font_small + text_color: 0xDDEEFF + - label: + id: all_done_label_jordyn + x: 0 + y: 192 + width: 172 + align: TOP_MID + text: "" + text_font: font_small + text_color: 0xFFFFFF + - btn: + x: 14 + y: 364 + width: 144 + height: 44 + bg_color: 0xFF4757 + radius: 14 + on_click: + then: + - script.execute: reset_jordyn_chores + widgets: + - label: + align: CENTER + text: "↺ Reset" + text_color: 0xFFFFFF + text_font: font_small + - btn: + x: 14 + y: 420 + width: 144 + height: 44 + bg_color: 0x2A6FCC + radius: 14 + on_click: + then: + - lvgl.page.show: page_home + widgets: + - label: + align: CENTER + text: "◀ Home" + text_color: 0xFFFFFF + text_font: font_small + + # ── Chore cards ─────────────────────────────────────────────────────── + - btn: + id: card_jordyn_make_bed + x: 182 + y: 10 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: jordyn_make_bed + widgets: + - label: + id: check_jordyn_make_bed + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🛏️" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Make Bed" + text_font: font_small + text_color: 0x2D3436 + + - btn: + id: card_jordyn_brush_teeth + x: 388 + y: 10 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: jordyn_brush_teeth + widgets: + - label: + id: check_jordyn_brush_teeth + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🦷" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Brush Teeth" + text_font: font_small + text_color: 0x2D3436 + + - btn: + id: card_jordyn_tidy_room + x: 594 + y: 10 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: jordyn_tidy_room + widgets: + - label: + id: check_jordyn_tidy_room + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🧹" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Tidy Room" + text_font: font_small + text_color: 0x2D3436 + + - btn: + id: card_jordyn_homework + x: 182 + y: 158 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: jordyn_homework + widgets: + - label: + id: check_jordyn_homework + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "📚" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Homework" + text_font: font_small + text_color: 0x2D3436 + + - btn: + id: card_jordyn_feed_dog + x: 388 + y: 158 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: jordyn_feed_dog + widgets: + - label: + id: check_jordyn_feed_dog + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🐾" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Feed Dog" + text_font: font_small + text_color: 0x2D3436 + + + - id: page_declan + bg_color: 0xFFF9F0 + widgets: + + # ── Sidebar ────────────────────────────────────────────────────────── + - obj: + x: 0 + y: 0 + width: 172 + height: 480 + bg_color: 0xC77DFF + border_width: 0 + radius: 0 + pad_all: 0 + widgets: + - label: + x: 0 + y: 22 + width: 172 + align: TOP_MID + text: "🤓" + text_font: font_title + - label: + x: 0 + y: 76 + width: 172 + align: TOP_MID + text: "Declan" + text_font: font_name + text_color: 0xFFFFFF + - bar: + id: progress_bar_declan + x: 14 + y: 132 + width: 144 + height: 16 + bg_color: 0x8B42CC + indicator: + bg_color: 0xFFFFFF + value: 0 + min_value: 0 + max_value: 4 + - label: + id: progress_label_declan + x: 0 + y: 156 + width: 172 + align: TOP_MID + text: "0 / 4" + text_font: font_small + text_color: 0xDDEEFF + - label: + id: all_done_label_declan + x: 0 + y: 192 + width: 172 + align: TOP_MID + text: "" + text_font: font_small + text_color: 0xFFFFFF + - btn: + x: 14 + y: 364 + width: 144 + height: 44 + bg_color: 0xFF4757 + radius: 14 + on_click: + then: + - script.execute: reset_declan_chores + widgets: + - label: + align: CENTER + text: "↺ Reset" + text_color: 0xFFFFFF + text_font: font_small + - btn: + x: 14 + y: 420 + width: 144 + height: 44 + bg_color: 0x8B42CC + radius: 14 + on_click: + then: + - lvgl.page.show: page_home + widgets: + - label: + align: CENTER + text: "◀ Home" + text_color: 0xFFFFFF + text_font: font_small + + # ── Chore cards ─────────────────────────────────────────────────────── + - btn: + id: card_declan_make_bed + x: 182 + y: 10 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: declan_make_bed + widgets: + - label: + id: check_declan_make_bed + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🛏️" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Make Bed" + text_font: font_small + text_color: 0x2D3436 + + - btn: + id: card_declan_brush_teeth + x: 388 + y: 10 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: declan_brush_teeth + widgets: + - label: + id: check_declan_brush_teeth + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🦷" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Brush Teeth" + text_font: font_small + text_color: 0x2D3436 + + - btn: + id: card_declan_set_table + x: 594 + y: 10 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: declan_set_table + widgets: + - label: + id: check_declan_set_table + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🍽️" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Set Table" + text_font: font_small + text_color: 0x2D3436 + + - btn: + id: card_declan_take_out_trash + x: 182 + y: 158 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: declan_take_out_trash + widgets: + - label: + id: check_declan_take_out_trash + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🗑️" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Take Out Trash" + text_font: font_small + text_color: 0x2D3436 + + + - id: page_chloe + bg_color: 0xFFF9F0 + widgets: + + # ── Sidebar ────────────────────────────────────────────────────────── + - obj: + x: 0 + y: 0 + width: 172 + height: 480 + bg_color: 0xFF6B9D + border_width: 0 + radius: 0 + pad_all: 0 + widgets: + - label: + x: 0 + y: 22 + width: 172 + align: TOP_MID + text: "🌝" + text_font: font_title + - label: + x: 0 + y: 76 + width: 172 + align: TOP_MID + text: "Chloe" + text_font: font_name + text_color: 0xFFFFFF + - bar: + id: progress_bar_chloe + x: 14 + y: 132 + width: 144 + height: 16 + bg_color: 0xCC3A6F + indicator: + bg_color: 0xFFFFFF + value: 0 + min_value: 0 + max_value: 6 + - label: + id: progress_label_chloe + x: 0 + y: 156 + width: 172 + align: TOP_MID + text: "0 / 6" + text_font: font_small + text_color: 0xDDEEFF + - label: + id: all_done_label_chloe + x: 0 + y: 192 + width: 172 + align: TOP_MID + text: "" + text_font: font_small + text_color: 0xFFFFFF + - btn: + x: 14 + y: 364 + width: 144 + height: 44 + bg_color: 0xFF4757 + radius: 14 + on_click: + then: + - script.execute: reset_chloe_chores + widgets: + - label: + align: CENTER + text: "↺ Reset" + text_color: 0xFFFFFF + text_font: font_small + - btn: + x: 14 + y: 420 + width: 144 + height: 44 + bg_color: 0xCC3A6F + radius: 14 + on_click: + then: + - lvgl.page.show: page_home + widgets: + - label: + align: CENTER + text: "◀ Home" + text_color: 0xFFFFFF + text_font: font_small + + # ── Chore cards ─────────────────────────────────────────────────────── + - btn: + id: card_chloe_make_bed + x: 182 + y: 10 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: chloe_make_bed + widgets: + - label: + id: check_chloe_make_bed + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🛏️" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Make Bed" + text_font: font_small + text_color: 0x2D3436 + + - btn: + id: card_chloe_brush_teeth + x: 388 + y: 10 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: chloe_brush_teeth + widgets: + - label: + id: check_chloe_brush_teeth + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🦷" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Brush Teeth" + text_font: font_small + text_color: 0x2D3436 + + - btn: + id: card_chloe_water_plants + x: 594 + y: 10 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: chloe_water_plants + widgets: + - label: + id: check_chloe_water_plants + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🌱" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Water Plants" + text_font: font_small + text_color: 0x2D3436 + + - btn: + id: card_chloe_homework + x: 182 + y: 158 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: chloe_homework + widgets: + - label: + id: check_chloe_homework + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "📚" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Homework" + text_font: font_small + text_color: 0x2D3436 + + - btn: + id: card_chloe_tidy_room + x: 388 + y: 158 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: chloe_tidy_room + widgets: + - label: + id: check_chloe_tidy_room + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🧹" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Tidy Room" + text_font: font_small + text_color: 0x2D3436 + + - btn: + id: card_chloe_practice_piano + x: 594 + y: 158 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: chloe_practice_piano + widgets: + - label: + id: check_chloe_practice_piano + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🎹" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Practice Piano" + text_font: font_small + text_color: 0x2D3436 + + diff --git a/esphome/chore-tracker/chores_config.yaml b/esphome/chore-tracker/chores_config.yaml new file mode 100644 index 0000000..8f47785 --- /dev/null +++ b/esphome/chore-tracker/chores_config.yaml @@ -0,0 +1,70 @@ +################################################################################ +# chores_config.yaml — YOUR SINGLE SOURCE OF TRUTH +# +# Edit this file to change kids, chores, and settings. +# Then run: python3 generate.py +################################################################################ + +settings: + device_name: chore-tracker + friendly_name: "Chore Tracker" + wifi_ssid: !secret wifi_iot_ssid + wifi_password: !secret wifi_password + api_key: !secret api_encryption_key + ota_password: !secret ota_password + reset_time: "00:00:00" + reminder_time: "18:00" + notify_service: notify.notify + +# ── KIDS ────────────────────────────────────────────────────────────────────── +# Each kid has their own chore list. +# name, avatar, color, color_dark, and chores are all required. +# +kids: + - name: Jordyn + avatar: "😺" + color: "4D96FF" + color_dark: "2A6FCC" + chores: + - name: Make Bed + icon: "🛏️" + - name: Brush Teeth + icon: "🦷" + - name: Tidy Room + icon: "🧹" + - name: Homework + icon: "📚" + - name: Feed Dog + icon: "🐾" + + - name: Declan + avatar: "🤓" + color: "C77DFF" + color_dark: "8B42CC" + chores: + - name: Make Bed + icon: "🛏️" + - name: Brush Teeth + icon: "🦷" + - name: Set Table + icon: "🍽️" + - name: Take Out Trash + icon: "🗑️" + + - name: Chloe + avatar: "🌝" + color: "FF6B9D" + color_dark: "CC3A6F" + chores: + - name: Make Bed + icon: "🛏️" + - name: Brush Teeth + icon: "🦷" + - name: Water Plants + icon: "🌱" + - name: Homework + icon: "📚" + - name: Tidy Room + icon: "🧹" + - name: Practice Piano + icon: "🎹" \ No newline at end of file diff --git a/esphome/chore-tracker/generate.py b/esphome/chore-tracker/generate.py new file mode 100644 index 0000000..4038820 --- /dev/null +++ b/esphome/chore-tracker/generate.py @@ -0,0 +1,895 @@ +#!/usr/bin/env python3 +""" +generate.py — Chore Tracker Code Generator +========================================== +Reads chores_config.yaml and generates: + • chore-tracker-esphome.yaml (flash to ESP32 via ESPHome) + • chore-tracker-ha.yaml (Home Assistant config) + • chore-tracker-dashboard.yaml (Lovelace dashboard) + +Home screen behaviour: + - Each kid's button has a RED outline while any chores remain undone + - Button turns SOLID GREEN when ALL chores are complete + - Resets to red automatically at midnight + +No star tracking — chores are simply done or not done. + +Usage: + python3 generate.py + python3 generate.py --config my_other_config.yaml + python3 generate.py --out ./output_dir +""" + +import argparse +import sys +from pathlib import Path + +try: + import yaml +except ImportError: + print("PyYAML not found. Install it with: pip install pyyaml") + sys.exit(1) + + +# ───────────────────────────────────────────────────────────────────────────── +# Helpers +# ───────────────────────────────────────────────────────────────────────────── + +def slug(name: str) -> str: + return name.lower().replace(" ", "_").replace("-", "_") + +def kid_slug(kid: dict) -> str: + return slug(kid["name"]) + +def eid(kid: dict, chore: dict) -> str: + return f"{kid_slug(kid)}_{slug(chore['name'])}" + +def ha_switch(kid: dict, chore: dict) -> str: + return f"switch.chore_tracker_{eid(kid, chore)}" + +def get_chores(kid: dict) -> list: + """Each kid must define their own chore list.""" + return kid["chores"] + + +# ───────────────────────────────────────────────────────────────────────────── +# ESPHome generator +# ───────────────────────────────────────────────────────────────────────────── + +def gen_esphome(cfg: dict) -> str: + s = cfg["settings"] + kids = cfg["kids"] + + # ── Switches ────────────────────────────────────────────────────────────── + switch_blocks = [] + for kid in kids: + chores = get_chores(kid) + ks = kid_slug(kid) + switch_blocks.append(f"\n # ── {kid['name']}'s chores ──────────────────────────") + for chore in chores: + e = eid(kid, chore) + switch_blocks.append(f"""\ + - platform: template + name: "{kid['name']} - {chore['name']}" + id: {e} + icon: mdi:checkbox-marked-circle + optimistic: true + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + then: + - script.execute: update_{ks}_ui + - homeassistant.service: + service: switch.turn_on + data: + entity_id: switch.chore_tracker_{e} + on_turn_off: + then: + - script.execute: update_{ks}_ui + - homeassistant.service: + service: switch.turn_off + data: + entity_id: switch.chore_tracker_{e} +""") + + # ── Sensors (chores-done count only) ────────────────────────────────────── + sensor_blocks = [] + for kid in kids: + chores = get_chores(kid) + ks = kid_slug(kid) + done_lines = "\n".join( + f" if (id({eid(kid, c)}).state) done++;" for c in chores + ) + sensor_blocks.append(f"""\ + - platform: template + name: "{kid['name']} Chores Done" + id: {ks}_chores_done + accuracy_decimals: 0 + update_interval: 2s + lambda: |- + int done = 0; +{done_lines} + return done; + +""") + + # ── Midnight reset ──────────────────────────────────────────────────────── + reset_calls = "\n".join( + f" id(reset_{kid_slug(k)}_chores).execute();" + for k in kids + ) + + lvgl_pages = _gen_lvgl_pages(kids) + scripts = _gen_scripts(kids) + + return f"""\ +################################################################################ +# chore-tracker-esphome.yaml (AUTO-GENERATED — edit chores_config.yaml) +# Kids: {", ".join(k["name"] for k in kids)} +# +# HOME SCREEN BEHAVIOUR: +# Red outline = chores incomplete +# Solid green = all chores done ✓ +# Resets to red automatically at midnight +################################################################################ + +esphome: + name: {s["device_name"]} + friendly_name: "{s["friendly_name"]}" + +esp32: + board: esp32s3box + framework: + type: esp-idf + +wifi: + ssid: {s["wifi_ssid"]} + password: {s["wifi_password"]} + ap: + ssid: "{s['friendly_name']} Hotspot" + password: "choretracker" + +captive_portal: +logger: + level: INFO + +api: + encryption: + key: {s["api_key"]} + +ota: + - platform: esphome + password: {s["ota_password"]} + +# ── Display — Waveshare ESP32-S3 7" (adjust pins for your board revision) ───── +display: + - platform: rpi_dpi_rgb + id: main_display + auto_clear_enabled: false + color_order: RGB + dimensions: + width: 800 + height: 480 + de_pin: + number: GPIO40 + ignore_strapping_warning: true + hsync_pin: + number: GPIO39 + ignore_strapping_warning: true + 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: + - id: i2c_touch + sda: GPIO19 + scl: GPIO20 + frequency: 400kHz + +output: + - platform: ledc + pin: GPIO17 + id: backlight_output + +light: + - platform: monochromatic + output: backlight_output + name: "Display Backlight" + id: backlight + restore_mode: ALWAYS_ON + +# ── Midnight reset ──────────────────────────────────────────────────────────── +time: + - platform: homeassistant + id: ha_time + on_time: + - hours: 0 + minutes: 0 + seconds: 0 + then: + - lambda: |- +{reset_calls} + - lvgl.page.show: page_home + +fonts: + - file: "gfonts://Nunito:wght@900" + id: font_title + size: 40 + - file: "gfonts://Nunito:wght@800" + id: font_name + size: 30 + - file: "gfonts://Nunito:wght@700" + id: font_med + size: 22 + - file: "gfonts://Nunito:wght@600" + id: font_small + size: 17 + - file: "gfonts://Nunito:wght@600" + id: font_tiny + size: 13 + +# ── Switches — one per chore per kid, synced to HA ─────────────────────────── +switch: +{"".join(switch_blocks)} + +# ── Sensors — reported to HA ───────────────────────────────────────────────── +sensor: +{"".join(sensor_blocks)} + +# ── Scripts — reset + UI update ─────────────────────────────────────────────── +script: +{scripts} + +# ── LVGL UI ─────────────────────────────────────────────────────────────────── +lvgl: + displays: + - main_display + touchscreens: + - touch + theme: + btn: + radius: 20 + border_width: 0 + pages: +{lvgl_pages} +""" + + +# ───────────────────────────────────────────────────────────────────────────── +# LVGL page builder +# ───────────────────────────────────────────────────────────────────────────── + +def _gen_lvgl_pages(kids: list) -> str: + pages = [] + + # ── HOME PAGE ───────────────────────────────────────────────────────────── + n = len(kids) + btn_w = min(200, max(140, (760 - 20 * (n - 1)) // n)) + total_w = btn_w * n + 20 * (n - 1) + start_x = (800 - total_w) // 2 + btn_y = 130 + btn_h = 210 + + reset_all_calls = "\n".join( + f" - script.execute: reset_{kid_slug(k)}_chores" + for k in kids + ) + + home_btns = "" + for i, kid in enumerate(kids): + x = start_x + i * (btn_w + 20) + ks = kid_slug(kid) + home_btns += f"""\ + - btn: + id: home_btn_{ks} + x: {x} + y: {btn_y} + width: {btn_w} + height: {btn_h} + bg_color: 0xFFFFFF + bg_opa: TRANSP + border_color: 0xFF4757 + border_width: 5 + radius: 24 + on_click: + then: + - lvgl.page.show: page_{ks} + widgets: + - label: + align: CENTER + y: -45 + text: "{kid['avatar']}" + text_font: font_title + - label: + align: CENTER + y: 22 + text: "{kid['name']}" + text_font: font_name + text_color: 0x2D3436 + - label: + id: home_status_{ks} + align: CENTER + y: 66 + text: "not done" + text_font: font_tiny + text_color: 0xFF4757 + +""" + + pages.append(f"""\ + - id: page_home + bg_color: 0xFFF9F0 + widgets: + - label: + x: 0 + y: 36 + width: 800 + align: TOP_MID + text: "Chore Tracker" + text_font: font_title + text_color: 0x2D3436 + - label: + x: 0 + y: 90 + width: 800 + align: TOP_MID + text: "Tap a name to check off chores" + text_font: font_small + text_color: 0xB2BEC3 + - btn: + x: 640 + y: 424 + width: 148 + height: 40 + bg_color: 0xFF4757 + radius: 12 + on_click: + then: +{reset_all_calls} + widgets: + - label: + align: CENTER + text: "↺ Reset All" + text_color: 0xFFFFFF + text_font: font_tiny +{home_btns}""") + + # ── PER-KID CHORE PAGES ─────────────────────────────────────────────────── + for kid in kids: + chores = get_chores(kid) + ks = kid_slug(kid) + n_chores = len(chores) + + cols = 3 + rows = (n_chores + cols - 1) // cols + sidebar_w = 172 + gap = 10 + content_w = 800 - sidebar_w - gap * 2 + card_w = (content_w - gap * (cols - 1)) // cols + card_h = min(138, (480 - gap * (rows + 1)) // rows) + + card_widgets = "" + for idx, chore in enumerate(chores): + row = idx // cols + col = idx % cols + x = sidebar_w + gap + col * (card_w + gap) + y = gap + row * (card_h + gap) + e = eid(kid, chore) + icon_y = -(card_h // 4) + label_y = card_h // 8 + card_widgets += f"""\ + - btn: + id: card_{e} + x: {x} + y: {y} + width: {card_w} + height: {card_h} + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: {e} + widgets: + - label: + id: check_{e} + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: {icon_y} + text: "{chore['icon']}" + text_font: font_med + - label: + align: CENTER + y: {label_y} + text: "{chore['name']}" + text_font: font_small + text_color: 0x2D3436 + +""" + + pages.append(f"""\ + - id: page_{ks} + bg_color: 0xFFF9F0 + widgets: + + # ── Sidebar ────────────────────────────────────────────────────────── + - obj: + x: 0 + y: 0 + width: {sidebar_w} + height: 480 + bg_color: 0x{kid['color']} + border_width: 0 + radius: 0 + pad_all: 0 + widgets: + - label: + x: 0 + y: 22 + width: {sidebar_w} + align: TOP_MID + text: "{kid['avatar']}" + text_font: font_title + - label: + x: 0 + y: 76 + width: {sidebar_w} + align: TOP_MID + text: "{kid['name']}" + text_font: font_name + text_color: 0xFFFFFF + - bar: + id: progress_bar_{ks} + x: 14 + y: 132 + width: {sidebar_w - 28} + height: 16 + bg_color: 0x{kid['color_dark']} + indicator: + bg_color: 0xFFFFFF + value: 0 + min_value: 0 + max_value: {n_chores} + - label: + id: progress_label_{ks} + x: 0 + y: 156 + width: {sidebar_w} + align: TOP_MID + text: "0 / {n_chores}" + text_font: font_small + text_color: 0xDDEEFF + - label: + id: all_done_label_{ks} + x: 0 + y: 192 + width: {sidebar_w} + align: TOP_MID + text: "" + text_font: font_small + text_color: 0xFFFFFF + - btn: + x: 14 + y: 364 + width: {sidebar_w - 28} + height: 44 + bg_color: 0xFF4757 + radius: 14 + on_click: + then: + - script.execute: reset_{ks}_chores + widgets: + - label: + align: CENTER + text: "↺ Reset" + text_color: 0xFFFFFF + text_font: font_small + - btn: + x: 14 + y: 420 + width: {sidebar_w - 28} + height: 44 + bg_color: 0x{kid['color_dark']} + radius: 14 + on_click: + then: + - lvgl.page.show: page_home + widgets: + - label: + align: CENTER + text: "◀ Home" + text_color: 0xFFFFFF + text_font: font_small + + # ── Chore cards ─────────────────────────────────────────────────────── +{card_widgets}""") + + return "\n".join(pages) + + +# ───────────────────────────────────────────────────────────────────────────── +# Script builder +# ───────────────────────────────────────────────────────────────────────────── + +def _gen_scripts(kids: list) -> str: + blocks = [] + for kid in kids: + chores = get_chores(kid) + ks = kid_slug(kid) + n = len(chores) + + card_updates = "" + for chore in chores: + e = eid(kid, chore) + card_updates += f"""\ + if (id({e}).state) {{ + lv_obj_set_style_bg_color(id(card_{e}), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_{e}), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_{e}), 3, LV_PART_MAIN); + lv_label_set_text(id(check_{e}), "\\u2705"); + }} else {{ + lv_obj_set_style_bg_color(id(card_{e}), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_{e}), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_{e}), 2, LV_PART_MAIN); + lv_label_set_text(id(check_{e}), ""); + }} +""" + + count_done = " + ".join(f"(id({eid(kid,c)}).state ? 1 : 0)" for c in chores) + reset_lines = "\n".join( + f" id({eid(kid,c)}).turn_off();" for c in chores + ) + + # Reset script + blocks.append(f"""\ + - id: reset_{ks}_chores + mode: single + then: + - lambda: |- +{reset_lines} + - script.execute: update_{ks}_ui + +""") + + # UI update script + blocks.append(f"""\ + - id: update_{ks}_ui + mode: single + then: + - lambda: |- + int done = {count_done}; + int total = {n}; + char buf[24]; + + // Progress bar + label + lv_bar_set_value(id(progress_bar_{ks}), done, LV_ANIM_ON); + snprintf(buf, sizeof(buf), "%d / {n}", done); + lv_label_set_text(id(progress_label_{ks}), buf); + + // All-done message in sidebar + lv_label_set_text(id(all_done_label_{ks}), done == total ? "\\U0001F389 All done!" : ""); + + // Home button colour + if (done == total) {{ + 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_border_width(id(home_btn_{ks}), 0, LV_PART_MAIN); + lv_label_set_text(id(home_status_{ks}), "\\u2713 all done!"); + lv_obj_set_style_text_color(id(home_status_{ks}), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + }} else {{ + lv_obj_set_style_bg_opa(id(home_btn_{ks}), LV_OPA_TRANSP, LV_PART_MAIN); + lv_obj_set_style_border_color(id(home_btn_{ks}), lv_color_hex(0xFF4757), LV_PART_MAIN); + lv_obj_set_style_border_width(id(home_btn_{ks}), 5, LV_PART_MAIN); + snprintf(buf, sizeof(buf), "%d left", total - done); + lv_label_set_text(id(home_status_{ks}), buf); + lv_obj_set_style_text_color(id(home_status_{ks}), lv_color_hex(0xFF4757), LV_PART_MAIN); + }} + + // Card colours +{card_updates} +""") + + return "\n".join(blocks) + + +# ───────────────────────────────────────────────────────────────────────────── +# Home Assistant YAML generator +# ───────────────────────────────────────────────────────────────────────────── + +def gen_ha(cfg: dict) -> str: + s = cfg["settings"] + kids = cfg["kids"] + + sensor_blocks = [] + for kid in kids: + chores = get_chores(kid) + ks = kid_slug(kid) + n = len(chores) + states_list = ", ".join(f"states('{ha_switch(kid,c)}')" for c in chores) + + sensor_blocks.append(f"""\ + - name: "{kid['name']} Chores Done Today" + unique_id: {ks}_chores_done_today + icon: mdi:check-circle + state: > + {{% set chores = [{states_list}] %}} + {{{{ chores | select('equalto', 'on') | list | count }}}} + + - name: "{kid['name']} All Chores Done" + unique_id: {ks}_all_chores_done + icon: mdi:check-all + state: > + {{{{ states('sensor.{ks}_chores_done_today') | int == {n} }}}} + +""") + + # input_button helpers + input_buttons = "".join(f"""\ + {kid_slug(k)}_reset_chores: + name: "Reset {k['name']}'s Chores" + icon: mdi:restart +""" for k in kids) + input_buttons += """\ + reset_all_chores: + name: "Reset All Chores" + icon: mdi:restart-alert +""" + + # Automations + auto_blocks = [] + + # Per-kid HA reset button + for kid in kids: + ks = kid_slug(kid) + off_calls = "\n".join( + f" - service: switch.turn_off\n target:\n entity_id: {ha_switch(kid, c)}" + for c in get_chores(kid) + ) + auto_blocks.append(f"""\ + - id: {ks}_reset_from_ha + alias: "Chore Tracker — Reset {kid['name']}'s chores from HA" + trigger: + - platform: state + entity_id: input_button.{ks}_reset_chores + action: +{off_calls} + +""") + + # Reset All from HA + all_off_calls = "\n".join( + f" - service: switch.turn_off\n target:\n entity_id: {ha_switch(kid, c)}" + for kid in kids for c in get_chores(kid) + ) + auto_blocks.append(f"""\ + - id: reset_all_from_ha + alias: "Chore Tracker — Reset ALL chores from HA" + trigger: + - platform: state + entity_id: input_button.reset_all_chores + action: +{all_off_calls} + +""") + + # All-done notification + for kid in kids: + ks = kid_slug(kid) + n = len(get_chores(kid)) + auto_blocks.append(f"""\ + - id: {ks}_all_done_notify + alias: "Chore Tracker — {kid['name']} all done!" + trigger: + - platform: state + entity_id: sensor.{ks}_all_chores_done + to: "True" + action: + - service: {s['notify_service']} + data: + title: "🎉 {kid['name']} finished all chores!" + message: "{kid['name']} completed all {n} chores today!" + +""") + + # Evening reminder + reminder_actions = "".join(f"""\ + - if: + condition: template + value_template: "{{{{ states('sensor.{kid_slug(k)}_all_chores_done') != 'True' }}}}" + then: + - service: {s['notify_service']} + data: + title: "📋 {k['name']} has unfinished chores" + message: > + {k['name']} has done + {{{{ states('sensor.{kid_slug(k)}_chores_done_today') }}}}/{len(get_chores(k))} chores today. +""" for k in kids) + + auto_blocks.append(f"""\ + - id: chore_reminder_evening + alias: "Chore Tracker — Evening reminder" + trigger: + - platform: time + at: "{s['reminder_time']}:00" + action: +{reminder_actions} +""") + + return f"""\ +################################################################################ +# chore-tracker-ha.yaml (AUTO-GENERATED — edit chores_config.yaml) +# Kids: {", ".join(k["name"] for k in kids)} +# +# BIDIRECTIONAL SYNC: +# Screen → HA: Each switch calls homeassistant.service on toggle +# HA → Screen: ESPHome native API handles this automatically +################################################################################ + +input_button: +{input_buttons} +template: + - sensor: +{"".join(sensor_blocks)} +automation: +{"".join(auto_blocks)} +""" + + +# ───────────────────────────────────────────────────────────────────────────── +# Lovelace dashboard generator +# ───────────────────────────────────────────────────────────────────────────── + +def gen_dashboard(cfg: dict) -> str: + kids = cfg["kids"] + + summary_cards = "\n".join(f"""\ + - type: markdown + content: > + ### {kid['avatar']} {kid['name']} + {{{{ + '✅ 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' + }}}} +""" for kid in kids) + + chore_cards = [] + for kid in kids: + chores = get_chores(kid) + ks = kid_slug(kid) + chore_rows = "\n".join(f"""\ + - entity: {ha_switch(kid, c)} + name: "{c['icon']} {c['name']}" +""" for c in chores) + + chore_cards.append(f"""\ + - type: entities + title: "{kid['avatar']} {kid['name']}'s Chores" + entities: +{chore_rows} - type: divider + - entity: sensor.{ks}_chores_done_today + name: "Chores done today" + - entity: sensor.{ks}_all_chores_done + name: "✅ All Done?" + - type: button + name: "↺ Reset {kid['name']}'s Chores" + tap_action: + action: call-service + service: input_button.press + target: + entity_id: input_button.{ks}_reset_chores +""") + + return f"""\ +################################################################################ +# chore-tracker-dashboard.yaml (AUTO-GENERATED — edit chores_config.yaml) +# Kids: {", ".join(k["name"] for k in kids)} +################################################################################ + +title: "Chore Tracker" +views: + - title: Today + icon: mdi:checkbox-marked-circle + path: chores + cards: + - type: horizontal-stack + cards: +{summary_cards} + - type: button + name: "↺ Reset ALL Chores" + icon: mdi:restart-alert + tap_action: + action: call-service + service: input_button.press + target: + entity_id: input_button.reset_all_chores +{"".join(chore_cards)} +""" + + +# ───────────────────────────────────────────────────────────────────────────── +# Main +# ───────────────────────────────────────────────────────────────────────────── + +def main(): + parser = argparse.ArgumentParser(description="Chore Tracker config generator") + parser.add_argument("--config", default="chores_config.yaml") + parser.add_argument("--out", default=".") + args = parser.parse_args() + + config_path = Path(args.config) + if not config_path.exists(): + print(f"❌ Config not found: {config_path}") + sys.exit(1) + + out_dir = Path(args.out) + out_dir.mkdir(parents=True, exist_ok=True) + + class SecretLoader(yaml.SafeLoader): + pass + SecretLoader.add_constructor( + "!secret", + lambda loader, node: f"!secret {loader.construct_scalar(node)}" + ) + + with open(config_path) as f: + cfg = yaml.load(f, Loader=SecretLoader) + + kids = cfg.get("kids", []) + if not kids: + print("❌ No kids defined in config!") + 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"]] + if errors: + print(f"❌ These kids have no chores defined: {', '.join(errors)}") + print(" Add a 'chores:' list under each kid in chores_config.yaml") + sys.exit(1) + + total_chores = sum(len(get_chores(k)) for k in kids) + print(f"✅ Config loaded: {len(kids)} kid(s), {total_chores} total chores") + for k in kids: + chores = get_chores(k) + print(f" {k['avatar']} {k['name']}: {len(chores)} chores — {', '.join(c['name'] for c in chores)}") + print() + + files = { + "chore-tracker-esphome.yaml": gen_esphome(cfg), + "chore-tracker-ha.yaml": gen_ha(cfg), + "chore-tracker-dashboard.yaml": gen_dashboard(cfg), + } + + for name, content in files.items(): + path = out_dir / name + path.write_text(content) + print(f"📄 {path}") + + print() + print("✅ Done!") + print(" 1. Flash chore-tracker-esphome.yaml → ESPHome dashboard") + print(" 2. Merge chore-tracker-ha.yaml → HA config + restart HA") + print(" 3. Paste chore-tracker-dashboard.yaml → New HA dashboard") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/packages/chore-tracker-ha.yaml b/packages/chore-tracker-ha.yaml new file mode 100644 index 0000000..b4dd7d1 --- /dev/null +++ b/packages/chore-tracker-ha.yaml @@ -0,0 +1,258 @@ +################################################################################ +# chore-tracker-ha.yaml (AUTO-GENERATED — edit chores_config.yaml) +# Kids: Jordyn, Declan, Chloe +# +# BIDIRECTIONAL SYNC: +# Screen → HA: Each switch calls homeassistant.service on toggle +# HA → Screen: ESPHome native API handles this automatically +################################################################################ + +input_button: + jordyn_reset_chores: + name: "Reset Jordyn's Chores" + icon: mdi:restart + declan_reset_chores: + name: "Reset Declan's Chores" + icon: mdi:restart + chloe_reset_chores: + name: "Reset Chloe's Chores" + icon: mdi:restart + reset_all_chores: + name: "Reset All Chores" + icon: mdi:restart-alert + +template: + - sensor: + - name: "Jordyn Chores Done Today" + unique_id: jordyn_chores_done_today + icon: mdi:check-circle + state: > + {% set chores = [states('switch.chore_tracker_jordyn_make_bed'), states('switch.chore_tracker_jordyn_brush_teeth'), states('switch.chore_tracker_jordyn_tidy_room'), states('switch.chore_tracker_jordyn_homework'), states('switch.chore_tracker_jordyn_feed_dog')] %} + {{ chores | select('equalto', 'on') | list | count }} + + - name: "Jordyn All Chores Done" + unique_id: jordyn_all_chores_done + icon: mdi:check-all + state: > + {{ states('sensor.jordyn_chores_done_today') | int == 5 }} + + - name: "Declan Chores Done Today" + unique_id: declan_chores_done_today + icon: mdi:check-circle + state: > + {% set chores = [states('switch.chore_tracker_declan_make_bed'), states('switch.chore_tracker_declan_brush_teeth'), states('switch.chore_tracker_declan_set_table'), states('switch.chore_tracker_declan_take_out_trash')] %} + {{ chores | select('equalto', 'on') | list | count }} + + - name: "Declan All Chores Done" + unique_id: declan_all_chores_done + icon: mdi:check-all + state: > + {{ states('sensor.declan_chores_done_today') | int == 4 }} + + - name: "Chloe Chores Done Today" + unique_id: chloe_chores_done_today + icon: mdi:check-circle + state: > + {% set chores = [states('switch.chore_tracker_chloe_make_bed'), states('switch.chore_tracker_chloe_brush_teeth'), states('switch.chore_tracker_chloe_water_plants'), states('switch.chore_tracker_chloe_homework'), states('switch.chore_tracker_chloe_tidy_room'), states('switch.chore_tracker_chloe_practice_piano')] %} + {{ chores | select('equalto', 'on') | list | count }} + + - name: "Chloe All Chores Done" + unique_id: chloe_all_chores_done + icon: mdi:check-all + state: > + {{ states('sensor.chloe_chores_done_today') | int == 6 }} + + +automation: + - id: jordyn_reset_from_ha + alias: "Chore Tracker — Reset Jordyn's chores from HA" + trigger: + - platform: state + entity_id: input_button.jordyn_reset_chores + action: + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_jordyn_make_bed + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_jordyn_brush_teeth + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_jordyn_tidy_room + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_jordyn_homework + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_jordyn_feed_dog + + - id: declan_reset_from_ha + alias: "Chore Tracker — Reset Declan's chores from HA" + trigger: + - platform: state + entity_id: input_button.declan_reset_chores + action: + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_declan_make_bed + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_declan_brush_teeth + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_declan_set_table + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_declan_take_out_trash + + - id: chloe_reset_from_ha + alias: "Chore Tracker — Reset Chloe's chores from HA" + trigger: + - platform: state + entity_id: input_button.chloe_reset_chores + action: + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_chloe_make_bed + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_chloe_brush_teeth + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_chloe_water_plants + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_chloe_homework + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_chloe_tidy_room + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_chloe_practice_piano + + - id: reset_all_from_ha + alias: "Chore Tracker — Reset ALL chores from HA" + trigger: + - platform: state + entity_id: input_button.reset_all_chores + action: + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_jordyn_make_bed + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_jordyn_brush_teeth + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_jordyn_tidy_room + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_jordyn_homework + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_jordyn_feed_dog + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_declan_make_bed + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_declan_brush_teeth + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_declan_set_table + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_declan_take_out_trash + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_chloe_make_bed + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_chloe_brush_teeth + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_chloe_water_plants + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_chloe_homework + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_chloe_tidy_room + - service: switch.turn_off + target: + entity_id: switch.chore_tracker_chloe_practice_piano + + - id: jordyn_all_done_notify + alias: "Chore Tracker — Jordyn all done!" + trigger: + - platform: state + entity_id: sensor.jordyn_all_chores_done + to: "True" + action: + - service: notify.notify + data: + title: "🎉 Jordyn finished all chores!" + message: "Jordyn completed all 5 chores today!" + + - id: declan_all_done_notify + alias: "Chore Tracker — Declan all done!" + trigger: + - platform: state + entity_id: sensor.declan_all_chores_done + to: "True" + action: + - service: notify.notify + data: + title: "🎉 Declan finished all chores!" + message: "Declan completed all 4 chores today!" + + - id: chloe_all_done_notify + alias: "Chore Tracker — Chloe all done!" + trigger: + - platform: state + entity_id: sensor.chloe_all_chores_done + to: "True" + action: + - service: notify.notify + data: + title: "🎉 Chloe finished all chores!" + message: "Chloe completed all 6 chores today!" + + - id: chore_reminder_evening + alias: "Chore Tracker — Evening reminder" + trigger: + - platform: time + at: "18:00:00" + action: + - if: + condition: template + value_template: "{{ states('sensor.jordyn_all_chores_done') != 'True' }}" + then: + - service: notify.notify + data: + title: "📋 Jordyn has unfinished chores" + message: > + Jordyn has done + {{ states('sensor.jordyn_chores_done_today') }}/5 chores today. + - if: + condition: template + value_template: "{{ states('sensor.declan_all_chores_done') != 'True' }}" + then: + - service: notify.notify + data: + title: "📋 Declan has unfinished chores" + message: > + Declan has done + {{ states('sensor.declan_chores_done_today') }}/4 chores today. + - if: + condition: template + value_template: "{{ states('sensor.chloe_all_chores_done') != 'True' }}" + then: + - service: notify.notify + data: + title: "📋 Chloe has unfinished chores" + message: > + Chloe has done + {{ states('sensor.chloe_chores_done_today') }}/6 chores today. + + From f60e040bc7586ed3bb00339fc01ddc7eb5b6bb2c Mon Sep 17 00:00:00 2001 From: Joshua King Date: Fri, 27 Feb 2026 21:54:59 -0500 Subject: [PATCH 2/2] Refactor code structure for improved readability and maintainability --- esphome/chore-tracker-esphome.yaml | 2527 +++++------------ .../chore-tracker/chore-tracker-esphome.yaml | 1757 ------------ 2 files changed, 668 insertions(+), 3616 deletions(-) delete mode 100644 esphome/chore-tracker/chore-tracker-esphome.yaml diff --git a/esphome/chore-tracker-esphome.yaml b/esphome/chore-tracker-esphome.yaml index 8ceaa22..3ef805f 100644 --- a/esphome/chore-tracker-esphome.yaml +++ b/esphome/chore-tracker-esphome.yaml @@ -1,6 +1,6 @@ ################################################################################ # chore-tracker-esphome.yaml (AUTO-GENERATED — edit chores_config.yaml) -# Kids: Emma, Liam, Zoe +# Kids: Jordyn, Declan, Chloe # # HOME SCREEN BEHAVIOUR: # Red outline = chores incomplete @@ -18,7 +18,7 @@ esp32: type: esp-idf wifi: - ssid: !secret wifi_ssid + ssid: !secret wifi_iot_ssid password: !secret wifi_password ap: ssid: "Chore Tracker Hotspot" @@ -85,7 +85,7 @@ light: id: backlight restore_mode: ALWAYS_ON -# ── Time: drives the daily reset ───────────────────────────────────────────── +# ── Midnight reset ──────────────────────────────────────────────────────────── time: - platform: homeassistant id: ha_time @@ -95,10 +95,9 @@ time: seconds: 0 then: - lambda: |- - // Reset all kids via named scripts (resets switches + refreshes UI) - id(reset_emma_chores).execute(); - id(reset_liam_chores).execute(); - id(reset_zoe_chores).execute(); + id(reset_jordyn_chores).execute(); + id(reset_declan_chores).execute(); + id(reset_chloe_chores).execute(); - lvgl.page.show: page_home fonts: @@ -121,1162 +120,661 @@ fonts: # ── Switches — one per chore per kid, synced to HA ─────────────────────────── switch: - # ── Emma's chores ────────────────────────── - platform: template - name: "Emma - Make Bed" - id: emma_make_bed - icon: mdi:star + # ── Jordyn's chores ────────────────────────── - platform: template + name: "Jordyn - Make Bed" + id: jordyn_make_bed + icon: mdi:checkbox-marked-circle optimistic: true restore_mode: RESTORE_DEFAULT_OFF on_turn_on: then: - - script.execute: update_emma_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_jordyn_ui - homeassistant.service: service: switch.turn_on data: - entity_id: switch.chore_tracker_emma_make_bed + entity_id: switch.chore_tracker_jordyn_make_bed on_turn_off: then: - - script.execute: update_emma_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_jordyn_ui - homeassistant.service: service: switch.turn_off data: - entity_id: switch.chore_tracker_emma_make_bed + entity_id: switch.chore_tracker_jordyn_make_bed - platform: template - name: "Emma - Brush Teeth" - id: emma_brush_teeth - icon: mdi:star + name: "Jordyn - Brush Teeth" + id: jordyn_brush_teeth + icon: mdi:checkbox-marked-circle optimistic: true restore_mode: RESTORE_DEFAULT_OFF on_turn_on: then: - - script.execute: update_emma_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_jordyn_ui - homeassistant.service: service: switch.turn_on data: - entity_id: switch.chore_tracker_emma_brush_teeth + entity_id: switch.chore_tracker_jordyn_brush_teeth on_turn_off: then: - - script.execute: update_emma_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_jordyn_ui - homeassistant.service: service: switch.turn_off data: - entity_id: switch.chore_tracker_emma_brush_teeth + entity_id: switch.chore_tracker_jordyn_brush_teeth - platform: template - name: "Emma - Tidy Room" - id: emma_tidy_room - icon: mdi:star + name: "Jordyn - Tidy Room" + id: jordyn_tidy_room + icon: mdi:checkbox-marked-circle optimistic: true restore_mode: RESTORE_DEFAULT_OFF on_turn_on: then: - - script.execute: update_emma_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_jordyn_ui - homeassistant.service: service: switch.turn_on data: - entity_id: switch.chore_tracker_emma_tidy_room + entity_id: switch.chore_tracker_jordyn_tidy_room on_turn_off: then: - - script.execute: update_emma_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_jordyn_ui - homeassistant.service: service: switch.turn_off data: - entity_id: switch.chore_tracker_emma_tidy_room + entity_id: switch.chore_tracker_jordyn_tidy_room - platform: template - name: "Emma - Homework" - id: emma_homework - icon: mdi:star + name: "Jordyn - Homework" + id: jordyn_homework + icon: mdi:checkbox-marked-circle optimistic: true restore_mode: RESTORE_DEFAULT_OFF on_turn_on: then: - - script.execute: update_emma_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_jordyn_ui - homeassistant.service: service: switch.turn_on data: - entity_id: switch.chore_tracker_emma_homework + entity_id: switch.chore_tracker_jordyn_homework on_turn_off: then: - - script.execute: update_emma_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_jordyn_ui - homeassistant.service: service: switch.turn_off data: - entity_id: switch.chore_tracker_emma_homework + entity_id: switch.chore_tracker_jordyn_homework - platform: template - name: "Emma - Set Table" - id: emma_set_table - icon: mdi:star + name: "Jordyn - Feed Dog" + id: jordyn_feed_dog + icon: mdi:checkbox-marked-circle optimistic: true restore_mode: RESTORE_DEFAULT_OFF on_turn_on: then: - - script.execute: update_emma_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_jordyn_ui - homeassistant.service: service: switch.turn_on data: - entity_id: switch.chore_tracker_emma_set_table + entity_id: switch.chore_tracker_jordyn_feed_dog on_turn_off: then: - - script.execute: update_emma_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_jordyn_ui - homeassistant.service: service: switch.turn_off data: - entity_id: switch.chore_tracker_emma_set_table - - platform: template - name: "Emma - Take Out Trash" - id: emma_take_out_trash - icon: mdi:star - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_emma_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_emma_take_out_trash - on_turn_off: - then: - - script.execute: update_emma_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_emma_take_out_trash - - platform: template - name: "Emma - Feed Pet" - id: emma_feed_pet - icon: mdi:star - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_emma_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_emma_feed_pet - on_turn_off: - then: - - script.execute: update_emma_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_emma_feed_pet - - platform: template - name: "Emma - Water Plants" - id: emma_water_plants - icon: mdi:star - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_emma_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_emma_water_plants - on_turn_off: - then: - - script.execute: update_emma_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_emma_water_plants + entity_id: switch.chore_tracker_jordyn_feed_dog - # ── Liam's chores ────────────────────────── - platform: template - name: "Liam - Make Bed" - id: liam_make_bed - icon: mdi:star + # ── Declan's chores ────────────────────────── - platform: template + name: "Declan - Make Bed" + id: declan_make_bed + icon: mdi:checkbox-marked-circle optimistic: true restore_mode: RESTORE_DEFAULT_OFF on_turn_on: then: - - script.execute: update_liam_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_declan_ui - homeassistant.service: service: switch.turn_on data: - entity_id: switch.chore_tracker_liam_make_bed + entity_id: switch.chore_tracker_declan_make_bed on_turn_off: then: - - script.execute: update_liam_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_declan_ui - homeassistant.service: service: switch.turn_off data: - entity_id: switch.chore_tracker_liam_make_bed + entity_id: switch.chore_tracker_declan_make_bed - platform: template - name: "Liam - Brush Teeth" - id: liam_brush_teeth - icon: mdi:star + name: "Declan - Brush Teeth" + id: declan_brush_teeth + icon: mdi:checkbox-marked-circle optimistic: true restore_mode: RESTORE_DEFAULT_OFF on_turn_on: then: - - script.execute: update_liam_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_declan_ui - homeassistant.service: service: switch.turn_on data: - entity_id: switch.chore_tracker_liam_brush_teeth + entity_id: switch.chore_tracker_declan_brush_teeth on_turn_off: then: - - script.execute: update_liam_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_declan_ui - homeassistant.service: service: switch.turn_off data: - entity_id: switch.chore_tracker_liam_brush_teeth + entity_id: switch.chore_tracker_declan_brush_teeth - platform: template - name: "Liam - Tidy Room" - id: liam_tidy_room - icon: mdi:star + name: "Declan - Set Table" + id: declan_set_table + icon: mdi:checkbox-marked-circle optimistic: true restore_mode: RESTORE_DEFAULT_OFF on_turn_on: then: - - script.execute: update_liam_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_declan_ui - homeassistant.service: service: switch.turn_on data: - entity_id: switch.chore_tracker_liam_tidy_room + entity_id: switch.chore_tracker_declan_set_table on_turn_off: then: - - script.execute: update_liam_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_declan_ui - homeassistant.service: service: switch.turn_off data: - entity_id: switch.chore_tracker_liam_tidy_room + entity_id: switch.chore_tracker_declan_set_table - platform: template - name: "Liam - Homework" - id: liam_homework - icon: mdi:star + name: "Declan - Take Out Trash" + id: declan_take_out_trash + icon: mdi:checkbox-marked-circle optimistic: true restore_mode: RESTORE_DEFAULT_OFF on_turn_on: then: - - script.execute: update_liam_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_declan_ui - homeassistant.service: service: switch.turn_on data: - entity_id: switch.chore_tracker_liam_homework + entity_id: switch.chore_tracker_declan_take_out_trash on_turn_off: then: - - script.execute: update_liam_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_declan_ui - homeassistant.service: service: switch.turn_off data: - entity_id: switch.chore_tracker_liam_homework - - platform: template - name: "Liam - Set Table" - id: liam_set_table - icon: mdi:star - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_liam_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_liam_set_table - on_turn_off: - then: - - script.execute: update_liam_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_liam_set_table - - platform: template - name: "Liam - Take Out Trash" - id: liam_take_out_trash - icon: mdi:star - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_liam_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_liam_take_out_trash - on_turn_off: - then: - - script.execute: update_liam_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_liam_take_out_trash - - platform: template - name: "Liam - Feed Pet" - id: liam_feed_pet - icon: mdi:star - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_liam_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_liam_feed_pet - on_turn_off: - then: - - script.execute: update_liam_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_liam_feed_pet - - platform: template - name: "Liam - Water Plants" - id: liam_water_plants - icon: mdi:star - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_liam_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_liam_water_plants - on_turn_off: - then: - - script.execute: update_liam_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_liam_water_plants + entity_id: switch.chore_tracker_declan_take_out_trash - # ── Zoe's chores ────────────────────────── - platform: template - name: "Zoe - Make Bed" - id: zoe_make_bed - icon: mdi:star + # ── Chloe's chores ────────────────────────── - platform: template + name: "Chloe - Make Bed" + id: chloe_make_bed + icon: mdi:checkbox-marked-circle optimistic: true restore_mode: RESTORE_DEFAULT_OFF on_turn_on: then: - - script.execute: update_zoe_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_chloe_ui - homeassistant.service: service: switch.turn_on data: - entity_id: switch.chore_tracker_zoe_make_bed + entity_id: switch.chore_tracker_chloe_make_bed on_turn_off: then: - - script.execute: update_zoe_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_chloe_ui - homeassistant.service: service: switch.turn_off data: - entity_id: switch.chore_tracker_zoe_make_bed + entity_id: switch.chore_tracker_chloe_make_bed - platform: template - name: "Zoe - Brush Teeth" - id: zoe_brush_teeth - icon: mdi:star + name: "Chloe - Brush Teeth" + id: chloe_brush_teeth + icon: mdi:checkbox-marked-circle optimistic: true restore_mode: RESTORE_DEFAULT_OFF on_turn_on: then: - - script.execute: update_zoe_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_chloe_ui - homeassistant.service: service: switch.turn_on data: - entity_id: switch.chore_tracker_zoe_brush_teeth + entity_id: switch.chore_tracker_chloe_brush_teeth on_turn_off: then: - - script.execute: update_zoe_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_chloe_ui - homeassistant.service: service: switch.turn_off data: - entity_id: switch.chore_tracker_zoe_brush_teeth + entity_id: switch.chore_tracker_chloe_brush_teeth - platform: template - name: "Zoe - Tidy Room" - id: zoe_tidy_room - icon: mdi:star + name: "Chloe - Water Plants" + id: chloe_water_plants + icon: mdi:checkbox-marked-circle optimistic: true restore_mode: RESTORE_DEFAULT_OFF on_turn_on: then: - - script.execute: update_zoe_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_chloe_ui - homeassistant.service: service: switch.turn_on data: - entity_id: switch.chore_tracker_zoe_tidy_room + entity_id: switch.chore_tracker_chloe_water_plants on_turn_off: then: - - script.execute: update_zoe_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_chloe_ui - homeassistant.service: service: switch.turn_off data: - entity_id: switch.chore_tracker_zoe_tidy_room + entity_id: switch.chore_tracker_chloe_water_plants - platform: template - name: "Zoe - Homework" - id: zoe_homework - icon: mdi:star + name: "Chloe - Homework" + id: chloe_homework + icon: mdi:checkbox-marked-circle optimistic: true restore_mode: RESTORE_DEFAULT_OFF on_turn_on: then: - - script.execute: update_zoe_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_chloe_ui - homeassistant.service: service: switch.turn_on data: - entity_id: switch.chore_tracker_zoe_homework + entity_id: switch.chore_tracker_chloe_homework on_turn_off: then: - - script.execute: update_zoe_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_chloe_ui - homeassistant.service: service: switch.turn_off data: - entity_id: switch.chore_tracker_zoe_homework + entity_id: switch.chore_tracker_chloe_homework - platform: template - name: "Zoe - Set Table" - id: zoe_set_table - icon: mdi:star + name: "Chloe - Tidy Room" + id: chloe_tidy_room + icon: mdi:checkbox-marked-circle optimistic: true restore_mode: RESTORE_DEFAULT_OFF on_turn_on: then: - - script.execute: update_zoe_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_chloe_ui - homeassistant.service: service: switch.turn_on data: - entity_id: switch.chore_tracker_zoe_set_table + entity_id: switch.chore_tracker_chloe_tidy_room on_turn_off: then: - - script.execute: update_zoe_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_chloe_ui - homeassistant.service: service: switch.turn_off data: - entity_id: switch.chore_tracker_zoe_set_table + entity_id: switch.chore_tracker_chloe_tidy_room - platform: template - name: "Zoe - Take Out Trash" - id: zoe_take_out_trash - icon: mdi:star + name: "Chloe - Practice Piano" + id: chloe_practice_piano + icon: mdi:checkbox-marked-circle optimistic: true restore_mode: RESTORE_DEFAULT_OFF on_turn_on: then: - - script.execute: update_zoe_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_chloe_ui - homeassistant.service: service: switch.turn_on data: - entity_id: switch.chore_tracker_zoe_take_out_trash + entity_id: switch.chore_tracker_chloe_practice_piano on_turn_off: then: - - script.execute: update_zoe_ui - # Push to HA so it stays in sync when toggled on the screen + - script.execute: update_chloe_ui - homeassistant.service: service: switch.turn_off data: - entity_id: switch.chore_tracker_zoe_take_out_trash - - platform: template - name: "Zoe - Feed Pet" - id: zoe_feed_pet - icon: mdi:star - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_zoe_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_zoe_feed_pet - on_turn_off: - then: - - script.execute: update_zoe_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_zoe_feed_pet - - platform: template - name: "Zoe - Water Plants" - id: zoe_water_plants - icon: mdi:star - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_zoe_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_zoe_water_plants - on_turn_off: - then: - - script.execute: update_zoe_ui - # Push to HA so it stays in sync when toggled on the screen - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_zoe_water_plants + entity_id: switch.chore_tracker_chloe_practice_piano # ── Sensors — reported to HA ───────────────────────────────────────────────── sensor: - platform: template - name: "Emma Chores Done" - id: emma_chores_done + name: "Jordyn Chores Done" + id: jordyn_chores_done accuracy_decimals: 0 update_interval: 2s lambda: |- int done = 0; - if (id(emma_make_bed).state) done++; - if (id(emma_brush_teeth).state) done++; - if (id(emma_tidy_room).state) done++; - if (id(emma_homework).state) done++; - if (id(emma_set_table).state) done++; - if (id(emma_take_out_trash).state) done++; - if (id(emma_feed_pet).state) done++; - if (id(emma_water_plants).state) done++; + if (id(jordyn_make_bed).state) done++; + if (id(jordyn_brush_teeth).state) done++; + if (id(jordyn_tidy_room).state) done++; + if (id(jordyn_homework).state) done++; + if (id(jordyn_feed_dog).state) done++; return done; - platform: template - name: "Emma Stars Today" - id: emma_stars - unit_of_measurement: "stars" - accuracy_decimals: 0 - update_interval: 2s - lambda: |- - int stars = 0; - if (id(emma_make_bed).state) stars += 1; - if (id(emma_brush_teeth).state) stars += 1; - if (id(emma_tidy_room).state) stars += 2; - if (id(emma_homework).state) stars += 3; - if (id(emma_set_table).state) stars += 1; - if (id(emma_take_out_trash).state) stars += 2; - if (id(emma_feed_pet).state) stars += 1; - if (id(emma_water_plants).state) stars += 1; - return stars; - - - platform: template - name: "Liam Chores Done" - id: liam_chores_done + name: "Declan Chores Done" + id: declan_chores_done accuracy_decimals: 0 update_interval: 2s lambda: |- int done = 0; - if (id(liam_make_bed).state) done++; - if (id(liam_brush_teeth).state) done++; - if (id(liam_tidy_room).state) done++; - if (id(liam_homework).state) done++; - if (id(liam_set_table).state) done++; - if (id(liam_take_out_trash).state) done++; - if (id(liam_feed_pet).state) done++; - if (id(liam_water_plants).state) done++; + if (id(declan_make_bed).state) done++; + if (id(declan_brush_teeth).state) done++; + if (id(declan_set_table).state) done++; + if (id(declan_take_out_trash).state) done++; return done; - platform: template - name: "Liam Stars Today" - id: liam_stars - unit_of_measurement: "stars" - accuracy_decimals: 0 - update_interval: 2s - lambda: |- - int stars = 0; - if (id(liam_make_bed).state) stars += 1; - if (id(liam_brush_teeth).state) stars += 1; - if (id(liam_tidy_room).state) stars += 2; - if (id(liam_homework).state) stars += 3; - if (id(liam_set_table).state) stars += 1; - if (id(liam_take_out_trash).state) stars += 2; - if (id(liam_feed_pet).state) stars += 1; - if (id(liam_water_plants).state) stars += 1; - return stars; - - - platform: template - name: "Zoe Chores Done" - id: zoe_chores_done + name: "Chloe Chores Done" + id: chloe_chores_done accuracy_decimals: 0 update_interval: 2s lambda: |- int done = 0; - if (id(zoe_make_bed).state) done++; - if (id(zoe_brush_teeth).state) done++; - if (id(zoe_tidy_room).state) done++; - if (id(zoe_homework).state) done++; - if (id(zoe_set_table).state) done++; - if (id(zoe_take_out_trash).state) done++; - if (id(zoe_feed_pet).state) done++; - if (id(zoe_water_plants).state) done++; + if (id(chloe_make_bed).state) done++; + if (id(chloe_brush_teeth).state) done++; + if (id(chloe_water_plants).state) done++; + if (id(chloe_homework).state) done++; + if (id(chloe_tidy_room).state) done++; + if (id(chloe_practice_piano).state) done++; return done; - - platform: template - name: "Zoe Stars Today" - id: zoe_stars - unit_of_measurement: "stars" - accuracy_decimals: 0 - update_interval: 2s - lambda: |- - int stars = 0; - if (id(zoe_make_bed).state) stars += 1; - if (id(zoe_brush_teeth).state) stars += 1; - if (id(zoe_tidy_room).state) stars += 2; - if (id(zoe_homework).state) stars += 3; - if (id(zoe_set_table).state) stars += 1; - if (id(zoe_take_out_trash).state) stars += 2; - if (id(zoe_feed_pet).state) stars += 1; - if (id(zoe_water_plants).state) stars += 1; - return stars; - -# ── Scripts — update LVGL visuals when chore state changes ─────────────────── +# ── Scripts — reset + UI update ─────────────────────────────────────────────── script: - # Reset all of Emma's chores (used by manual reset button + midnight) - - id: reset_emma_chores + - id: reset_jordyn_chores mode: single then: - lambda: |- - id(emma_make_bed).turn_off(); - id(emma_brush_teeth).turn_off(); - id(emma_tidy_room).turn_off(); - id(emma_homework).turn_off(); - id(emma_set_table).turn_off(); - id(emma_take_out_trash).turn_off(); - id(emma_feed_pet).turn_off(); - id(emma_water_plants).turn_off(); - - script.execute: update_emma_ui + id(jordyn_make_bed).turn_off(); + id(jordyn_brush_teeth).turn_off(); + id(jordyn_tidy_room).turn_off(); + id(jordyn_homework).turn_off(); + id(jordyn_feed_dog).turn_off(); + - script.execute: update_jordyn_ui - - id: update_emma_ui + - id: update_jordyn_ui mode: single then: - lambda: |- - int done = (id(emma_make_bed).state ? 1 : 0) + (id(emma_brush_teeth).state ? 1 : 0) + (id(emma_tidy_room).state ? 1 : 0) + (id(emma_homework).state ? 1 : 0) + (id(emma_set_table).state ? 1 : 0) + (id(emma_take_out_trash).state ? 1 : 0) + (id(emma_feed_pet).state ? 1 : 0) + (id(emma_water_plants).state ? 1 : 0); - int stars = (id(emma_make_bed).state ? 1 : 0) + (id(emma_brush_teeth).state ? 1 : 0) + (id(emma_tidy_room).state ? 2 : 0) + (id(emma_homework).state ? 3 : 0) + (id(emma_set_table).state ? 1 : 0) + (id(emma_take_out_trash).state ? 2 : 0) + (id(emma_feed_pet).state ? 1 : 0) + (id(emma_water_plants).state ? 1 : 0); - int total = 8; + int done = (id(jordyn_make_bed).state ? 1 : 0) + (id(jordyn_brush_teeth).state ? 1 : 0) + (id(jordyn_tidy_room).state ? 1 : 0) + (id(jordyn_homework).state ? 1 : 0) + (id(jordyn_feed_dog).state ? 1 : 0); + int total = 5; + char buf[24]; - // ── Sidebar progress & stars ────────────────────────────────────── - lv_bar_set_value(id(progress_bar_emma), done, LV_ANIM_ON); - char buf[32]; - snprintf(buf, sizeof(buf), "%d / 8", done); - lv_label_set_text(id(progress_label_emma), buf); - snprintf(buf, sizeof(buf), "⭐ %d star%s", stars, stars == 1 ? "" : "s"); - lv_label_set_text(id(sidebar_stars_emma), buf); + // Progress bar + label + lv_bar_set_value(id(progress_bar_jordyn), done, LV_ANIM_ON); + snprintf(buf, sizeof(buf), "%d / 5", done); + lv_label_set_text(id(progress_label_jordyn), buf); - // ── All-done celebration text ───────────────────────────────────── + // All-done message in sidebar + lv_label_set_text(id(all_done_label_jordyn), done == total ? "\U0001F389 All done!" : ""); + + // Home button colour if (done == total) { - lv_label_set_text(id(all_done_label_emma), "🎉 All done!"); + 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_border_width(id(home_btn_jordyn), 0, LV_PART_MAIN); + lv_label_set_text(id(home_status_jordyn), "\u2713 all done!"); + lv_obj_set_style_text_color(id(home_status_jordyn), lv_color_hex(0xFFFFFF), LV_PART_MAIN); } else { - lv_label_set_text(id(all_done_label_emma), ""); - } - - // ── Home screen button: RED outline = incomplete, GREEN = complete ─ - if (done == total) { - // Solid green — all chores done - lv_obj_set_style_bg_opa(id(home_btn_emma), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_bg_color(id(home_btn_emma), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(home_btn_emma), 0, LV_PART_MAIN); - lv_label_set_text(id(home_status_emma), "✓ all done!"); - lv_obj_set_style_text_color(id(home_status_emma), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - } else { - // Transparent fill with red border — incomplete - lv_obj_set_style_bg_opa(id(home_btn_emma), LV_OPA_TRANSP, LV_PART_MAIN); - lv_obj_set_style_border_color(id(home_btn_emma), lv_color_hex(0xFF4757), LV_PART_MAIN); - lv_obj_set_style_border_width(id(home_btn_emma), 5, LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(home_btn_jordyn), LV_OPA_TRANSP, LV_PART_MAIN); + lv_obj_set_style_border_color(id(home_btn_jordyn), lv_color_hex(0xFF4757), LV_PART_MAIN); + lv_obj_set_style_border_width(id(home_btn_jordyn), 5, LV_PART_MAIN); snprintf(buf, sizeof(buf), "%d left", total - done); - lv_label_set_text(id(home_status_emma), buf); - lv_obj_set_style_text_color(id(home_status_emma), lv_color_hex(0xFF4757), LV_PART_MAIN); + lv_label_set_text(id(home_status_jordyn), buf); + lv_obj_set_style_text_color(id(home_status_jordyn), lv_color_hex(0xFF4757), LV_PART_MAIN); } - // ── Individual chore card colours ───────────────────────────────── - // Make Bed - if (id(emma_make_bed).state) { - lv_obj_set_style_bg_color(id(card_emma_make_bed), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_emma_make_bed), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_emma_make_bed), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_emma_make_bed), 3, LV_PART_MAIN); - lv_label_set_text(id(check_emma_make_bed), "✅"); + // Card colours + if (id(jordyn_make_bed).state) { + lv_obj_set_style_bg_color(id(card_jordyn_make_bed), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_make_bed), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_make_bed), 3, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_make_bed), "\u2705"); } else { - lv_obj_set_style_bg_color(id(card_emma_make_bed), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_emma_make_bed), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_emma_make_bed), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_emma_make_bed), 2, LV_PART_MAIN); - lv_label_set_text(id(check_emma_make_bed), ""); + lv_obj_set_style_bg_color(id(card_jordyn_make_bed), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_make_bed), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_make_bed), 2, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_make_bed), ""); } - // Brush Teeth - if (id(emma_brush_teeth).state) { - lv_obj_set_style_bg_color(id(card_emma_brush_teeth), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_emma_brush_teeth), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_emma_brush_teeth), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_emma_brush_teeth), 3, LV_PART_MAIN); - lv_label_set_text(id(check_emma_brush_teeth), "✅"); + if (id(jordyn_brush_teeth).state) { + lv_obj_set_style_bg_color(id(card_jordyn_brush_teeth), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_brush_teeth), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_brush_teeth), 3, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_brush_teeth), "\u2705"); } else { - lv_obj_set_style_bg_color(id(card_emma_brush_teeth), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_emma_brush_teeth), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_emma_brush_teeth), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_emma_brush_teeth), 2, LV_PART_MAIN); - lv_label_set_text(id(check_emma_brush_teeth), ""); + lv_obj_set_style_bg_color(id(card_jordyn_brush_teeth), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_brush_teeth), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_brush_teeth), 2, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_brush_teeth), ""); } - // Tidy Room - if (id(emma_tidy_room).state) { - lv_obj_set_style_bg_color(id(card_emma_tidy_room), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_emma_tidy_room), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_emma_tidy_room), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_emma_tidy_room), 3, LV_PART_MAIN); - lv_label_set_text(id(check_emma_tidy_room), "✅"); + if (id(jordyn_tidy_room).state) { + lv_obj_set_style_bg_color(id(card_jordyn_tidy_room), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_tidy_room), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_tidy_room), 3, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_tidy_room), "\u2705"); } else { - lv_obj_set_style_bg_color(id(card_emma_tidy_room), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_emma_tidy_room), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_emma_tidy_room), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_emma_tidy_room), 2, LV_PART_MAIN); - lv_label_set_text(id(check_emma_tidy_room), ""); + lv_obj_set_style_bg_color(id(card_jordyn_tidy_room), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_tidy_room), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_tidy_room), 2, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_tidy_room), ""); } - // Homework - if (id(emma_homework).state) { - lv_obj_set_style_bg_color(id(card_emma_homework), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_emma_homework), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_emma_homework), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_emma_homework), 3, LV_PART_MAIN); - lv_label_set_text(id(check_emma_homework), "✅"); + if (id(jordyn_homework).state) { + lv_obj_set_style_bg_color(id(card_jordyn_homework), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_homework), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_homework), 3, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_homework), "\u2705"); } else { - lv_obj_set_style_bg_color(id(card_emma_homework), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_emma_homework), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_emma_homework), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_emma_homework), 2, LV_PART_MAIN); - lv_label_set_text(id(check_emma_homework), ""); + lv_obj_set_style_bg_color(id(card_jordyn_homework), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_homework), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_homework), 2, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_homework), ""); } - // Set Table - if (id(emma_set_table).state) { - lv_obj_set_style_bg_color(id(card_emma_set_table), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_emma_set_table), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_emma_set_table), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_emma_set_table), 3, LV_PART_MAIN); - lv_label_set_text(id(check_emma_set_table), "✅"); + if (id(jordyn_feed_dog).state) { + lv_obj_set_style_bg_color(id(card_jordyn_feed_dog), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_feed_dog), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_feed_dog), 3, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_feed_dog), "\u2705"); } else { - lv_obj_set_style_bg_color(id(card_emma_set_table), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_emma_set_table), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_emma_set_table), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_emma_set_table), 2, LV_PART_MAIN); - lv_label_set_text(id(check_emma_set_table), ""); - } - // Take Out Trash - if (id(emma_take_out_trash).state) { - lv_obj_set_style_bg_color(id(card_emma_take_out_trash), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_emma_take_out_trash), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_emma_take_out_trash), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_emma_take_out_trash), 3, LV_PART_MAIN); - lv_label_set_text(id(check_emma_take_out_trash), "✅"); - } else { - lv_obj_set_style_bg_color(id(card_emma_take_out_trash), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_emma_take_out_trash), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_emma_take_out_trash), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_emma_take_out_trash), 2, LV_PART_MAIN); - lv_label_set_text(id(check_emma_take_out_trash), ""); - } - // Feed Pet - if (id(emma_feed_pet).state) { - lv_obj_set_style_bg_color(id(card_emma_feed_pet), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_emma_feed_pet), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_emma_feed_pet), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_emma_feed_pet), 3, LV_PART_MAIN); - lv_label_set_text(id(check_emma_feed_pet), "✅"); - } else { - lv_obj_set_style_bg_color(id(card_emma_feed_pet), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_emma_feed_pet), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_emma_feed_pet), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_emma_feed_pet), 2, LV_PART_MAIN); - lv_label_set_text(id(check_emma_feed_pet), ""); - } - // Water Plants - if (id(emma_water_plants).state) { - lv_obj_set_style_bg_color(id(card_emma_water_plants), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_emma_water_plants), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_emma_water_plants), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_emma_water_plants), 3, LV_PART_MAIN); - lv_label_set_text(id(check_emma_water_plants), "✅"); - } else { - lv_obj_set_style_bg_color(id(card_emma_water_plants), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_emma_water_plants), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_emma_water_plants), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_emma_water_plants), 2, LV_PART_MAIN); - lv_label_set_text(id(check_emma_water_plants), ""); + lv_obj_set_style_bg_color(id(card_jordyn_feed_dog), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_jordyn_feed_dog), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_jordyn_feed_dog), 2, LV_PART_MAIN); + lv_label_set_text(id(check_jordyn_feed_dog), ""); } - # Reset all of Liam's chores (used by manual reset button + midnight) - - id: reset_liam_chores + - id: reset_declan_chores mode: single then: - lambda: |- - id(liam_make_bed).turn_off(); - id(liam_brush_teeth).turn_off(); - id(liam_tidy_room).turn_off(); - id(liam_homework).turn_off(); - id(liam_set_table).turn_off(); - id(liam_take_out_trash).turn_off(); - id(liam_feed_pet).turn_off(); - id(liam_water_plants).turn_off(); - - script.execute: update_liam_ui + id(declan_make_bed).turn_off(); + id(declan_brush_teeth).turn_off(); + id(declan_set_table).turn_off(); + id(declan_take_out_trash).turn_off(); + - script.execute: update_declan_ui - - id: update_liam_ui + - id: update_declan_ui mode: single then: - lambda: |- - int done = (id(liam_make_bed).state ? 1 : 0) + (id(liam_brush_teeth).state ? 1 : 0) + (id(liam_tidy_room).state ? 1 : 0) + (id(liam_homework).state ? 1 : 0) + (id(liam_set_table).state ? 1 : 0) + (id(liam_take_out_trash).state ? 1 : 0) + (id(liam_feed_pet).state ? 1 : 0) + (id(liam_water_plants).state ? 1 : 0); - int stars = (id(liam_make_bed).state ? 1 : 0) + (id(liam_brush_teeth).state ? 1 : 0) + (id(liam_tidy_room).state ? 2 : 0) + (id(liam_homework).state ? 3 : 0) + (id(liam_set_table).state ? 1 : 0) + (id(liam_take_out_trash).state ? 2 : 0) + (id(liam_feed_pet).state ? 1 : 0) + (id(liam_water_plants).state ? 1 : 0); - int total = 8; + int done = (id(declan_make_bed).state ? 1 : 0) + (id(declan_brush_teeth).state ? 1 : 0) + (id(declan_set_table).state ? 1 : 0) + (id(declan_take_out_trash).state ? 1 : 0); + int total = 4; + char buf[24]; - // ── Sidebar progress & stars ────────────────────────────────────── - lv_bar_set_value(id(progress_bar_liam), done, LV_ANIM_ON); - char buf[32]; - snprintf(buf, sizeof(buf), "%d / 8", done); - lv_label_set_text(id(progress_label_liam), buf); - snprintf(buf, sizeof(buf), "⭐ %d star%s", stars, stars == 1 ? "" : "s"); - lv_label_set_text(id(sidebar_stars_liam), buf); + // Progress bar + label + lv_bar_set_value(id(progress_bar_declan), done, LV_ANIM_ON); + snprintf(buf, sizeof(buf), "%d / 4", done); + lv_label_set_text(id(progress_label_declan), buf); - // ── All-done celebration text ───────────────────────────────────── + // All-done message in sidebar + lv_label_set_text(id(all_done_label_declan), done == total ? "\U0001F389 All done!" : ""); + + // Home button colour if (done == total) { - lv_label_set_text(id(all_done_label_liam), "🎉 All done!"); + 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_border_width(id(home_btn_declan), 0, LV_PART_MAIN); + lv_label_set_text(id(home_status_declan), "\u2713 all done!"); + lv_obj_set_style_text_color(id(home_status_declan), lv_color_hex(0xFFFFFF), LV_PART_MAIN); } else { - lv_label_set_text(id(all_done_label_liam), ""); - } - - // ── Home screen button: RED outline = incomplete, GREEN = complete ─ - if (done == total) { - // Solid green — all chores done - lv_obj_set_style_bg_opa(id(home_btn_liam), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_bg_color(id(home_btn_liam), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(home_btn_liam), 0, LV_PART_MAIN); - lv_label_set_text(id(home_status_liam), "✓ all done!"); - lv_obj_set_style_text_color(id(home_status_liam), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - } else { - // Transparent fill with red border — incomplete - lv_obj_set_style_bg_opa(id(home_btn_liam), LV_OPA_TRANSP, LV_PART_MAIN); - lv_obj_set_style_border_color(id(home_btn_liam), lv_color_hex(0xFF4757), LV_PART_MAIN); - lv_obj_set_style_border_width(id(home_btn_liam), 5, LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(home_btn_declan), LV_OPA_TRANSP, LV_PART_MAIN); + lv_obj_set_style_border_color(id(home_btn_declan), lv_color_hex(0xFF4757), LV_PART_MAIN); + lv_obj_set_style_border_width(id(home_btn_declan), 5, LV_PART_MAIN); snprintf(buf, sizeof(buf), "%d left", total - done); - lv_label_set_text(id(home_status_liam), buf); - lv_obj_set_style_text_color(id(home_status_liam), lv_color_hex(0xFF4757), LV_PART_MAIN); + lv_label_set_text(id(home_status_declan), buf); + lv_obj_set_style_text_color(id(home_status_declan), lv_color_hex(0xFF4757), LV_PART_MAIN); } - // ── Individual chore card colours ───────────────────────────────── - // Make Bed - if (id(liam_make_bed).state) { - lv_obj_set_style_bg_color(id(card_liam_make_bed), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_liam_make_bed), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_liam_make_bed), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_liam_make_bed), 3, LV_PART_MAIN); - lv_label_set_text(id(check_liam_make_bed), "✅"); + // Card colours + if (id(declan_make_bed).state) { + lv_obj_set_style_bg_color(id(card_declan_make_bed), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_declan_make_bed), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_declan_make_bed), 3, LV_PART_MAIN); + lv_label_set_text(id(check_declan_make_bed), "\u2705"); } else { - lv_obj_set_style_bg_color(id(card_liam_make_bed), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_liam_make_bed), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_liam_make_bed), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_liam_make_bed), 2, LV_PART_MAIN); - lv_label_set_text(id(check_liam_make_bed), ""); + lv_obj_set_style_bg_color(id(card_declan_make_bed), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_declan_make_bed), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_declan_make_bed), 2, LV_PART_MAIN); + lv_label_set_text(id(check_declan_make_bed), ""); } - // Brush Teeth - if (id(liam_brush_teeth).state) { - lv_obj_set_style_bg_color(id(card_liam_brush_teeth), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_liam_brush_teeth), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_liam_brush_teeth), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_liam_brush_teeth), 3, LV_PART_MAIN); - lv_label_set_text(id(check_liam_brush_teeth), "✅"); + if (id(declan_brush_teeth).state) { + lv_obj_set_style_bg_color(id(card_declan_brush_teeth), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_declan_brush_teeth), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_declan_brush_teeth), 3, LV_PART_MAIN); + lv_label_set_text(id(check_declan_brush_teeth), "\u2705"); } else { - lv_obj_set_style_bg_color(id(card_liam_brush_teeth), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_liam_brush_teeth), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_liam_brush_teeth), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_liam_brush_teeth), 2, LV_PART_MAIN); - lv_label_set_text(id(check_liam_brush_teeth), ""); + lv_obj_set_style_bg_color(id(card_declan_brush_teeth), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_declan_brush_teeth), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_declan_brush_teeth), 2, LV_PART_MAIN); + lv_label_set_text(id(check_declan_brush_teeth), ""); } - // Tidy Room - if (id(liam_tidy_room).state) { - lv_obj_set_style_bg_color(id(card_liam_tidy_room), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_liam_tidy_room), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_liam_tidy_room), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_liam_tidy_room), 3, LV_PART_MAIN); - lv_label_set_text(id(check_liam_tidy_room), "✅"); + if (id(declan_set_table).state) { + lv_obj_set_style_bg_color(id(card_declan_set_table), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_declan_set_table), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_declan_set_table), 3, LV_PART_MAIN); + lv_label_set_text(id(check_declan_set_table), "\u2705"); } else { - lv_obj_set_style_bg_color(id(card_liam_tidy_room), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_liam_tidy_room), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_liam_tidy_room), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_liam_tidy_room), 2, LV_PART_MAIN); - lv_label_set_text(id(check_liam_tidy_room), ""); + lv_obj_set_style_bg_color(id(card_declan_set_table), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_declan_set_table), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_declan_set_table), 2, LV_PART_MAIN); + lv_label_set_text(id(check_declan_set_table), ""); } - // Homework - if (id(liam_homework).state) { - lv_obj_set_style_bg_color(id(card_liam_homework), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_liam_homework), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_liam_homework), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_liam_homework), 3, LV_PART_MAIN); - lv_label_set_text(id(check_liam_homework), "✅"); + if (id(declan_take_out_trash).state) { + lv_obj_set_style_bg_color(id(card_declan_take_out_trash), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_declan_take_out_trash), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_declan_take_out_trash), 3, LV_PART_MAIN); + lv_label_set_text(id(check_declan_take_out_trash), "\u2705"); } else { - lv_obj_set_style_bg_color(id(card_liam_homework), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_liam_homework), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_liam_homework), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_liam_homework), 2, LV_PART_MAIN); - lv_label_set_text(id(check_liam_homework), ""); - } - // Set Table - if (id(liam_set_table).state) { - lv_obj_set_style_bg_color(id(card_liam_set_table), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_liam_set_table), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_liam_set_table), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_liam_set_table), 3, LV_PART_MAIN); - lv_label_set_text(id(check_liam_set_table), "✅"); - } else { - lv_obj_set_style_bg_color(id(card_liam_set_table), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_liam_set_table), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_liam_set_table), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_liam_set_table), 2, LV_PART_MAIN); - lv_label_set_text(id(check_liam_set_table), ""); - } - // Take Out Trash - if (id(liam_take_out_trash).state) { - lv_obj_set_style_bg_color(id(card_liam_take_out_trash), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_liam_take_out_trash), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_liam_take_out_trash), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_liam_take_out_trash), 3, LV_PART_MAIN); - lv_label_set_text(id(check_liam_take_out_trash), "✅"); - } else { - lv_obj_set_style_bg_color(id(card_liam_take_out_trash), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_liam_take_out_trash), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_liam_take_out_trash), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_liam_take_out_trash), 2, LV_PART_MAIN); - lv_label_set_text(id(check_liam_take_out_trash), ""); - } - // Feed Pet - if (id(liam_feed_pet).state) { - lv_obj_set_style_bg_color(id(card_liam_feed_pet), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_liam_feed_pet), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_liam_feed_pet), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_liam_feed_pet), 3, LV_PART_MAIN); - lv_label_set_text(id(check_liam_feed_pet), "✅"); - } else { - lv_obj_set_style_bg_color(id(card_liam_feed_pet), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_liam_feed_pet), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_liam_feed_pet), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_liam_feed_pet), 2, LV_PART_MAIN); - lv_label_set_text(id(check_liam_feed_pet), ""); - } - // Water Plants - if (id(liam_water_plants).state) { - lv_obj_set_style_bg_color(id(card_liam_water_plants), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_liam_water_plants), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_liam_water_plants), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_liam_water_plants), 3, LV_PART_MAIN); - lv_label_set_text(id(check_liam_water_plants), "✅"); - } else { - lv_obj_set_style_bg_color(id(card_liam_water_plants), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_liam_water_plants), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_liam_water_plants), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_liam_water_plants), 2, LV_PART_MAIN); - lv_label_set_text(id(check_liam_water_plants), ""); + lv_obj_set_style_bg_color(id(card_declan_take_out_trash), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_declan_take_out_trash), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_declan_take_out_trash), 2, LV_PART_MAIN); + lv_label_set_text(id(check_declan_take_out_trash), ""); } - # Reset all of Zoe's chores (used by manual reset button + midnight) - - id: reset_zoe_chores + - id: reset_chloe_chores mode: single then: - lambda: |- - id(zoe_make_bed).turn_off(); - id(zoe_brush_teeth).turn_off(); - id(zoe_tidy_room).turn_off(); - id(zoe_homework).turn_off(); - id(zoe_set_table).turn_off(); - id(zoe_take_out_trash).turn_off(); - id(zoe_feed_pet).turn_off(); - id(zoe_water_plants).turn_off(); - - script.execute: update_zoe_ui + id(chloe_make_bed).turn_off(); + id(chloe_brush_teeth).turn_off(); + id(chloe_water_plants).turn_off(); + id(chloe_homework).turn_off(); + id(chloe_tidy_room).turn_off(); + id(chloe_practice_piano).turn_off(); + - script.execute: update_chloe_ui - - id: update_zoe_ui + - id: update_chloe_ui mode: single then: - lambda: |- - int done = (id(zoe_make_bed).state ? 1 : 0) + (id(zoe_brush_teeth).state ? 1 : 0) + (id(zoe_tidy_room).state ? 1 : 0) + (id(zoe_homework).state ? 1 : 0) + (id(zoe_set_table).state ? 1 : 0) + (id(zoe_take_out_trash).state ? 1 : 0) + (id(zoe_feed_pet).state ? 1 : 0) + (id(zoe_water_plants).state ? 1 : 0); - int stars = (id(zoe_make_bed).state ? 1 : 0) + (id(zoe_brush_teeth).state ? 1 : 0) + (id(zoe_tidy_room).state ? 2 : 0) + (id(zoe_homework).state ? 3 : 0) + (id(zoe_set_table).state ? 1 : 0) + (id(zoe_take_out_trash).state ? 2 : 0) + (id(zoe_feed_pet).state ? 1 : 0) + (id(zoe_water_plants).state ? 1 : 0); - int total = 8; + int done = (id(chloe_make_bed).state ? 1 : 0) + (id(chloe_brush_teeth).state ? 1 : 0) + (id(chloe_water_plants).state ? 1 : 0) + (id(chloe_homework).state ? 1 : 0) + (id(chloe_tidy_room).state ? 1 : 0) + (id(chloe_practice_piano).state ? 1 : 0); + int total = 6; + char buf[24]; - // ── Sidebar progress & stars ────────────────────────────────────── - lv_bar_set_value(id(progress_bar_zoe), done, LV_ANIM_ON); - char buf[32]; - snprintf(buf, sizeof(buf), "%d / 8", done); - lv_label_set_text(id(progress_label_zoe), buf); - snprintf(buf, sizeof(buf), "⭐ %d star%s", stars, stars == 1 ? "" : "s"); - lv_label_set_text(id(sidebar_stars_zoe), buf); + // Progress bar + label + lv_bar_set_value(id(progress_bar_chloe), done, LV_ANIM_ON); + snprintf(buf, sizeof(buf), "%d / 6", done); + lv_label_set_text(id(progress_label_chloe), buf); - // ── All-done celebration text ───────────────────────────────────── + // All-done message in sidebar + lv_label_set_text(id(all_done_label_chloe), done == total ? "\U0001F389 All done!" : ""); + + // Home button colour if (done == total) { - lv_label_set_text(id(all_done_label_zoe), "🎉 All done!"); + 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_border_width(id(home_btn_chloe), 0, LV_PART_MAIN); + lv_label_set_text(id(home_status_chloe), "\u2713 all done!"); + lv_obj_set_style_text_color(id(home_status_chloe), lv_color_hex(0xFFFFFF), LV_PART_MAIN); } else { - lv_label_set_text(id(all_done_label_zoe), ""); - } - - // ── Home screen button: RED outline = incomplete, GREEN = complete ─ - if (done == total) { - // Solid green — all chores done - lv_obj_set_style_bg_opa(id(home_btn_zoe), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_bg_color(id(home_btn_zoe), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(home_btn_zoe), 0, LV_PART_MAIN); - lv_label_set_text(id(home_status_zoe), "✓ all done!"); - lv_obj_set_style_text_color(id(home_status_zoe), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - } else { - // Transparent fill with red border — incomplete - lv_obj_set_style_bg_opa(id(home_btn_zoe), LV_OPA_TRANSP, LV_PART_MAIN); - lv_obj_set_style_border_color(id(home_btn_zoe), lv_color_hex(0xFF4757), LV_PART_MAIN); - lv_obj_set_style_border_width(id(home_btn_zoe), 5, LV_PART_MAIN); + lv_obj_set_style_bg_opa(id(home_btn_chloe), LV_OPA_TRANSP, LV_PART_MAIN); + lv_obj_set_style_border_color(id(home_btn_chloe), lv_color_hex(0xFF4757), LV_PART_MAIN); + lv_obj_set_style_border_width(id(home_btn_chloe), 5, LV_PART_MAIN); snprintf(buf, sizeof(buf), "%d left", total - done); - lv_label_set_text(id(home_status_zoe), buf); - lv_obj_set_style_text_color(id(home_status_zoe), lv_color_hex(0xFF4757), LV_PART_MAIN); + lv_label_set_text(id(home_status_chloe), buf); + lv_obj_set_style_text_color(id(home_status_chloe), lv_color_hex(0xFF4757), LV_PART_MAIN); } - // ── Individual chore card colours ───────────────────────────────── - // Make Bed - if (id(zoe_make_bed).state) { - lv_obj_set_style_bg_color(id(card_zoe_make_bed), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_zoe_make_bed), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_zoe_make_bed), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_zoe_make_bed), 3, LV_PART_MAIN); - lv_label_set_text(id(check_zoe_make_bed), "✅"); + // Card colours + if (id(chloe_make_bed).state) { + lv_obj_set_style_bg_color(id(card_chloe_make_bed), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_make_bed), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_make_bed), 3, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_make_bed), "\u2705"); } else { - lv_obj_set_style_bg_color(id(card_zoe_make_bed), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_zoe_make_bed), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_zoe_make_bed), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_zoe_make_bed), 2, LV_PART_MAIN); - lv_label_set_text(id(check_zoe_make_bed), ""); + lv_obj_set_style_bg_color(id(card_chloe_make_bed), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_make_bed), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_make_bed), 2, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_make_bed), ""); } - // Brush Teeth - if (id(zoe_brush_teeth).state) { - lv_obj_set_style_bg_color(id(card_zoe_brush_teeth), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_zoe_brush_teeth), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_zoe_brush_teeth), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_zoe_brush_teeth), 3, LV_PART_MAIN); - lv_label_set_text(id(check_zoe_brush_teeth), "✅"); + if (id(chloe_brush_teeth).state) { + lv_obj_set_style_bg_color(id(card_chloe_brush_teeth), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_brush_teeth), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_brush_teeth), 3, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_brush_teeth), "\u2705"); } else { - lv_obj_set_style_bg_color(id(card_zoe_brush_teeth), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_zoe_brush_teeth), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_zoe_brush_teeth), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_zoe_brush_teeth), 2, LV_PART_MAIN); - lv_label_set_text(id(check_zoe_brush_teeth), ""); + lv_obj_set_style_bg_color(id(card_chloe_brush_teeth), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_brush_teeth), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_brush_teeth), 2, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_brush_teeth), ""); } - // Tidy Room - if (id(zoe_tidy_room).state) { - lv_obj_set_style_bg_color(id(card_zoe_tidy_room), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_zoe_tidy_room), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_zoe_tidy_room), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_zoe_tidy_room), 3, LV_PART_MAIN); - lv_label_set_text(id(check_zoe_tidy_room), "✅"); + if (id(chloe_water_plants).state) { + lv_obj_set_style_bg_color(id(card_chloe_water_plants), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_water_plants), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_water_plants), 3, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_water_plants), "\u2705"); } else { - lv_obj_set_style_bg_color(id(card_zoe_tidy_room), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_zoe_tidy_room), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_zoe_tidy_room), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_zoe_tidy_room), 2, LV_PART_MAIN); - lv_label_set_text(id(check_zoe_tidy_room), ""); + lv_obj_set_style_bg_color(id(card_chloe_water_plants), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_water_plants), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_water_plants), 2, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_water_plants), ""); } - // Homework - if (id(zoe_homework).state) { - lv_obj_set_style_bg_color(id(card_zoe_homework), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_zoe_homework), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_zoe_homework), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_zoe_homework), 3, LV_PART_MAIN); - lv_label_set_text(id(check_zoe_homework), "✅"); + if (id(chloe_homework).state) { + lv_obj_set_style_bg_color(id(card_chloe_homework), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_homework), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_homework), 3, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_homework), "\u2705"); } else { - lv_obj_set_style_bg_color(id(card_zoe_homework), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_zoe_homework), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_zoe_homework), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_zoe_homework), 2, LV_PART_MAIN); - lv_label_set_text(id(check_zoe_homework), ""); + lv_obj_set_style_bg_color(id(card_chloe_homework), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_homework), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_homework), 2, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_homework), ""); } - // Set Table - if (id(zoe_set_table).state) { - lv_obj_set_style_bg_color(id(card_zoe_set_table), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_zoe_set_table), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_zoe_set_table), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_zoe_set_table), 3, LV_PART_MAIN); - lv_label_set_text(id(check_zoe_set_table), "✅"); + if (id(chloe_tidy_room).state) { + lv_obj_set_style_bg_color(id(card_chloe_tidy_room), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_tidy_room), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_tidy_room), 3, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_tidy_room), "\u2705"); } else { - lv_obj_set_style_bg_color(id(card_zoe_set_table), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_zoe_set_table), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_zoe_set_table), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_zoe_set_table), 2, LV_PART_MAIN); - lv_label_set_text(id(check_zoe_set_table), ""); + lv_obj_set_style_bg_color(id(card_chloe_tidy_room), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_tidy_room), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_tidy_room), 2, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_tidy_room), ""); } - // Take Out Trash - if (id(zoe_take_out_trash).state) { - lv_obj_set_style_bg_color(id(card_zoe_take_out_trash), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_zoe_take_out_trash), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_zoe_take_out_trash), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_zoe_take_out_trash), 3, LV_PART_MAIN); - lv_label_set_text(id(check_zoe_take_out_trash), "✅"); + if (id(chloe_practice_piano).state) { + lv_obj_set_style_bg_color(id(card_chloe_practice_piano), lv_color_hex(0xF0FFF4), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_practice_piano), lv_color_hex(0x6BCB77), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_practice_piano), 3, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_practice_piano), "\u2705"); } else { - lv_obj_set_style_bg_color(id(card_zoe_take_out_trash), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_zoe_take_out_trash), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_zoe_take_out_trash), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_zoe_take_out_trash), 2, LV_PART_MAIN); - lv_label_set_text(id(check_zoe_take_out_trash), ""); - } - // Feed Pet - if (id(zoe_feed_pet).state) { - lv_obj_set_style_bg_color(id(card_zoe_feed_pet), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_zoe_feed_pet), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_zoe_feed_pet), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_zoe_feed_pet), 3, LV_PART_MAIN); - lv_label_set_text(id(check_zoe_feed_pet), "✅"); - } else { - lv_obj_set_style_bg_color(id(card_zoe_feed_pet), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_zoe_feed_pet), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_zoe_feed_pet), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_zoe_feed_pet), 2, LV_PART_MAIN); - lv_label_set_text(id(check_zoe_feed_pet), ""); - } - // Water Plants - if (id(zoe_water_plants).state) { - lv_obj_set_style_bg_color(id(card_zoe_water_plants), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_zoe_water_plants), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_zoe_water_plants), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_zoe_water_plants), 3, LV_PART_MAIN); - lv_label_set_text(id(check_zoe_water_plants), "✅"); - } else { - lv_obj_set_style_bg_color(id(card_zoe_water_plants), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_bg_opa(id(card_zoe_water_plants), LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_zoe_water_plants), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_zoe_water_plants), 2, LV_PART_MAIN); - lv_label_set_text(id(check_zoe_water_plants), ""); + lv_obj_set_style_bg_color(id(card_chloe_practice_piano), lv_color_hex(0xFFFFFF), LV_PART_MAIN); + lv_obj_set_style_border_color(id(card_chloe_practice_piano), lv_color_hex(0xEEEEEE), LV_PART_MAIN); + lv_obj_set_style_border_width(id(card_chloe_practice_piano), 2, LV_PART_MAIN); + lv_label_set_text(id(check_chloe_practice_piano), ""); } @@ -1297,46 +795,44 @@ lvgl: widgets: - label: x: 0 - y: 38 + y: 36 width: 800 align: TOP_MID - text: "⭐ Chore Tracker" + text: "Chore Tracker" text_font: font_title text_color: 0x2D3436 - label: x: 0 - y: 96 + y: 90 width: 800 align: TOP_MID text: "Tap a name to check off chores" text_font: font_small text_color: 0xB2BEC3 - # Reset All button — bottom right, subtle red - btn: - x: 660 - y: 428 - width: 130 + x: 640 + y: 424 + width: 148 height: 40 bg_color: 0xFF4757 radius: 12 on_click: then: - - script.execute: reset_emma_chores - - script.execute: reset_liam_chores - - script.execute: reset_zoe_chores + - script.execute: reset_jordyn_chores + - script.execute: reset_declan_chores + - script.execute: reset_chloe_chores widgets: - label: align: CENTER text: "↺ Reset All" text_color: 0xFFFFFF text_font: font_tiny - # Emma — starts red (incomplete), turns green when all done - btn: - id: home_btn_emma + id: home_btn_jordyn x: 80 - y: 140 + y: 130 width: 200 - height: 200 + height: 210 bg_color: 0xFFFFFF bg_opa: TRANSP border_color: 0xFF4757 @@ -1344,34 +840,33 @@ lvgl: radius: 24 on_click: then: - - lvgl.page.show: page_emma + - lvgl.page.show: page_jordyn widgets: - label: align: CENTER - y: -38 - text: "🐶" + y: -45 + text: "😺" text_font: font_title - label: align: CENTER - y: 28 - text: "Emma" + y: 22 + text: "Jordyn" text_font: font_name text_color: 0x2D3436 - label: - id: home_status_emma + id: home_status_jordyn align: CENTER - y: 68 + y: 66 text: "not done" text_font: font_tiny text_color: 0xFF4757 - # Liam — starts red (incomplete), turns green when all done - btn: - id: home_btn_liam + id: home_btn_declan x: 300 - y: 140 + y: 130 width: 200 - height: 200 + height: 210 bg_color: 0xFFFFFF bg_opa: TRANSP border_color: 0xFF4757 @@ -1379,34 +874,33 @@ lvgl: radius: 24 on_click: then: - - lvgl.page.show: page_liam + - lvgl.page.show: page_declan widgets: - label: align: CENTER - y: -38 - text: "🐱" + y: -45 + text: "🤓" text_font: font_title - label: align: CENTER - y: 28 - text: "Liam" + y: 22 + text: "Declan" text_font: font_name text_color: 0x2D3436 - label: - id: home_status_liam + id: home_status_declan align: CENTER - y: 68 + y: 66 text: "not done" text_font: font_tiny text_color: 0xFF4757 - # Zoe — starts red (incomplete), turns green when all done - btn: - id: home_btn_zoe + id: home_btn_chloe x: 520 - y: 140 + y: 130 width: 200 - height: 200 + height: 210 bg_color: 0xFFFFFF bg_opa: TRANSP border_color: 0xFF4757 @@ -1414,29 +908,29 @@ lvgl: radius: 24 on_click: then: - - lvgl.page.show: page_zoe + - lvgl.page.show: page_chloe widgets: - label: align: CENTER - y: -38 - text: "🐻" + y: -45 + text: "🌝" text_font: font_title - label: align: CENTER - y: 28 - text: "Zoe" + y: 22 + text: "Chloe" text_font: font_name text_color: 0x2D3436 - label: - id: home_status_zoe + id: home_status_chloe align: CENTER - y: 68 + y: 66 text: "not done" text_font: font_tiny text_color: 0xFF4757 - - id: page_emma + - id: page_jordyn bg_color: 0xFFF9F0 widgets: @@ -1444,7 +938,7 @@ lvgl: - obj: x: 0 y: 0 - width: 180 + width: 172 height: 480 bg_color: 0x4D96FF border_width: 0 @@ -1453,87 +947,70 @@ lvgl: widgets: - label: x: 0 - y: 20 - width: 180 + y: 22 + width: 172 align: TOP_MID - text: "🐶" + text: "😺" text_font: font_title - label: x: 0 - y: 74 - width: 180 + y: 76 + width: 172 align: TOP_MID - text: "Emma" + text: "Jordyn" text_font: font_name text_color: 0xFFFFFF - - label: - id: sidebar_stars_emma - x: 0 - y: 120 - width: 180 - align: TOP_MID - text: "⭐ 0 stars" - text_font: font_med - text_color: 0xFFD93D - - # Progress bar - bar: - id: progress_bar_emma - x: 16 - y: 164 - width: 148 + id: progress_bar_jordyn + x: 14 + y: 132 + width: 144 height: 16 bg_color: 0x2A6FCC indicator: bg_color: 0xFFFFFF value: 0 min_value: 0 - max_value: 8 + max_value: 5 - label: - id: progress_label_emma + id: progress_label_jordyn x: 0 - y: 188 - width: 180 + y: 156 + width: 172 align: TOP_MID - text: "0 / 8" - text_font: font_tiny + text: "0 / 5" + text_font: font_small text_color: 0xDDEEFF - - # All-done celebration label (hidden until complete) - label: - id: all_done_label_emma + id: all_done_label_jordyn x: 0 - y: 214 - width: 180 + y: 192 + width: 172 align: TOP_MID text: "" text_font: font_small text_color: 0xFFFFFF - - # Manual reset button (parent use — above back button) - btn: - x: 16 - y: 362 - width: 148 + x: 14 + y: 364 + width: 144 height: 44 bg_color: 0xFF4757 radius: 14 on_click: then: - - script.execute: reset_emma_chores + - script.execute: reset_jordyn_chores widgets: - label: align: CENTER text: "↺ Reset" text_color: 0xFFFFFF text_font: font_small - - # Back button - btn: - x: 16 - y: 418 - width: 148 - height: 46 + x: 14 + y: 420 + width: 144 + height: 44 bg_color: 0x2A6FCC radius: 14 on_click: @@ -1547,12 +1024,11 @@ lvgl: text_font: font_small # ── Chore cards ─────────────────────────────────────────────────────── - # Make Bed - btn: - id: card_emma_make_bed - x: 190 + id: card_jordyn_make_bed + x: 182 y: 10 - width: 193 + width: 196 height: 138 bg_color: 0xFFFFFF border_color: 0xEEEEEE @@ -1563,10 +1039,10 @@ lvgl: shadow_ofs_y: 3 on_click: then: - - switch.toggle: emma_make_bed + - switch.toggle: jordyn_make_bed widgets: - label: - id: check_emma_make_bed + id: check_jordyn_make_bed align: TOP_RIGHT x: -10 y: 8 @@ -1579,29 +1055,16 @@ lvgl: text_font: font_med - label: align: CENTER - y: 23 + y: 17 text: "Make Bed" text_font: font_small text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 1" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - # Brush Teeth - btn: - id: card_emma_brush_teeth - x: 393 + id: card_jordyn_brush_teeth + x: 388 y: 10 - width: 193 + width: 196 height: 138 bg_color: 0xFFFFFF border_color: 0xEEEEEE @@ -1612,10 +1075,10 @@ lvgl: shadow_ofs_y: 3 on_click: then: - - switch.toggle: emma_brush_teeth + - switch.toggle: jordyn_brush_teeth widgets: - label: - id: check_emma_brush_teeth + id: check_jordyn_brush_teeth align: TOP_RIGHT x: -10 y: 8 @@ -1628,29 +1091,16 @@ lvgl: text_font: font_med - label: align: CENTER - y: 23 + y: 17 text: "Brush Teeth" text_font: font_small text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 1" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - # Tidy Room - btn: - id: card_emma_tidy_room - x: 596 + id: card_jordyn_tidy_room + x: 594 y: 10 - width: 193 + width: 196 height: 138 bg_color: 0xFFFFFF border_color: 0xEEEEEE @@ -1661,10 +1111,10 @@ lvgl: shadow_ofs_y: 3 on_click: then: - - switch.toggle: emma_tidy_room + - switch.toggle: jordyn_tidy_room widgets: - label: - id: check_emma_tidy_room + id: check_jordyn_tidy_room align: TOP_RIGHT x: -10 y: 8 @@ -1677,29 +1127,16 @@ lvgl: text_font: font_med - label: align: CENTER - y: 23 + y: 17 text: "Tidy Room" text_font: font_small text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 2" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - # Homework - btn: - id: card_emma_homework - x: 190 + id: card_jordyn_homework + x: 182 y: 158 - width: 193 + width: 196 height: 138 bg_color: 0xFFFFFF border_color: 0xEEEEEE @@ -1710,10 +1147,10 @@ lvgl: shadow_ofs_y: 3 on_click: then: - - switch.toggle: emma_homework + - switch.toggle: jordyn_homework widgets: - label: - id: check_emma_homework + id: check_jordyn_homework align: TOP_RIGHT x: -10 y: 8 @@ -1726,29 +1163,16 @@ lvgl: text_font: font_med - label: align: CENTER - y: 23 + y: 17 text: "Homework" text_font: font_small text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 3" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - # Set Table - btn: - id: card_emma_set_table - x: 393 + id: card_jordyn_feed_dog + x: 388 y: 158 - width: 193 + width: 196 height: 138 bg_color: 0xFFFFFF border_color: 0xEEEEEE @@ -1759,108 +1183,10 @@ lvgl: shadow_ofs_y: 3 on_click: then: - - switch.toggle: emma_set_table + - switch.toggle: jordyn_feed_dog widgets: - label: - id: check_emma_set_table - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🍽️" - text_font: font_med - - label: - align: CENTER - y: 23 - text: "Set Table" - text_font: font_small - text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 1" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - - # Take Out Trash - - btn: - id: card_emma_take_out_trash - x: 596 - y: 158 - width: 193 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: emma_take_out_trash - widgets: - - label: - id: check_emma_take_out_trash - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🗑️" - text_font: font_med - - label: - align: CENTER - y: 23 - text: "Take Out Trash" - text_font: font_small - text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 2" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - - # Feed Pet - - btn: - id: card_emma_feed_pet - x: 190 - y: 306 - width: 193 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: emma_feed_pet - widgets: - - label: - id: check_emma_feed_pet + id: check_jordyn_feed_dog align: TOP_RIGHT x: -10 y: 8 @@ -1873,74 +1199,13 @@ lvgl: text_font: font_med - label: align: CENTER - y: 23 - text: "Feed Pet" + y: 17 + text: "Feed Dog" text_font: font_small text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 1" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - - # Water Plants - - btn: - id: card_emma_water_plants - x: 393 - y: 306 - width: 193 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: emma_water_plants - widgets: - - label: - id: check_emma_water_plants - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🌱" - text_font: font_med - - label: - align: CENTER - y: 23 - text: "Water Plants" - text_font: font_small - text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 1" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - - id: page_liam + - id: page_declan bg_color: 0xFFF9F0 widgets: @@ -1948,7 +1213,7 @@ lvgl: - obj: x: 0 y: 0 - width: 180 + width: 172 height: 480 bg_color: 0xC77DFF border_width: 0 @@ -1957,87 +1222,70 @@ lvgl: widgets: - label: x: 0 - y: 20 - width: 180 + y: 22 + width: 172 align: TOP_MID - text: "🐱" + text: "🤓" text_font: font_title - label: x: 0 - y: 74 - width: 180 + y: 76 + width: 172 align: TOP_MID - text: "Liam" + text: "Declan" text_font: font_name text_color: 0xFFFFFF - - label: - id: sidebar_stars_liam - x: 0 - y: 120 - width: 180 - align: TOP_MID - text: "⭐ 0 stars" - text_font: font_med - text_color: 0xFFD93D - - # Progress bar - bar: - id: progress_bar_liam - x: 16 - y: 164 - width: 148 + id: progress_bar_declan + x: 14 + y: 132 + width: 144 height: 16 bg_color: 0x8B42CC indicator: bg_color: 0xFFFFFF value: 0 min_value: 0 - max_value: 8 + max_value: 4 - label: - id: progress_label_liam + id: progress_label_declan x: 0 - y: 188 - width: 180 + y: 156 + width: 172 align: TOP_MID - text: "0 / 8" - text_font: font_tiny + text: "0 / 4" + text_font: font_small text_color: 0xDDEEFF - - # All-done celebration label (hidden until complete) - label: - id: all_done_label_liam + id: all_done_label_declan x: 0 - y: 214 - width: 180 + y: 192 + width: 172 align: TOP_MID text: "" text_font: font_small text_color: 0xFFFFFF - - # Manual reset button (parent use — above back button) - btn: - x: 16 - y: 362 - width: 148 + x: 14 + y: 364 + width: 144 height: 44 bg_color: 0xFF4757 radius: 14 on_click: then: - - script.execute: reset_liam_chores + - script.execute: reset_declan_chores widgets: - label: align: CENTER text: "↺ Reset" text_color: 0xFFFFFF text_font: font_small - - # Back button - btn: - x: 16 - y: 418 - width: 148 - height: 46 + x: 14 + y: 420 + width: 144 + height: 44 bg_color: 0x8B42CC radius: 14 on_click: @@ -2051,12 +1299,11 @@ lvgl: text_font: font_small # ── Chore cards ─────────────────────────────────────────────────────── - # Make Bed - btn: - id: card_liam_make_bed - x: 190 + id: card_declan_make_bed + x: 182 y: 10 - width: 193 + width: 196 height: 138 bg_color: 0xFFFFFF border_color: 0xEEEEEE @@ -2067,10 +1314,10 @@ lvgl: shadow_ofs_y: 3 on_click: then: - - switch.toggle: liam_make_bed + - switch.toggle: declan_make_bed widgets: - label: - id: check_liam_make_bed + id: check_declan_make_bed align: TOP_RIGHT x: -10 y: 8 @@ -2083,29 +1330,16 @@ lvgl: text_font: font_med - label: align: CENTER - y: 23 + y: 17 text: "Make Bed" text_font: font_small text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 1" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - # Brush Teeth - btn: - id: card_liam_brush_teeth - x: 393 + id: card_declan_brush_teeth + x: 388 y: 10 - width: 193 + width: 196 height: 138 bg_color: 0xFFFFFF border_color: 0xEEEEEE @@ -2116,10 +1350,10 @@ lvgl: shadow_ofs_y: 3 on_click: then: - - switch.toggle: liam_brush_teeth + - switch.toggle: declan_brush_teeth widgets: - label: - id: check_liam_brush_teeth + id: check_declan_brush_teeth align: TOP_RIGHT x: -10 y: 8 @@ -2132,29 +1366,16 @@ lvgl: text_font: font_med - label: align: CENTER - y: 23 + y: 17 text: "Brush Teeth" text_font: font_small text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 1" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - # Tidy Room - btn: - id: card_liam_tidy_room - x: 596 + id: card_declan_set_table + x: 594 y: 10 - width: 193 + width: 196 height: 138 bg_color: 0xFFFFFF border_color: 0xEEEEEE @@ -2165,108 +1386,10 @@ lvgl: shadow_ofs_y: 3 on_click: then: - - switch.toggle: liam_tidy_room + - switch.toggle: declan_set_table widgets: - label: - id: check_liam_tidy_room - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🧹" - text_font: font_med - - label: - align: CENTER - y: 23 - text: "Tidy Room" - text_font: font_small - text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 2" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - - # Homework - - btn: - id: card_liam_homework - x: 190 - y: 158 - width: 193 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: liam_homework - widgets: - - label: - id: check_liam_homework - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "📚" - text_font: font_med - - label: - align: CENTER - y: 23 - text: "Homework" - text_font: font_small - text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 3" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - - # Set Table - - btn: - id: card_liam_set_table - x: 393 - y: 158 - width: 193 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: liam_set_table - widgets: - - label: - id: check_liam_set_table + id: check_declan_set_table align: TOP_RIGHT x: -10 y: 8 @@ -2279,29 +1402,16 @@ lvgl: text_font: font_med - label: align: CENTER - y: 23 + y: 17 text: "Set Table" text_font: font_small text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 1" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - # Take Out Trash - btn: - id: card_liam_take_out_trash - x: 596 + id: card_declan_take_out_trash + x: 182 y: 158 - width: 193 + width: 196 height: 138 bg_color: 0xFFFFFF border_color: 0xEEEEEE @@ -2312,10 +1422,10 @@ lvgl: shadow_ofs_y: 3 on_click: then: - - switch.toggle: liam_take_out_trash + - switch.toggle: declan_take_out_trash widgets: - label: - id: check_liam_take_out_trash + id: check_declan_take_out_trash align: TOP_RIGHT x: -10 y: 8 @@ -2328,123 +1438,13 @@ lvgl: text_font: font_med - label: align: CENTER - y: 23 + y: 17 text: "Take Out Trash" text_font: font_small text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 2" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - - # Feed Pet - - btn: - id: card_liam_feed_pet - x: 190 - y: 306 - width: 193 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: liam_feed_pet - widgets: - - label: - id: check_liam_feed_pet - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🐾" - text_font: font_med - - label: - align: CENTER - y: 23 - text: "Feed Pet" - text_font: font_small - text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 1" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - - # Water Plants - - btn: - id: card_liam_water_plants - x: 393 - y: 306 - width: 193 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: liam_water_plants - widgets: - - label: - id: check_liam_water_plants - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🌱" - text_font: font_med - - label: - align: CENTER - y: 23 - text: "Water Plants" - text_font: font_small - text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 1" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - - id: page_zoe + - id: page_chloe bg_color: 0xFFF9F0 widgets: @@ -2452,7 +1452,7 @@ lvgl: - obj: x: 0 y: 0 - width: 180 + width: 172 height: 480 bg_color: 0xFF6B9D border_width: 0 @@ -2461,87 +1461,70 @@ lvgl: widgets: - label: x: 0 - y: 20 - width: 180 + y: 22 + width: 172 align: TOP_MID - text: "🐻" + text: "🌝" text_font: font_title - label: x: 0 - y: 74 - width: 180 + y: 76 + width: 172 align: TOP_MID - text: "Zoe" + text: "Chloe" text_font: font_name text_color: 0xFFFFFF - - label: - id: sidebar_stars_zoe - x: 0 - y: 120 - width: 180 - align: TOP_MID - text: "⭐ 0 stars" - text_font: font_med - text_color: 0xFFD93D - - # Progress bar - bar: - id: progress_bar_zoe - x: 16 - y: 164 - width: 148 + id: progress_bar_chloe + x: 14 + y: 132 + width: 144 height: 16 bg_color: 0xCC3A6F indicator: bg_color: 0xFFFFFF value: 0 min_value: 0 - max_value: 8 + max_value: 6 - label: - id: progress_label_zoe + id: progress_label_chloe x: 0 - y: 188 - width: 180 + y: 156 + width: 172 align: TOP_MID - text: "0 / 8" - text_font: font_tiny + text: "0 / 6" + text_font: font_small text_color: 0xDDEEFF - - # All-done celebration label (hidden until complete) - label: - id: all_done_label_zoe + id: all_done_label_chloe x: 0 - y: 214 - width: 180 + y: 192 + width: 172 align: TOP_MID text: "" text_font: font_small text_color: 0xFFFFFF - - # Manual reset button (parent use — above back button) - btn: - x: 16 - y: 362 - width: 148 + x: 14 + y: 364 + width: 144 height: 44 bg_color: 0xFF4757 radius: 14 on_click: then: - - script.execute: reset_zoe_chores + - script.execute: reset_chloe_chores widgets: - label: align: CENTER text: "↺ Reset" text_color: 0xFFFFFF text_font: font_small - - # Back button - btn: - x: 16 - y: 418 - width: 148 - height: 46 + x: 14 + y: 420 + width: 144 + height: 44 bg_color: 0xCC3A6F radius: 14 on_click: @@ -2555,12 +1538,11 @@ lvgl: text_font: font_small # ── Chore cards ─────────────────────────────────────────────────────── - # Make Bed - btn: - id: card_zoe_make_bed - x: 190 + id: card_chloe_make_bed + x: 182 y: 10 - width: 193 + width: 196 height: 138 bg_color: 0xFFFFFF border_color: 0xEEEEEE @@ -2571,10 +1553,10 @@ lvgl: shadow_ofs_y: 3 on_click: then: - - switch.toggle: zoe_make_bed + - switch.toggle: chloe_make_bed widgets: - label: - id: check_zoe_make_bed + id: check_chloe_make_bed align: TOP_RIGHT x: -10 y: 8 @@ -2587,29 +1569,16 @@ lvgl: text_font: font_med - label: align: CENTER - y: 23 + y: 17 text: "Make Bed" text_font: font_small text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 1" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - # Brush Teeth - btn: - id: card_zoe_brush_teeth - x: 393 + id: card_chloe_brush_teeth + x: 388 y: 10 - width: 193 + width: 196 height: 138 bg_color: 0xFFFFFF border_color: 0xEEEEEE @@ -2620,10 +1589,10 @@ lvgl: shadow_ofs_y: 3 on_click: then: - - switch.toggle: zoe_brush_teeth + - switch.toggle: chloe_brush_teeth widgets: - label: - id: check_zoe_brush_teeth + id: check_chloe_brush_teeth align: TOP_RIGHT x: -10 y: 8 @@ -2636,29 +1605,16 @@ lvgl: text_font: font_med - label: align: CENTER - y: 23 + y: 17 text: "Brush Teeth" text_font: font_small text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 1" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - # Tidy Room - btn: - id: card_zoe_tidy_room - x: 596 + id: card_chloe_water_plants + x: 594 y: 10 - width: 193 + width: 196 height: 138 bg_color: 0xFFFFFF border_color: 0xEEEEEE @@ -2669,255 +1625,10 @@ lvgl: shadow_ofs_y: 3 on_click: then: - - switch.toggle: zoe_tidy_room + - switch.toggle: chloe_water_plants widgets: - label: - id: check_zoe_tidy_room - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🧹" - text_font: font_med - - label: - align: CENTER - y: 23 - text: "Tidy Room" - text_font: font_small - text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 2" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - - # Homework - - btn: - id: card_zoe_homework - x: 190 - y: 158 - width: 193 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: zoe_homework - widgets: - - label: - id: check_zoe_homework - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "📚" - text_font: font_med - - label: - align: CENTER - y: 23 - text: "Homework" - text_font: font_small - text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 3" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - - # Set Table - - btn: - id: card_zoe_set_table - x: 393 - y: 158 - width: 193 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: zoe_set_table - widgets: - - label: - id: check_zoe_set_table - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🍽️" - text_font: font_med - - label: - align: CENTER - y: 23 - text: "Set Table" - text_font: font_small - text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 1" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - - # Take Out Trash - - btn: - id: card_zoe_take_out_trash - x: 596 - y: 158 - width: 193 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: zoe_take_out_trash - widgets: - - label: - id: check_zoe_take_out_trash - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🗑️" - text_font: font_med - - label: - align: CENTER - y: 23 - text: "Take Out Trash" - text_font: font_small - text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 2" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - - # Feed Pet - - btn: - id: card_zoe_feed_pet - x: 190 - y: 306 - width: 193 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: zoe_feed_pet - widgets: - - label: - id: check_zoe_feed_pet - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🐾" - text_font: font_med - - label: - align: CENTER - y: 23 - text: "Feed Pet" - text_font: font_small - text_color: 0x2D3436 - - label: - align: CENTER - y: 45 - text: "⭐ 1" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 - - # Water Plants - - btn: - id: card_zoe_water_plants - x: 393 - y: 306 - width: 193 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: zoe_water_plants - widgets: - - label: - id: check_zoe_water_plants + id: check_chloe_water_plants align: TOP_RIGHT x: -10 y: 8 @@ -2930,19 +1641,117 @@ lvgl: text_font: font_med - label: align: CENTER - y: 23 + y: 17 text: "Water Plants" text_font: font_small text_color: 0x2D3436 + + - btn: + id: card_chloe_homework + x: 182 + y: 158 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: chloe_homework + widgets: + - label: + id: check_chloe_homework + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med - label: align: CENTER - y: 45 - text: "⭐ 1" - text_font: font_tiny - text_color: 0x7A5900 - bg_color: 0xFFD93D - radius: 8 - pad_left: 8 - pad_right: 8 - pad_top: 2 - pad_bottom: 2 \ No newline at end of file + y: -34 + text: "📚" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Homework" + text_font: font_small + text_color: 0x2D3436 + + - btn: + id: card_chloe_tidy_room + x: 388 + y: 158 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: chloe_tidy_room + widgets: + - label: + id: check_chloe_tidy_room + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🧹" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Tidy Room" + text_font: font_small + text_color: 0x2D3436 + + - btn: + id: card_chloe_practice_piano + x: 594 + y: 158 + width: 196 + height: 138 + bg_color: 0xFFFFFF + border_color: 0xEEEEEE + border_width: 2 + radius: 20 + shadow_color: 0xCCCCCC + shadow_width: 4 + shadow_ofs_y: 3 + on_click: + then: + - switch.toggle: chloe_practice_piano + widgets: + - label: + id: check_chloe_practice_piano + align: TOP_RIGHT + x: -10 + y: 8 + text: "" + text_font: font_med + - label: + align: CENTER + y: -34 + text: "🎹" + text_font: font_med + - label: + align: CENTER + y: 17 + text: "Practice Piano" + text_font: font_small + text_color: 0x2D3436 + + diff --git a/esphome/chore-tracker/chore-tracker-esphome.yaml b/esphome/chore-tracker/chore-tracker-esphome.yaml deleted file mode 100644 index 3ef805f..0000000 --- a/esphome/chore-tracker/chore-tracker-esphome.yaml +++ /dev/null @@ -1,1757 +0,0 @@ -################################################################################ -# chore-tracker-esphome.yaml (AUTO-GENERATED — edit chores_config.yaml) -# Kids: Jordyn, Declan, Chloe -# -# HOME SCREEN BEHAVIOUR: -# Red outline = chores incomplete -# Solid green = all chores done ✓ -# Resets to red automatically at midnight -################################################################################ - -esphome: - name: chore-tracker - friendly_name: "Chore Tracker" - -esp32: - board: esp32s3box - framework: - type: esp-idf - -wifi: - ssid: !secret wifi_iot_ssid - password: !secret wifi_password - ap: - ssid: "Chore Tracker Hotspot" - password: "choretracker" - -captive_portal: -logger: - level: INFO - -api: - encryption: - key: !secret api_encryption_key - -ota: - - platform: esphome - password: !secret ota_password - -# ── Display — Waveshare ESP32-S3 7" (adjust pins for your board revision) ───── -display: - - platform: rpi_dpi_rgb - id: main_display - auto_clear_enabled: false - color_order: RGB - dimensions: - width: 800 - height: 480 - de_pin: - number: GPIO40 - ignore_strapping_warning: true - hsync_pin: - number: GPIO39 - ignore_strapping_warning: true - 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: - - id: i2c_touch - sda: GPIO19 - scl: GPIO20 - frequency: 400kHz - -output: - - platform: ledc - pin: GPIO17 - id: backlight_output - -light: - - platform: monochromatic - output: backlight_output - name: "Display Backlight" - id: backlight - restore_mode: ALWAYS_ON - -# ── Midnight reset ──────────────────────────────────────────────────────────── -time: - - platform: homeassistant - id: ha_time - on_time: - - hours: 0 - minutes: 0 - seconds: 0 - then: - - lambda: |- - id(reset_jordyn_chores).execute(); - id(reset_declan_chores).execute(); - id(reset_chloe_chores).execute(); - - lvgl.page.show: page_home - -fonts: - - file: "gfonts://Nunito:wght@900" - id: font_title - size: 40 - - file: "gfonts://Nunito:wght@800" - id: font_name - size: 30 - - file: "gfonts://Nunito:wght@700" - id: font_med - size: 22 - - file: "gfonts://Nunito:wght@600" - id: font_small - size: 17 - - file: "gfonts://Nunito:wght@600" - id: font_tiny - size: 13 - -# ── Switches — one per chore per kid, synced to HA ─────────────────────────── -switch: - - # ── Jordyn's chores ────────────────────────── - platform: template - name: "Jordyn - Make Bed" - id: jordyn_make_bed - icon: mdi:checkbox-marked-circle - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_jordyn_ui - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_jordyn_make_bed - on_turn_off: - then: - - script.execute: update_jordyn_ui - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_jordyn_make_bed - - platform: template - name: "Jordyn - Brush Teeth" - id: jordyn_brush_teeth - icon: mdi:checkbox-marked-circle - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_jordyn_ui - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_jordyn_brush_teeth - on_turn_off: - then: - - script.execute: update_jordyn_ui - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_jordyn_brush_teeth - - platform: template - name: "Jordyn - Tidy Room" - id: jordyn_tidy_room - icon: mdi:checkbox-marked-circle - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_jordyn_ui - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_jordyn_tidy_room - on_turn_off: - then: - - script.execute: update_jordyn_ui - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_jordyn_tidy_room - - platform: template - name: "Jordyn - Homework" - id: jordyn_homework - icon: mdi:checkbox-marked-circle - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_jordyn_ui - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_jordyn_homework - on_turn_off: - then: - - script.execute: update_jordyn_ui - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_jordyn_homework - - platform: template - name: "Jordyn - Feed Dog" - id: jordyn_feed_dog - icon: mdi:checkbox-marked-circle - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_jordyn_ui - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_jordyn_feed_dog - on_turn_off: - then: - - script.execute: update_jordyn_ui - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_jordyn_feed_dog - - # ── Declan's chores ────────────────────────── - platform: template - name: "Declan - Make Bed" - id: declan_make_bed - icon: mdi:checkbox-marked-circle - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_declan_ui - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_declan_make_bed - on_turn_off: - then: - - script.execute: update_declan_ui - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_declan_make_bed - - platform: template - name: "Declan - Brush Teeth" - id: declan_brush_teeth - icon: mdi:checkbox-marked-circle - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_declan_ui - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_declan_brush_teeth - on_turn_off: - then: - - script.execute: update_declan_ui - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_declan_brush_teeth - - platform: template - name: "Declan - Set Table" - id: declan_set_table - icon: mdi:checkbox-marked-circle - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_declan_ui - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_declan_set_table - on_turn_off: - then: - - script.execute: update_declan_ui - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_declan_set_table - - platform: template - name: "Declan - Take Out Trash" - id: declan_take_out_trash - icon: mdi:checkbox-marked-circle - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_declan_ui - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_declan_take_out_trash - on_turn_off: - then: - - script.execute: update_declan_ui - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_declan_take_out_trash - - # ── Chloe's chores ────────────────────────── - platform: template - name: "Chloe - Make Bed" - id: chloe_make_bed - icon: mdi:checkbox-marked-circle - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_chloe_ui - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_chloe_make_bed - on_turn_off: - then: - - script.execute: update_chloe_ui - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_chloe_make_bed - - platform: template - name: "Chloe - Brush Teeth" - id: chloe_brush_teeth - icon: mdi:checkbox-marked-circle - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_chloe_ui - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_chloe_brush_teeth - on_turn_off: - then: - - script.execute: update_chloe_ui - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_chloe_brush_teeth - - platform: template - name: "Chloe - Water Plants" - id: chloe_water_plants - icon: mdi:checkbox-marked-circle - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_chloe_ui - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_chloe_water_plants - on_turn_off: - then: - - script.execute: update_chloe_ui - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_chloe_water_plants - - platform: template - name: "Chloe - Homework" - id: chloe_homework - icon: mdi:checkbox-marked-circle - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_chloe_ui - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_chloe_homework - on_turn_off: - then: - - script.execute: update_chloe_ui - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_chloe_homework - - platform: template - name: "Chloe - Tidy Room" - id: chloe_tidy_room - icon: mdi:checkbox-marked-circle - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_chloe_ui - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_chloe_tidy_room - on_turn_off: - then: - - script.execute: update_chloe_ui - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_chloe_tidy_room - - platform: template - name: "Chloe - Practice Piano" - id: chloe_practice_piano - icon: mdi:checkbox-marked-circle - optimistic: true - restore_mode: RESTORE_DEFAULT_OFF - on_turn_on: - then: - - script.execute: update_chloe_ui - - homeassistant.service: - service: switch.turn_on - data: - entity_id: switch.chore_tracker_chloe_practice_piano - on_turn_off: - then: - - script.execute: update_chloe_ui - - homeassistant.service: - service: switch.turn_off - data: - entity_id: switch.chore_tracker_chloe_practice_piano - - -# ── Sensors — reported to HA ───────────────────────────────────────────────── -sensor: - - platform: template - name: "Jordyn Chores Done" - id: jordyn_chores_done - accuracy_decimals: 0 - update_interval: 2s - lambda: |- - int done = 0; - if (id(jordyn_make_bed).state) done++; - if (id(jordyn_brush_teeth).state) done++; - if (id(jordyn_tidy_room).state) done++; - if (id(jordyn_homework).state) done++; - if (id(jordyn_feed_dog).state) done++; - return done; - - - platform: template - name: "Declan Chores Done" - id: declan_chores_done - accuracy_decimals: 0 - update_interval: 2s - lambda: |- - int done = 0; - if (id(declan_make_bed).state) done++; - if (id(declan_brush_teeth).state) done++; - if (id(declan_set_table).state) done++; - if (id(declan_take_out_trash).state) done++; - return done; - - - platform: template - name: "Chloe Chores Done" - id: chloe_chores_done - accuracy_decimals: 0 - update_interval: 2s - lambda: |- - int done = 0; - if (id(chloe_make_bed).state) done++; - if (id(chloe_brush_teeth).state) done++; - if (id(chloe_water_plants).state) done++; - if (id(chloe_homework).state) done++; - if (id(chloe_tidy_room).state) done++; - if (id(chloe_practice_piano).state) done++; - return done; - - - -# ── Scripts — reset + UI update ─────────────────────────────────────────────── -script: - - id: reset_jordyn_chores - mode: single - then: - - lambda: |- - id(jordyn_make_bed).turn_off(); - id(jordyn_brush_teeth).turn_off(); - id(jordyn_tidy_room).turn_off(); - id(jordyn_homework).turn_off(); - id(jordyn_feed_dog).turn_off(); - - script.execute: update_jordyn_ui - - - - id: update_jordyn_ui - mode: single - then: - - lambda: |- - int done = (id(jordyn_make_bed).state ? 1 : 0) + (id(jordyn_brush_teeth).state ? 1 : 0) + (id(jordyn_tidy_room).state ? 1 : 0) + (id(jordyn_homework).state ? 1 : 0) + (id(jordyn_feed_dog).state ? 1 : 0); - int total = 5; - char buf[24]; - - // Progress bar + label - lv_bar_set_value(id(progress_bar_jordyn), done, LV_ANIM_ON); - snprintf(buf, sizeof(buf), "%d / 5", done); - lv_label_set_text(id(progress_label_jordyn), buf); - - // All-done message in sidebar - lv_label_set_text(id(all_done_label_jordyn), done == total ? "\U0001F389 All done!" : ""); - - // Home button colour - if (done == total) { - 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_border_width(id(home_btn_jordyn), 0, LV_PART_MAIN); - lv_label_set_text(id(home_status_jordyn), "\u2713 all done!"); - lv_obj_set_style_text_color(id(home_status_jordyn), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - } else { - lv_obj_set_style_bg_opa(id(home_btn_jordyn), LV_OPA_TRANSP, LV_PART_MAIN); - lv_obj_set_style_border_color(id(home_btn_jordyn), lv_color_hex(0xFF4757), LV_PART_MAIN); - lv_obj_set_style_border_width(id(home_btn_jordyn), 5, LV_PART_MAIN); - snprintf(buf, sizeof(buf), "%d left", total - done); - lv_label_set_text(id(home_status_jordyn), buf); - lv_obj_set_style_text_color(id(home_status_jordyn), lv_color_hex(0xFF4757), LV_PART_MAIN); - } - - // Card colours - if (id(jordyn_make_bed).state) { - lv_obj_set_style_bg_color(id(card_jordyn_make_bed), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_jordyn_make_bed), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_jordyn_make_bed), 3, LV_PART_MAIN); - lv_label_set_text(id(check_jordyn_make_bed), "\u2705"); - } else { - lv_obj_set_style_bg_color(id(card_jordyn_make_bed), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_jordyn_make_bed), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_jordyn_make_bed), 2, LV_PART_MAIN); - lv_label_set_text(id(check_jordyn_make_bed), ""); - } - if (id(jordyn_brush_teeth).state) { - lv_obj_set_style_bg_color(id(card_jordyn_brush_teeth), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_jordyn_brush_teeth), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_jordyn_brush_teeth), 3, LV_PART_MAIN); - lv_label_set_text(id(check_jordyn_brush_teeth), "\u2705"); - } else { - lv_obj_set_style_bg_color(id(card_jordyn_brush_teeth), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_jordyn_brush_teeth), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_jordyn_brush_teeth), 2, LV_PART_MAIN); - lv_label_set_text(id(check_jordyn_brush_teeth), ""); - } - if (id(jordyn_tidy_room).state) { - lv_obj_set_style_bg_color(id(card_jordyn_tidy_room), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_jordyn_tidy_room), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_jordyn_tidy_room), 3, LV_PART_MAIN); - lv_label_set_text(id(check_jordyn_tidy_room), "\u2705"); - } else { - lv_obj_set_style_bg_color(id(card_jordyn_tidy_room), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_jordyn_tidy_room), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_jordyn_tidy_room), 2, LV_PART_MAIN); - lv_label_set_text(id(check_jordyn_tidy_room), ""); - } - if (id(jordyn_homework).state) { - lv_obj_set_style_bg_color(id(card_jordyn_homework), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_jordyn_homework), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_jordyn_homework), 3, LV_PART_MAIN); - lv_label_set_text(id(check_jordyn_homework), "\u2705"); - } else { - lv_obj_set_style_bg_color(id(card_jordyn_homework), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_jordyn_homework), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_jordyn_homework), 2, LV_PART_MAIN); - lv_label_set_text(id(check_jordyn_homework), ""); - } - if (id(jordyn_feed_dog).state) { - lv_obj_set_style_bg_color(id(card_jordyn_feed_dog), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_jordyn_feed_dog), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_jordyn_feed_dog), 3, LV_PART_MAIN); - lv_label_set_text(id(check_jordyn_feed_dog), "\u2705"); - } else { - lv_obj_set_style_bg_color(id(card_jordyn_feed_dog), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_jordyn_feed_dog), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_jordyn_feed_dog), 2, LV_PART_MAIN); - lv_label_set_text(id(check_jordyn_feed_dog), ""); - } - - - - id: reset_declan_chores - mode: single - then: - - lambda: |- - id(declan_make_bed).turn_off(); - id(declan_brush_teeth).turn_off(); - id(declan_set_table).turn_off(); - id(declan_take_out_trash).turn_off(); - - script.execute: update_declan_ui - - - - id: update_declan_ui - mode: single - then: - - lambda: |- - int done = (id(declan_make_bed).state ? 1 : 0) + (id(declan_brush_teeth).state ? 1 : 0) + (id(declan_set_table).state ? 1 : 0) + (id(declan_take_out_trash).state ? 1 : 0); - int total = 4; - char buf[24]; - - // Progress bar + label - lv_bar_set_value(id(progress_bar_declan), done, LV_ANIM_ON); - snprintf(buf, sizeof(buf), "%d / 4", done); - lv_label_set_text(id(progress_label_declan), buf); - - // All-done message in sidebar - lv_label_set_text(id(all_done_label_declan), done == total ? "\U0001F389 All done!" : ""); - - // Home button colour - if (done == total) { - 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_border_width(id(home_btn_declan), 0, LV_PART_MAIN); - lv_label_set_text(id(home_status_declan), "\u2713 all done!"); - lv_obj_set_style_text_color(id(home_status_declan), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - } else { - lv_obj_set_style_bg_opa(id(home_btn_declan), LV_OPA_TRANSP, LV_PART_MAIN); - lv_obj_set_style_border_color(id(home_btn_declan), lv_color_hex(0xFF4757), LV_PART_MAIN); - lv_obj_set_style_border_width(id(home_btn_declan), 5, LV_PART_MAIN); - snprintf(buf, sizeof(buf), "%d left", total - done); - lv_label_set_text(id(home_status_declan), buf); - lv_obj_set_style_text_color(id(home_status_declan), lv_color_hex(0xFF4757), LV_PART_MAIN); - } - - // Card colours - if (id(declan_make_bed).state) { - lv_obj_set_style_bg_color(id(card_declan_make_bed), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_declan_make_bed), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_declan_make_bed), 3, LV_PART_MAIN); - lv_label_set_text(id(check_declan_make_bed), "\u2705"); - } else { - lv_obj_set_style_bg_color(id(card_declan_make_bed), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_declan_make_bed), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_declan_make_bed), 2, LV_PART_MAIN); - lv_label_set_text(id(check_declan_make_bed), ""); - } - if (id(declan_brush_teeth).state) { - lv_obj_set_style_bg_color(id(card_declan_brush_teeth), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_declan_brush_teeth), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_declan_brush_teeth), 3, LV_PART_MAIN); - lv_label_set_text(id(check_declan_brush_teeth), "\u2705"); - } else { - lv_obj_set_style_bg_color(id(card_declan_brush_teeth), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_declan_brush_teeth), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_declan_brush_teeth), 2, LV_PART_MAIN); - lv_label_set_text(id(check_declan_brush_teeth), ""); - } - if (id(declan_set_table).state) { - lv_obj_set_style_bg_color(id(card_declan_set_table), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_declan_set_table), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_declan_set_table), 3, LV_PART_MAIN); - lv_label_set_text(id(check_declan_set_table), "\u2705"); - } else { - lv_obj_set_style_bg_color(id(card_declan_set_table), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_declan_set_table), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_declan_set_table), 2, LV_PART_MAIN); - lv_label_set_text(id(check_declan_set_table), ""); - } - if (id(declan_take_out_trash).state) { - lv_obj_set_style_bg_color(id(card_declan_take_out_trash), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_declan_take_out_trash), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_declan_take_out_trash), 3, LV_PART_MAIN); - lv_label_set_text(id(check_declan_take_out_trash), "\u2705"); - } else { - lv_obj_set_style_bg_color(id(card_declan_take_out_trash), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_declan_take_out_trash), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_declan_take_out_trash), 2, LV_PART_MAIN); - lv_label_set_text(id(check_declan_take_out_trash), ""); - } - - - - id: reset_chloe_chores - mode: single - then: - - lambda: |- - id(chloe_make_bed).turn_off(); - id(chloe_brush_teeth).turn_off(); - id(chloe_water_plants).turn_off(); - id(chloe_homework).turn_off(); - id(chloe_tidy_room).turn_off(); - id(chloe_practice_piano).turn_off(); - - script.execute: update_chloe_ui - - - - id: update_chloe_ui - mode: single - then: - - lambda: |- - int done = (id(chloe_make_bed).state ? 1 : 0) + (id(chloe_brush_teeth).state ? 1 : 0) + (id(chloe_water_plants).state ? 1 : 0) + (id(chloe_homework).state ? 1 : 0) + (id(chloe_tidy_room).state ? 1 : 0) + (id(chloe_practice_piano).state ? 1 : 0); - int total = 6; - char buf[24]; - - // Progress bar + label - lv_bar_set_value(id(progress_bar_chloe), done, LV_ANIM_ON); - snprintf(buf, sizeof(buf), "%d / 6", done); - lv_label_set_text(id(progress_label_chloe), buf); - - // All-done message in sidebar - lv_label_set_text(id(all_done_label_chloe), done == total ? "\U0001F389 All done!" : ""); - - // Home button colour - if (done == total) { - 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_border_width(id(home_btn_chloe), 0, LV_PART_MAIN); - lv_label_set_text(id(home_status_chloe), "\u2713 all done!"); - lv_obj_set_style_text_color(id(home_status_chloe), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - } else { - lv_obj_set_style_bg_opa(id(home_btn_chloe), LV_OPA_TRANSP, LV_PART_MAIN); - lv_obj_set_style_border_color(id(home_btn_chloe), lv_color_hex(0xFF4757), LV_PART_MAIN); - lv_obj_set_style_border_width(id(home_btn_chloe), 5, LV_PART_MAIN); - snprintf(buf, sizeof(buf), "%d left", total - done); - lv_label_set_text(id(home_status_chloe), buf); - lv_obj_set_style_text_color(id(home_status_chloe), lv_color_hex(0xFF4757), LV_PART_MAIN); - } - - // Card colours - if (id(chloe_make_bed).state) { - lv_obj_set_style_bg_color(id(card_chloe_make_bed), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_chloe_make_bed), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_chloe_make_bed), 3, LV_PART_MAIN); - lv_label_set_text(id(check_chloe_make_bed), "\u2705"); - } else { - lv_obj_set_style_bg_color(id(card_chloe_make_bed), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_chloe_make_bed), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_chloe_make_bed), 2, LV_PART_MAIN); - lv_label_set_text(id(check_chloe_make_bed), ""); - } - if (id(chloe_brush_teeth).state) { - lv_obj_set_style_bg_color(id(card_chloe_brush_teeth), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_chloe_brush_teeth), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_chloe_brush_teeth), 3, LV_PART_MAIN); - lv_label_set_text(id(check_chloe_brush_teeth), "\u2705"); - } else { - lv_obj_set_style_bg_color(id(card_chloe_brush_teeth), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_chloe_brush_teeth), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_chloe_brush_teeth), 2, LV_PART_MAIN); - lv_label_set_text(id(check_chloe_brush_teeth), ""); - } - if (id(chloe_water_plants).state) { - lv_obj_set_style_bg_color(id(card_chloe_water_plants), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_chloe_water_plants), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_chloe_water_plants), 3, LV_PART_MAIN); - lv_label_set_text(id(check_chloe_water_plants), "\u2705"); - } else { - lv_obj_set_style_bg_color(id(card_chloe_water_plants), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_chloe_water_plants), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_chloe_water_plants), 2, LV_PART_MAIN); - lv_label_set_text(id(check_chloe_water_plants), ""); - } - if (id(chloe_homework).state) { - lv_obj_set_style_bg_color(id(card_chloe_homework), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_chloe_homework), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_chloe_homework), 3, LV_PART_MAIN); - lv_label_set_text(id(check_chloe_homework), "\u2705"); - } else { - lv_obj_set_style_bg_color(id(card_chloe_homework), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_chloe_homework), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_chloe_homework), 2, LV_PART_MAIN); - lv_label_set_text(id(check_chloe_homework), ""); - } - if (id(chloe_tidy_room).state) { - lv_obj_set_style_bg_color(id(card_chloe_tidy_room), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_chloe_tidy_room), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_chloe_tidy_room), 3, LV_PART_MAIN); - lv_label_set_text(id(check_chloe_tidy_room), "\u2705"); - } else { - lv_obj_set_style_bg_color(id(card_chloe_tidy_room), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_chloe_tidy_room), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_chloe_tidy_room), 2, LV_PART_MAIN); - lv_label_set_text(id(check_chloe_tidy_room), ""); - } - if (id(chloe_practice_piano).state) { - lv_obj_set_style_bg_color(id(card_chloe_practice_piano), lv_color_hex(0xF0FFF4), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_chloe_practice_piano), lv_color_hex(0x6BCB77), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_chloe_practice_piano), 3, LV_PART_MAIN); - lv_label_set_text(id(check_chloe_practice_piano), "\u2705"); - } else { - lv_obj_set_style_bg_color(id(card_chloe_practice_piano), lv_color_hex(0xFFFFFF), LV_PART_MAIN); - lv_obj_set_style_border_color(id(card_chloe_practice_piano), lv_color_hex(0xEEEEEE), LV_PART_MAIN); - lv_obj_set_style_border_width(id(card_chloe_practice_piano), 2, LV_PART_MAIN); - lv_label_set_text(id(check_chloe_practice_piano), ""); - } - - - -# ── LVGL UI ─────────────────────────────────────────────────────────────────── -lvgl: - displays: - - main_display - touchscreens: - - touch - theme: - btn: - radius: 20 - border_width: 0 - pages: - - id: page_home - bg_color: 0xFFF9F0 - widgets: - - label: - x: 0 - y: 36 - width: 800 - align: TOP_MID - text: "Chore Tracker" - text_font: font_title - text_color: 0x2D3436 - - label: - x: 0 - y: 90 - width: 800 - align: TOP_MID - text: "Tap a name to check off chores" - text_font: font_small - text_color: 0xB2BEC3 - - btn: - x: 640 - y: 424 - width: 148 - height: 40 - bg_color: 0xFF4757 - radius: 12 - on_click: - then: - - script.execute: reset_jordyn_chores - - script.execute: reset_declan_chores - - script.execute: reset_chloe_chores - widgets: - - label: - align: CENTER - text: "↺ Reset All" - text_color: 0xFFFFFF - text_font: font_tiny - - btn: - id: home_btn_jordyn - x: 80 - y: 130 - width: 200 - height: 210 - bg_color: 0xFFFFFF - bg_opa: TRANSP - border_color: 0xFF4757 - border_width: 5 - radius: 24 - on_click: - then: - - lvgl.page.show: page_jordyn - widgets: - - label: - align: CENTER - y: -45 - text: "😺" - text_font: font_title - - label: - align: CENTER - y: 22 - text: "Jordyn" - text_font: font_name - text_color: 0x2D3436 - - label: - id: home_status_jordyn - align: CENTER - y: 66 - text: "not done" - text_font: font_tiny - text_color: 0xFF4757 - - - btn: - id: home_btn_declan - x: 300 - y: 130 - width: 200 - height: 210 - bg_color: 0xFFFFFF - bg_opa: TRANSP - border_color: 0xFF4757 - border_width: 5 - radius: 24 - on_click: - then: - - lvgl.page.show: page_declan - widgets: - - label: - align: CENTER - y: -45 - text: "🤓" - text_font: font_title - - label: - align: CENTER - y: 22 - text: "Declan" - text_font: font_name - text_color: 0x2D3436 - - label: - id: home_status_declan - align: CENTER - y: 66 - text: "not done" - text_font: font_tiny - text_color: 0xFF4757 - - - btn: - id: home_btn_chloe - x: 520 - y: 130 - width: 200 - height: 210 - bg_color: 0xFFFFFF - bg_opa: TRANSP - border_color: 0xFF4757 - border_width: 5 - radius: 24 - on_click: - then: - - lvgl.page.show: page_chloe - widgets: - - label: - align: CENTER - y: -45 - text: "🌝" - text_font: font_title - - label: - align: CENTER - y: 22 - text: "Chloe" - text_font: font_name - text_color: 0x2D3436 - - label: - id: home_status_chloe - align: CENTER - y: 66 - text: "not done" - text_font: font_tiny - text_color: 0xFF4757 - - - - id: page_jordyn - bg_color: 0xFFF9F0 - widgets: - - # ── Sidebar ────────────────────────────────────────────────────────── - - obj: - x: 0 - y: 0 - width: 172 - height: 480 - bg_color: 0x4D96FF - border_width: 0 - radius: 0 - pad_all: 0 - widgets: - - label: - x: 0 - y: 22 - width: 172 - align: TOP_MID - text: "😺" - text_font: font_title - - label: - x: 0 - y: 76 - width: 172 - align: TOP_MID - text: "Jordyn" - text_font: font_name - text_color: 0xFFFFFF - - bar: - id: progress_bar_jordyn - x: 14 - y: 132 - width: 144 - height: 16 - bg_color: 0x2A6FCC - indicator: - bg_color: 0xFFFFFF - value: 0 - min_value: 0 - max_value: 5 - - label: - id: progress_label_jordyn - x: 0 - y: 156 - width: 172 - align: TOP_MID - text: "0 / 5" - text_font: font_small - text_color: 0xDDEEFF - - label: - id: all_done_label_jordyn - x: 0 - y: 192 - width: 172 - align: TOP_MID - text: "" - text_font: font_small - text_color: 0xFFFFFF - - btn: - x: 14 - y: 364 - width: 144 - height: 44 - bg_color: 0xFF4757 - radius: 14 - on_click: - then: - - script.execute: reset_jordyn_chores - widgets: - - label: - align: CENTER - text: "↺ Reset" - text_color: 0xFFFFFF - text_font: font_small - - btn: - x: 14 - y: 420 - width: 144 - height: 44 - bg_color: 0x2A6FCC - radius: 14 - on_click: - then: - - lvgl.page.show: page_home - widgets: - - label: - align: CENTER - text: "◀ Home" - text_color: 0xFFFFFF - text_font: font_small - - # ── Chore cards ─────────────────────────────────────────────────────── - - btn: - id: card_jordyn_make_bed - x: 182 - y: 10 - width: 196 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: jordyn_make_bed - widgets: - - label: - id: check_jordyn_make_bed - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🛏️" - text_font: font_med - - label: - align: CENTER - y: 17 - text: "Make Bed" - text_font: font_small - text_color: 0x2D3436 - - - btn: - id: card_jordyn_brush_teeth - x: 388 - y: 10 - width: 196 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: jordyn_brush_teeth - widgets: - - label: - id: check_jordyn_brush_teeth - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🦷" - text_font: font_med - - label: - align: CENTER - y: 17 - text: "Brush Teeth" - text_font: font_small - text_color: 0x2D3436 - - - btn: - id: card_jordyn_tidy_room - x: 594 - y: 10 - width: 196 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: jordyn_tidy_room - widgets: - - label: - id: check_jordyn_tidy_room - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🧹" - text_font: font_med - - label: - align: CENTER - y: 17 - text: "Tidy Room" - text_font: font_small - text_color: 0x2D3436 - - - btn: - id: card_jordyn_homework - x: 182 - y: 158 - width: 196 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: jordyn_homework - widgets: - - label: - id: check_jordyn_homework - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "📚" - text_font: font_med - - label: - align: CENTER - y: 17 - text: "Homework" - text_font: font_small - text_color: 0x2D3436 - - - btn: - id: card_jordyn_feed_dog - x: 388 - y: 158 - width: 196 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: jordyn_feed_dog - widgets: - - label: - id: check_jordyn_feed_dog - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🐾" - text_font: font_med - - label: - align: CENTER - y: 17 - text: "Feed Dog" - text_font: font_small - text_color: 0x2D3436 - - - - id: page_declan - bg_color: 0xFFF9F0 - widgets: - - # ── Sidebar ────────────────────────────────────────────────────────── - - obj: - x: 0 - y: 0 - width: 172 - height: 480 - bg_color: 0xC77DFF - border_width: 0 - radius: 0 - pad_all: 0 - widgets: - - label: - x: 0 - y: 22 - width: 172 - align: TOP_MID - text: "🤓" - text_font: font_title - - label: - x: 0 - y: 76 - width: 172 - align: TOP_MID - text: "Declan" - text_font: font_name - text_color: 0xFFFFFF - - bar: - id: progress_bar_declan - x: 14 - y: 132 - width: 144 - height: 16 - bg_color: 0x8B42CC - indicator: - bg_color: 0xFFFFFF - value: 0 - min_value: 0 - max_value: 4 - - label: - id: progress_label_declan - x: 0 - y: 156 - width: 172 - align: TOP_MID - text: "0 / 4" - text_font: font_small - text_color: 0xDDEEFF - - label: - id: all_done_label_declan - x: 0 - y: 192 - width: 172 - align: TOP_MID - text: "" - text_font: font_small - text_color: 0xFFFFFF - - btn: - x: 14 - y: 364 - width: 144 - height: 44 - bg_color: 0xFF4757 - radius: 14 - on_click: - then: - - script.execute: reset_declan_chores - widgets: - - label: - align: CENTER - text: "↺ Reset" - text_color: 0xFFFFFF - text_font: font_small - - btn: - x: 14 - y: 420 - width: 144 - height: 44 - bg_color: 0x8B42CC - radius: 14 - on_click: - then: - - lvgl.page.show: page_home - widgets: - - label: - align: CENTER - text: "◀ Home" - text_color: 0xFFFFFF - text_font: font_small - - # ── Chore cards ─────────────────────────────────────────────────────── - - btn: - id: card_declan_make_bed - x: 182 - y: 10 - width: 196 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: declan_make_bed - widgets: - - label: - id: check_declan_make_bed - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🛏️" - text_font: font_med - - label: - align: CENTER - y: 17 - text: "Make Bed" - text_font: font_small - text_color: 0x2D3436 - - - btn: - id: card_declan_brush_teeth - x: 388 - y: 10 - width: 196 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: declan_brush_teeth - widgets: - - label: - id: check_declan_brush_teeth - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🦷" - text_font: font_med - - label: - align: CENTER - y: 17 - text: "Brush Teeth" - text_font: font_small - text_color: 0x2D3436 - - - btn: - id: card_declan_set_table - x: 594 - y: 10 - width: 196 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: declan_set_table - widgets: - - label: - id: check_declan_set_table - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🍽️" - text_font: font_med - - label: - align: CENTER - y: 17 - text: "Set Table" - text_font: font_small - text_color: 0x2D3436 - - - btn: - id: card_declan_take_out_trash - x: 182 - y: 158 - width: 196 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: declan_take_out_trash - widgets: - - label: - id: check_declan_take_out_trash - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🗑️" - text_font: font_med - - label: - align: CENTER - y: 17 - text: "Take Out Trash" - text_font: font_small - text_color: 0x2D3436 - - - - id: page_chloe - bg_color: 0xFFF9F0 - widgets: - - # ── Sidebar ────────────────────────────────────────────────────────── - - obj: - x: 0 - y: 0 - width: 172 - height: 480 - bg_color: 0xFF6B9D - border_width: 0 - radius: 0 - pad_all: 0 - widgets: - - label: - x: 0 - y: 22 - width: 172 - align: TOP_MID - text: "🌝" - text_font: font_title - - label: - x: 0 - y: 76 - width: 172 - align: TOP_MID - text: "Chloe" - text_font: font_name - text_color: 0xFFFFFF - - bar: - id: progress_bar_chloe - x: 14 - y: 132 - width: 144 - height: 16 - bg_color: 0xCC3A6F - indicator: - bg_color: 0xFFFFFF - value: 0 - min_value: 0 - max_value: 6 - - label: - id: progress_label_chloe - x: 0 - y: 156 - width: 172 - align: TOP_MID - text: "0 / 6" - text_font: font_small - text_color: 0xDDEEFF - - label: - id: all_done_label_chloe - x: 0 - y: 192 - width: 172 - align: TOP_MID - text: "" - text_font: font_small - text_color: 0xFFFFFF - - btn: - x: 14 - y: 364 - width: 144 - height: 44 - bg_color: 0xFF4757 - radius: 14 - on_click: - then: - - script.execute: reset_chloe_chores - widgets: - - label: - align: CENTER - text: "↺ Reset" - text_color: 0xFFFFFF - text_font: font_small - - btn: - x: 14 - y: 420 - width: 144 - height: 44 - bg_color: 0xCC3A6F - radius: 14 - on_click: - then: - - lvgl.page.show: page_home - widgets: - - label: - align: CENTER - text: "◀ Home" - text_color: 0xFFFFFF - text_font: font_small - - # ── Chore cards ─────────────────────────────────────────────────────── - - btn: - id: card_chloe_make_bed - x: 182 - y: 10 - width: 196 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: chloe_make_bed - widgets: - - label: - id: check_chloe_make_bed - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🛏️" - text_font: font_med - - label: - align: CENTER - y: 17 - text: "Make Bed" - text_font: font_small - text_color: 0x2D3436 - - - btn: - id: card_chloe_brush_teeth - x: 388 - y: 10 - width: 196 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: chloe_brush_teeth - widgets: - - label: - id: check_chloe_brush_teeth - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🦷" - text_font: font_med - - label: - align: CENTER - y: 17 - text: "Brush Teeth" - text_font: font_small - text_color: 0x2D3436 - - - btn: - id: card_chloe_water_plants - x: 594 - y: 10 - width: 196 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: chloe_water_plants - widgets: - - label: - id: check_chloe_water_plants - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🌱" - text_font: font_med - - label: - align: CENTER - y: 17 - text: "Water Plants" - text_font: font_small - text_color: 0x2D3436 - - - btn: - id: card_chloe_homework - x: 182 - y: 158 - width: 196 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: chloe_homework - widgets: - - label: - id: check_chloe_homework - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "📚" - text_font: font_med - - label: - align: CENTER - y: 17 - text: "Homework" - text_font: font_small - text_color: 0x2D3436 - - - btn: - id: card_chloe_tidy_room - x: 388 - y: 158 - width: 196 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: chloe_tidy_room - widgets: - - label: - id: check_chloe_tidy_room - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🧹" - text_font: font_med - - label: - align: CENTER - y: 17 - text: "Tidy Room" - text_font: font_small - text_color: 0x2D3436 - - - btn: - id: card_chloe_practice_piano - x: 594 - y: 158 - width: 196 - height: 138 - bg_color: 0xFFFFFF - border_color: 0xEEEEEE - border_width: 2 - radius: 20 - shadow_color: 0xCCCCCC - shadow_width: 4 - shadow_ofs_y: 3 - on_click: - then: - - switch.toggle: chloe_practice_piano - widgets: - - label: - id: check_chloe_practice_piano - align: TOP_RIGHT - x: -10 - y: 8 - text: "" - text_font: font_med - - label: - align: CENTER - y: -34 - text: "🎹" - text_font: font_med - - label: - align: CENTER - y: 17 - text: "Practice Piano" - text_font: font_small - text_color: 0x2D3436 - -