Skip to content

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 of 2026-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; }
Pair with a 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-card verbatim as the first card.
  • [ ] Step 2 — Room temps (P3): a grid columns: 2 of two thermostat glance tiles — reuse the Overview's current climate tile body (big temp + status dot + Heat–Cool range), tap_action: navigate to the existing #thermo-bedroom / #thermo-office pop-ups (global — already defined in Overview). Add an occupancy badge to each tile's body JS: read the room's binary_sensor.*_occupancy (Bedroom→binary_sensor.bedroom_occupancy, Office→binary_sensor.office_occupancy) and render a small "occupied"/"empty" pill (green dot when on).
  • [ ] Step 3 — "Why" / differential card (P3): a full-width glass button-card whose body JS computes bedroom.current_temperature − office.current_temperature and annotates with each thermostat's hvac_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 via card_mod) plotting climate.bedroom and climate.office current_temperature over 24h (two entities with attribute: current_temperature, name: each).
  • [ ] Step 5 — Food temps (P3): a grid columns: 2/3 of 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). Commit auto: 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 grid of glass tiles — current TOU period/rate (amber when peak/input_boolean.peak_mode on), 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-card list of the em_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 grid of small glass tiles, one per occupancy sensor, green dot + room name when on, dim when off. Add a YAML comment: "future mmWave/presence sensors slot in here as more tiles."
  • [ ] Step 3 — Who's home: person.louis, person.lindsay as mushroom-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 #leaks Bubble-Card pop-up listing all ~10 leak detectors as an entities card (or mushroom rows) with dry/wet state.
  • [ ] Step 6 — Front-door camera glance: a picture-glance or picture-entity of camera.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 grid columns: 2 of picture-glance cards for the 3 cameras (live thumbnail + name), each tap_action: { action: more-info } (fullscreen live). YAML comment: "Tapo cameras append here as their camera.* entities are created."
  • [ ] Step 2 — Recent-motion rail (P3): a full-width glass button-card whose body JS lists the most-recent camera activity from sensor.garage_stickup_cam_1_last_activity / sensor.personnel_door_last_activity (relative time via last_changed/state) and any binary_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.yml nav. Build mkdocs build --strict (or python -m mkdocs build --strict; if not installed locally, note that docs.yml CI validates on push). Commit auto: 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 (needs HA_URL+HA_TOKEN).
  • [ ] Step 2: Remove the 6 Command-backend forward-refs from tests/fixtures/entities_allow.txt (the binary_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/cameras under /command-center; pop-up hashes #thermo-bedroom/#thermo-office/#garage/#media/#leaks; backend entities sensor.leak_status/sensor.food_status/binary_sensor.any_leak_wet; scripts script.good_night/script.all_lights_off/script.movie_mode — all already live from earlier tasks. ✓