Master-Bedroom Sitting-Area Lamp — Automations¶
Date: 2026-07-07 Ticket: #72 Status: Approved (design settled via brainstorm; device corrected to plug_2)
Context¶
switch.upstairs_hallway_plug_2 is a power-monitored ZHA smart plug (on/off only) that now physically powers a wall lamp in the master-bedroom sitting area.
Clean slate — plug_2 has no automations today. (The §11 "Upstairs Hallway" schedule and the §49 toggle button belong to a different plug, switch.upstairs_hallway_1 = Henry's Ramen Sign — do not touch those.) plug_2 is not in group.lights, so Good Night doesn't currently turn it off; the renderer's sleeping → off will (single-owner). plug_2 is referenced by homekit.yaml (exposed to Apple Home) and the Command dashboard (a power-monitoring card + a switch tile).
Goal¶
Four coordinated behaviors on the (on/off) sitting lamp, driven by one priority renderer (same pattern as script.night_lights_render) so they never fight over the plug: evening ambiance, wake-to-lamp, movie mode, and away presence-simulation. Plus rename the entity to match reality.
Step 0 — Rename the entity¶
Rename the switch entity id (ZHA, live registry — controller step, not a repo edit): switch.upstairs_hallway_plug_2 → switch.master_bedroom_sitting_lamp.
Update the repo references to the switch: - homekit.yaml — the whitelist entry (~line 48) and the entity_config key + its name: (~line 100 → name: Master Bedroom Sitting Lamp). - lovelace/home_command_dashboard.json — the switch tile entity ref (~line 857). Storage-mode dashboard: pull fresh first (user also edits it in the UI), edit, deploy via deploy-lovelace.
Scope: rename the switch only. Leave the diagnostic sensors (sensor.upstairs_hallway_plug_2_power/_voltage/_summation_delivered/_lqi/…) as-is — this preserves InfluxDB energy history and keeps the dashboard's power-monitoring card working (those tiles reference the sensor ids, which don't change). The card keeps its "Upstairs Hallway Plug 2" label (cosmetic; relabel later if desired).
Apple Home caveat (accepted): renaming a HomeKit-bridged entity makes the bridge drop and re-add the accessory, so it reappears in the Apple Home app as a new device — re-assign its room/name there once after deploy.
Because the config references the new id before the live registry has it, add switch.master_bedroom_sitting_lamp to tests/fixtures/entities_allow.txt (with a #-comment); fold into entities.txt via make snapshot after deploy.
Component A — script.master_bedroom_sitting_lamp_render (the brain)¶
Single renderer that decides on/off from a priority stack (top wins), via a choose: whose conditions are evaluated in order (first match wins) — mirrors script.night_lights_render.
1. away (zone.home count == 0) -> STOP (yield; away-sim owns lamp)
2. waking (input_boolean.morning_armed on) AND dark -> switch.turn_on (outranks sleeping)
3. sleeping (input_boolean.sleeping on) -> switch.turn_off
4. movie (master_bedroom_apple_tv playing OR bedroom_tv on) -> switch.turn_off
5. occupied (bedroom_occupancy on) AND dark AND time 16:00-02:00 -> switch.turn_on (evening ambiance)
default -> switch.turn_off
dark = sun.sun is below_horizon. The away branch uses a stop: action (yield). The 20-min "empty" delay is not here — it lives in the occupancy trigger's for: (Component B), so the renderer reads binary_sensor.bedroom_occupancy directly. mode: restart.
Wake-to-lamp lives here (priority 2), triggered by input_boolean.morning_armed → on — the moment the phone comes off the charger and arms Good Morning, while you're still in the bedroom (before the kitchen-motion stage). It outranks sleeping (still on at arm time).
Morning-off is the kitchen-motion moment. When you reach the kitchen, its NL2 motion fires Good Morning, which clears morning_armed and sleeping. morning_armed→off re-runs the renderer (Component B trigger): priority 2 is now false, so the lamp drops — and it stays off because the Evening rule (priority 5) is time-gated to 16:00–02:00, excluding the early-morning wake window. This gate is essential: a partner still asleep in bed keeps bedroom_occupancy on, so without the time gate the Evening rule would re-light the lamp at 5 AM after Good Morning cleared sleeping. With it, once you're downstairs making coffee the bedroom goes dark for the sleeping partner. The dark gate on wake also keeps it from lighting in summer daylight.
Component B — automation: master_bedroom_sitting_lamp_render_triggers¶
One automation, many triggers, one action (script.master_bedroom_sitting_lamp_render), mode: restart. Triggers: - input_boolean.morning_armed (any state change) - input_boolean.sleeping (any state change) - binary_sensor.bedroom_occupancy → on (immediate) - binary_sensor.bedroom_occupancy → off for 00:20:00 (the empty-delay) - sun.sun → below_horizon and → above_horizon (the two real transitions — not a bare trigger, which would fire on every elevation attribute update) - media_player.master_bedroom_apple_tv and media_player.bedroom_tv (state change — movie) - zone.home (state change — returning home re-renders and takes the lamp back from the sim)
Component C — Away presence-simulation¶
automation: master_bedroom_sitting_lamp_away_sim—time_patternevery 30 min; conditions away ANDsunbelow_horizon ANDnow < 23:00; action:if [true,false]|random then turn_on else turn_off. Randomized evening presence.automation: master_bedroom_sitting_lamp_away_off— at23:00, if away,switch.turn_off(so it doesn't sit on overnight). Return-home re-render is Component B'szone.hometrigger.
The renderer yields while away (priority 1 → stop), so sim and renderer never fight: sim owns the lamp when away, renderer when home.
Known limitations¶
- On/off only (plain bulb) — no dimming/circadian.
- Manual override is soft: a manual toggle (Apple Home/app) sticks only until the next render trigger fires; since the renderer fires on state changes, a manual off while sitting still (stable occupancy) persists until a real event (sun/TV/sleep/leave). Acceptable.
- Presence-sim is a fixed 30-min cadence.
Testing¶
- Entity-ref (Tier 3): driving entities exist;
switch.master_bedroom_sitting_lampgoes inentities_allow.txtuntilmake snapshotpost-deploy. - New structural test
tests/test_sitting_lamp.py: the 3 new automations + the render script exist; the render script and triggers referenceswitch.master_bedroom_sitting_lamp. (No assertion about §11 — those belong to a different plug and are untouched.) - Unique automation
id/alias;make testgreen; Tier-1check_configin CI validates load. - Manual post-deploy: morning_armed→on (dark); evening occupancy on/off (20-min); movie off/on; away-sim toggling; Good Night → off (via renderer).
Docs¶
- CLAUDE.md — add a "Master Bedroom Sitting Lamp" automation entry + the entity rename note (plug_2 → sitting_lamp). Do not change the §11 Upstairs Hallway entry (different plug).
docs/automations.md— new section for the renderer + triggers + away-sim.docs/lighting.md— household-facing description.projects/smart_lighting_scenes.md— mark the away-simulation backlog item first implemented here.
Out of scope¶
- The §11 hallway schedule / §49 toggle /
group.lights(all belong toswitch.upstairs_hallway_1). - Dimming / smart-bulb / color; renaming the diagnostic sensors; relabeling the dashboard power card.
- Extending presence-sim to other lights.
Acceptance criteria¶
- [ ]
switch.upstairs_hallway_plug_2renamed toswitch.master_bedroom_sitting_lamp;homekit.yaml(whitelist + name) and the dashboard switch tile updated; allowlisted until snapshot. - [ ]
script.master_bedroom_sitting_lamp_renderimplements the priority stack (away→stop, waking&dark→on, sleeping→off, movie→off, occupied&dark&time-16:00–02:00→on, else off). - [ ] Trigger automation calls the renderer on all listed events; 20-min empty delay via
for:. - [ ] Wake-to-lamp fires on
input_boolean.morning_armed→on (dark), outranking sleeping. - [ ] Morning-off: when Good Morning fires (
morning_armed→off at kitchen motion), the lamp turns off and stays off with a partner still in bed — the Evening rule's 16:00–02:00 gate prevents a 5 AM re-light. - [ ] Movie mode: lamp off while bedroom TV/Apple TV playing, re-renders when it stops.
- [ ] Away presence-sim toggles when away+dark+<23:00; off at 23:00 away; hands back on return.
- [ ] §11 / §49 / group.lights untouched (different plug).
- [ ]
make testpasses; docs (CLAUDE.md, automations.md, lighting.md, smart_lighting_scenes.md) updated.