Command Dashboard — Remaining Tabs Implementation Plan¶
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development. Steps use checkbox (
- [ ]) syntax. This plan supersedes Tasks 6–9/11/12 of2026-06-17-command-dashboard-redesign.md, incorporating the patterns proven on-device while building the Overview tab.
Goal: Add the Climate, Energy, Security, and Cameras tabs to the already-live command_dashboard.yaml, reusing the Overview's proven Midnight Glass / Bubble-Card patterns, then ship the manual page and final snapshot.
Status of the build so far (DONE, live): backend templates + scripts (Task 1), dashboard scaffold + registration + kiosk (Task 2), and the full Overview tab (hero w/ 4-day forecast, status chips, Now Playing bar, climate+power glances, quick actions, thermostat/garage/media pop-ups), plus CI/test wiring (Task 10). The old Home Command Dashboard remains untouched.
Pattern Library (proven on the Overview — reuse verbatim)¶
These are the exact, on-device-verified idioms. Subagents should open command_dashboard.yaml and copy these, substituting entities. All live in one YAML-mode file; pop-ups are global to the dashboard (a pop-up defined in any view opens from any view).
Design tokens (Midnight Glass): view background: "radial-gradient(130% 80% at 50% -5%, #1a2440 0%, #0a0e1a 55%) fixed". Glass card: background: rgba(255,255,255,0.10), border: 1px solid rgba(255,255,255,0.20), border-radius: 16px, backdrop-filter: blur(9px) (+-webkit-), box-shadow: none. Text #e7ecf6 / muted #9fb0d0/#8aa0c8; accent #6ea8ff; green #34d399/#6ee7b7, amber #fbbf24, red #ef4444, heat #fb923c, cool #6ea8ff, media purple #c4b5fd. No emoji in status/chip rows (icons/dots only).
P1 — Hero (copy the Overview hero button-card verbatim onto each tab; the greeting+weather+4-day strip is fine on every tab). Forecast provider returns only 5 daily entries (today + 4) → strip uses fc.slice(1,5) = 4 days; today's H/L stays on the current-conditions line.
P2 — Status chip row (button-card, tap_action: none, triggers_update: all): a chips custom_field building pills with const chip=(txt,col)=> + a colored ●. Display-only. Per-tab chip rows pick relevant statuses.
P3 — Glass glance tile (button-card + custom_fields.body [[[ JS ]]]): a fixed-height glass tile rendering a value. For temperatures, do NOT use an arbitrary conic ring — show a big number + a small colored status dot + a sub-line (e.g. setpoint range). tap_action: navigate → '#hash' to open a pop-up.
P4 — Bubble-Card pop-up: - type: custom:bubble-card / card_type: pop-up / hash: '#id' / name: / icon: / cards: [...]. Opened by any tile's tap_action: { action: navigate, navigation_path: '#id' }.
P5 — Native thermostat in a pop-up (control enabled — user opted in; the Ecobee-owns-HVAC rule still forbids HVAC automations, not manual cards):
- type: thermostat
entity: climate.bedroom
features:
- type: climate-hvac-modes
card_mod:
style: |
ha-card { background: transparent; border: none; box-shadow: none; }
custom:mini-graph-card (attribute: current_temperature, hours_to_show: 24) for the trend. P6 — Action / launcher tile = mushroom-template-card, NOT button-card. button-card's native icon collapses when the card has no entity; mushroom renders icons reliably:
- type: custom:mushroom-template-card
icon: mdi:weather-night
icon_color: purple # red/amber/green/blue/purple or rgb
primary: Good Night
layout: vertical
tap_action: { action: call-service, service: script.good_night } # or action: navigate, navigation_path: '#hash'
card_mod:
style: |
ha-card { background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.13); border-radius: 13px; box-shadow: none; height: 80px; --card-primary-font-size: 11px; }
P7 — Graph card (apexcharts), glass-framed:
- type: custom:apexcharts-card
graph_span: 24h
span: { start: day }
card_mod: { style: "ha-card { background: rgba(255,255,255,0.10); border: 1px solid rgba(255,255,255,0.20); border-radius: 16px; backdrop-filter: blur(9px); -webkit-backdrop-filter: blur(9px); box-shadow: none; }" }
header: { show: true, title: Power, show_states: true, colorize_states: true }
apex_config: { chart: { height: 130 }, grid: { show: false } }
series:
- entity: sensor.whole_home_power
type: area
extend_to: now
stroke_width: 2
color: "#7fd4e8"
group_by: { func: avg, duration: 15min }
Conventions (every task): - Append each tab as a new - title: … view under views: in command_dashboard.yaml (6-space list items inside the view's cards:). Add path: (lowercase, the tab url), icon:, and the Midnight Glass background:. - .yamllint disables line-length — long [[[ JS ]]] lines are fine. Gate every task with make lint && make pytest (expect "20 passed"), plus python3 -c "import yaml; d=yaml.safe_load(open('command_dashboard.yaml')); print(len(d['views']),'views')". - Entity-ref scan: command_dashboard.yaml uses the default conftest scan (not bare_scan) because chip JS concatenates ids ("input_number.plant_"+s) which bare_scan would mis-read. Keep it that way. Any states('entity') template-fn refs you add ARE checked — ensure those entities exist. - Deploy cadence: commit per task; push after each tab so it deploys (CI restart) and gets an on-device check before the next. Commit trailer: Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>. - There is a pre-existing unrelated automations.yaml modification in the working tree — never stage/commit it.
Task A: Climate tab¶
Files: Modify command_dashboard.yaml (append a - title: Climate view: path: climate, icon: mdi:thermometer, Midnight Glass background).
Entities: climate.bedroom, climate.office; occupancy binary_sensor.bedroom_1_occupancy…_4_occupancy, binary_sensor.bedroom_occupancy, binary_sensor.office_occupancy; food-temp sensor.freezer_temperature_sensor_temperature, sensor.refrigerator_freezer_temperature_sensor_temperature, sensor.refrigerator_temperature_sensor_temperature (verify the third exists in tests/fixtures/entities.txt; omit if absent). No CO₂/VOC cards.
- [ ] Step 1 — Hero: copy the Overview hero
button-cardverbatim as the first card. - [ ] Step 2 — Room temps (P3): a
gridcolumns: 2of two thermostat glance tiles — reuse the Overview's current climate tile body (big temp + status dot +Heat–Coolrange),tap_action: navigateto the existing#thermo-bedroom/#thermo-officepop-ups (global — already defined in Overview). Add an occupancy badge to each tile's body JS: read the room'sbinary_sensor.*_occupancy(Bedroom→binary_sensor.bedroom_occupancy, Office→binary_sensor.office_occupancy) and render a small "occupied"/"empty" pill (green dot whenon). - [ ] Step 3 — "Why" / differential card (P3): a full-width glass
button-cardwhose body JS computesbedroom.current_temperature − office.current_temperatureand annotates with each thermostat'shvac_action+ occupancy, e.g.Bedroom 71° · Office 73° (+2°) · Office occupied · both idle. Observe-only (no service calls). - [ ] Step 4 — Trends: a
custom:mini-graph-card(glass viacard_mod) plottingclimate.bedroomandclimate.officecurrent_temperatureover 24h (twoentitieswithattribute: current_temperature,name:each). - [ ] Step 5 — Food temps (P3): a
gridcolumns: 2/3of glass tiles for the food-temp sensors. Each tile body: big temp °F + a colored dot (green in range, amber/red if warm — thresholds: fridge warm > 42°F, freezer warm > 10°F as a reasonable default). Label each (Fridge / Fridge-Freezer / Deep Freezer). The Overview chip is the summary; this is the detail. - [ ] Step 6: Gate (
make lint && make pytest; views count = 2). Commitauto: command — Climate tab (room temps+occupancy, differential, trends, food-temp; no CO2/VOC). Push, watch CI green, on-device check.
Task B: Energy tab¶
Files: Modify command_dashboard.yaml (append - title: Energy view: path: energy, icon: mdi:lightning-bolt).
Source of truth for content: the current dashboard's Energy view — read it first so nothing is lost (user loves the power data): ssh root@192.168.4.93 "cat /config/.storage/lovelace.home_command_dashboard" → python3 to dump data.config.views[1] (Energy) card list.
Entities: sensor.tou_period, sensor.tou_rate, input_boolean.peak_mode, sensor.energy_cost_today, sensor.energy_cost_this_month, sensor.energy_cost_accumulated, sensor.whole_home_power; per-circuit sensor.em_power_* and Refoss em_channel_* (Panel 1 lighting) / a1..c6 (Panel 2 appliances; AC condensers a5/a6/b5 per memory).
- [ ] Step 1 — Hero (copy verbatim).
- [ ] Step 2 — TOU + cost summary (P3): a
gridof glass tiles — current TOU period/rate (amber whenpeak/input_boolean.peak_modeon), today's cost (sensor.energy_cost_today), month-to-date bill (sensor.energy_cost_this_month). - [ ] Step 3 — Whole-home power graph (P7): apexcharts day-graph of
sensor.whole_home_power(reuse the Overview power card config; can be taller here, e.g. height 200). - [ ] Step 4 — Per-circuit breakdown: mirror the current Energy tab's circuit groupings reskinned to glass — an
entities/mushroom/button-cardlist of theem_power_*/em_channel_*circuits (lighting vs appliances vs condensers). Keep ALL circuits the current tab shows. - [ ] Step 5 — Usage/cost history: apexcharts/mini-graph of daily cost or kWh (reuse whatever the current Energy tab trends).
- [ ] Step 6: Gate; views = 3. Commit
auto: command — Energy tab (all TOU/cost/power/per-circuit data, reskinned to glass). Push, CI, on-device check.
Task C: Security tab¶
Files: Modify command_dashboard.yaml (append - title: Security view: path: security, icon: mdi:shield-home). Also add a #leaks Bubble-Card pop-up.
Entities: occupancy binary_sensor.bedroom_1_occupancy…_4_occupancy, binary_sensor.bedroom_occupancy, binary_sensor.office_occupancy; person.louis, person.lindsay; garage cover.left_garage_door_opener_garage_door, cover.right_garage_door_opener_garage_door (reuse #garage pop-up); leaks sensor.leak_status + the ~10 binary_sensor.*_leak_detector/*_leak_sensor (see redesign spec for the list); camera.personnel_door_live_view. No battery cards.
- [ ] Step 1 — Hero (copy verbatim).
- [ ] Step 2 — Room presence panel (featured) (P3): a
gridof small glass tiles, one per occupancy sensor, green dot + room name whenon, dim whenoff. Add a YAML comment: "future mmWave/presence sensors slot in here as more tiles." - [ ] Step 3 — Who's home:
person.louis,person.lindsayasmushroom-person-cards (or glass tiles) showing home/away. - [ ] Step 4 — Doors & garage: a
mushroom-template-card(P6) "Garage" tile →tap_action: navigate '#garage'; plus any door binary_sensors as status tiles if present. - [ ] Step 5 — Leak summary + pop-up: a glass tile bound to
sensor.leak_status(green "All dry" / red wet list) →tap_action: navigate '#leaks'. Add a#leaksBubble-Card pop-up listing all ~10 leak detectors as anentitiescard (or mushroom rows) with dry/wet state. - [ ] Step 6 — Front-door camera glance: a
picture-glanceorpicture-entityofcamera.personnel_door_live_view,tap_action: navigate '/command-center/cameras'. - [ ] Step 7: Gate; views = 4. Commit
auto: command — Security tab (room presence, who's home, garage, leak summary+pop-up, cam glance). Push, CI, on-device check.
Task D: Cameras tab¶
Files: Modify command_dashboard.yaml (append - title: Cameras view: path: cameras, icon: mdi:cctv).
Entities: camera.garage_stickup_cam_1_live_view, camera.personnel_door_live_view, camera.wyze_cam_v3_1; recent-activity sensor.garage_stickup_cam_1_last_activity, sensor.personnel_door_last_activity; motion binary_sensor.office_cam_motion (and Ring motion binaries if present).
- [ ] Step 1 — Live grid: a
gridcolumns: 2ofpicture-glancecards for the 3 cameras (live thumbnail + name), eachtap_action: { action: more-info }(fullscreen live). YAML comment: "Tapo cameras append here as theircamera.*entities are created." - [ ] Step 2 — Recent-motion rail (P3): a full-width glass
button-cardwhose body JS lists the most-recent camera activity fromsensor.garage_stickup_cam_1_last_activity/sensor.personnel_door_last_activity(relative time vialast_changed/state) and anybinary_sensor.*_motion, newest first. Cameras without event data still appear live in the grid (graceful degradation). - [ ] Step 3: Gate; views = 5. Commit
auto: command — Cameras tab (live grid + recent-activity rail; scales to Tapo). Push, CI, on-device check.
Task E: Manual page¶
Files: Create docs/command.md; modify mkdocs.yml nav.
- [ ] Step 1: Read
mkdocs.yml+ an existing page (e.g.docs/climate.md) for voice/structure. - [ ] Step 2: Write
docs/command.md— household-facing: the 5 tabs, the status chips (what each color/dot means), the Now Playing bar, and the pop-ups (tap a thermostat → native dial you can adjust; tap garage/leaks/media). Plain language, tables,!!! tip. No broken internal links. - [ ] Step 3: Add to
mkdocs.ymlnav. Buildmkdocs build --strict(orpython -m mkdocs build --strict; if not installed locally, note thatdocs.ymlCI validates on push). Commitauto: docs — add Command dashboard manual page.
Task F: Final snapshot + close-out¶
Files: tests/fixtures/entities.txt, tests/fixtures/entities_allow.txt.
- [ ] Step 1: After all tabs are deployed and HA has restarted with the backend live, run
make snapshot(needsHA_URL+HA_TOKEN). - [ ] Step 2: Remove the 6 Command-backend forward-refs from
tests/fixtures/entities_allow.txt(thebinary_sensor.any_leak_wet/sensor.leak_status/sensor.food_status/script.*block) now that they're in the snapshot.make pytest→ PASS. - [ ] Step 3: Commit
auto: tests — snapshot Command backend entities, drop their allowlist entries. Push.
Self-Review (against the redesign spec)¶
- Climate (room temps + occupancy + differential + trends + food-temp, no CO₂/VOC, thermostats now controllable via the native dial pop-up) → Task A. ✓
- Energy (ALL power/TOU/cost/per-circuit, reskinned) → Task B, with an explicit "read the current Energy view first" step so nothing is dropped. ✓
- Security (Ecobee room presence featured + future headroom, who's home, garage, leak summary+pop-up, cam glance, no batteries) → Task C. ✓
- Cameras (live grid + recent-activity rail, scales to Tapo) → Task D. ✓
- Manual + snapshot → Tasks E/F. ✓
- Media stays a pop-up (done on Overview); no Media/Garden tab; Health/Morning/Sleep dropped — consistent. ✓
- No placeholders: each task names exact entities and which pattern (P1–P7) to copy; the two genuine lookups (current Energy view dump; verify the third fridge sensor) are explicit, bounded discovery steps. ✓
- Consistency: view paths
climate/energy/security/camerasunder/command-center; pop-up hashes#thermo-bedroom/#thermo-office/#garage/#media/#leaks; backend entitiessensor.leak_status/sensor.food_status/binary_sensor.any_leak_wet; scriptsscript.good_night/script.all_lights_off/script.movie_mode— all already live from earlier tasks. ✓