mirror of
https://github.com/kuhyx/wake-alarm.git
synced 2026-11-10 19:27:02 +01:00
_curtains.py: a two-method driver protocol, a registry, and a logging no-op default. prepare_hardware() calls open_curtains() next to turn_on_plug(). The no-op is not a placeholder awaiting hardware -- it is the correct behaviour on a machine with no motor. Shipping it now means the call site and the JSONL event are real, so buying a motor later is a config file rather than a code change. Shaped like _smart_plug.py, which solves the same problem: absent or malformed config means "no curtains" rather than an error, an unknown driver name degrades with a WARNING, and a driver that throws is caught -- a jammed motor must never be the reason nobody is woken. The call sits on the startup path, ahead of the first beep, so an exception escaping it would take the alarm down entirely. Why bother at all with no hardware: the audio failsafe silences the alarm at FAILSAFE_SILENCE_SECONDS, and daylight is the one wake cue that outlives it -- and the only one independent of a sink, a speaker or an HDMI handshake, which is the exact chain that made this alarm silent in the first place. DOCS-curtains-hardware.md has the buy list, the three rules a new driver must follow, and what is deliberately excluded (no cloud, no scheduling of its own, no close-at-night -- closing belongs to the night lockdown, item 13). CURTAINS_CONFIG_FILE and CURTAINS_DEFAULT_DRIVER live in _curtains.py rather than _constants.py, since this is their only consumer -- the same call _rounds.py and _alarm_session.py already make. That also keeps _constants.py under the 250-line cap without dragging _sync.py's pre-existing overage into this commit; splitting _sync.py belongs to the phase that legitimately touches it (item 8). 465 tests pass, 100% branch coverage. vmbox harness 8/8, exit 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EckWmyfetYq3Mi8MAnUudh |
||
|---|---|---|
| .. | ||
| tests | ||
| __init__.py | ||
| _alarm_display.py | ||
| _alarm_flash.py | ||
| _alarm_payload.py | ||
| _alarm_session.py | ||
| _alarm_state.py | ||
| _alarm_timers.py | ||
| _alarm_view.py | ||
| _alarm.py | ||
| _audio.py | ||
| _beep_loop.py | ||
| _brightness.py | ||
| _challenges.py | ||
| _constants.py | ||
| _correlation.py | ||
| _countdown.py | ||
| _curtains.py | ||
| _dismiss_view.py | ||
| _escalation.py | ||
| _escape_flow.py | ||
| _gating.py | ||
| _inhibit.py | ||
| _lock_setup.py | ||
| _log_dedupe.py | ||
| _log_sink.py | ||
| _logging_setup.py | ||
| _reactivate.py | ||
| _rounds.py | ||
| _screen_flash.py | ||
| _sinks.py | ||
| _smart_plug.py | ||
| _startup.py | ||
| _state.py | ||
| _sync.py | ||
| _tone.py | ||
| _trigger.py | ||