shrink root README into a landing page with a docs map and focused contributor guidance add TV_POWER_RUNBOOK as the canonical TV power rollout and canary runbook add CHANGELOG and move project history out of README-style docs refactor src README into a developer-focused guide (architecture, runtime files, MQTT, debugging) prune redundant older HDMI docs and keep a canonical HDMI_CEC_SETUP path update copilot instructions to a high-signal policy format with strict anti-shadow-README design rules align references across docs to current files, scripts, and TV power behavior
96 lines
3.1 KiB
Markdown
96 lines
3.1 KiB
Markdown
# Client Handoff: TV Power Coordination
|
|
|
|
## Purpose
|
|
Implement robust client-side TV power control that applies server MQTT intents when valid and falls back to local event timing when server/broker data is missing or stale.
|
|
|
|
## Source of Truth
|
|
- Shared full plan: TV_POWER_COORDINATION_TASKLIST.md
|
|
|
|
## Scope (Client Team)
|
|
- Intent subscription/validation
|
|
- CEC state transitions and timer cancellation safety
|
|
- Hybrid fallback using local event windows
|
|
- Power state acknowledgment publishing
|
|
|
|
## MQTT Contract (Client Responsibilities)
|
|
|
|
### Subscribe
|
|
- infoscreen/{client_id}/power/intent
|
|
- Optional: infoscreen/groups/{group_id}/power/intent
|
|
|
|
### Publish state
|
|
- infoscreen/{client_id}/power/state
|
|
|
|
### State Payload (v1)
|
|
```json
|
|
{
|
|
"schema_version": "1.0",
|
|
"intent_id": "last-applied-intent-id",
|
|
"client_id": "...",
|
|
"reported_at": "2026-03-31T12:00:01Z",
|
|
"power": {
|
|
"applied_state": "on",
|
|
"source": "mqtt_intent|local_fallback",
|
|
"result": "ok|skipped|error",
|
|
"detail": "free text"
|
|
}
|
|
}
|
|
```
|
|
|
|
## Required Runtime Rules
|
|
|
|
### Intent Validation and Ordering
|
|
- Accept only schema_version=1.0 (or explicitly version-gated supported set).
|
|
- Ignore malformed payloads.
|
|
- Ignore expired intents (expires_at in past).
|
|
- Apply only newest valid intent by issued_at, intent_id tie-break.
|
|
- Deduplicate already-applied intent_id.
|
|
|
|
### Power Action Safety
|
|
- desired_state=on:
|
|
- cancel pending delayed-off timer immediately
|
|
- turn on via CEC only if needed
|
|
- desired_state=off:
|
|
- schedule delayed off (grace_seconds or local default)
|
|
- re-check active event before executing actual off
|
|
|
|
### Fallback (Critical)
|
|
- If MQTT unavailable, intent missing, invalid, or stale:
|
|
- use existing local event start/end logic
|
|
- use event end as off trigger plus delayed-off safety
|
|
- Any active event must cancel pending off timers.
|
|
|
|
## Configuration
|
|
- Add POWER_CONTROL_MODE with values:
|
|
- local
|
|
- mqtt
|
|
- hybrid (recommended default)
|
|
|
|
### Hybrid Mode
|
|
- Prefer valid MQTT intent.
|
|
- Automatically fall back to local schedule logic when intent channel is not trustworthy.
|
|
|
|
## Implementation Tasks
|
|
1. Add intent topic handlers and schema validation.
|
|
2. Integrate intent application into display power control path.
|
|
3. Add timer race hardening for adjacent event transitions.
|
|
4. Add fallback decision branch for stale/missing intents.
|
|
5. Add power state publisher with intent_id/source/result.
|
|
6. Add logs for timer arm/cancel/fire with reason and event_id.
|
|
7. Add tests for adjacent events, broker outage, reconnect, duplicate intent.
|
|
|
|
## Acceptance Criteria
|
|
1. No unintended TV off between adjacent events.
|
|
2. Broker outage during active event does not power off TV prematurely.
|
|
3. Reconnect with retained intent reconciles state without oscillation.
|
|
4. Duplicate/old intents do not trigger repeated CEC toggles.
|
|
5. State messages clearly show mqtt_intent vs local_fallback source.
|
|
|
|
## Target Integration Points
|
|
- Main runtime orchestration: src/display_manager.py
|
|
- MQTT plumbing and topic handlers: src/simclient.py
|
|
|
|
## Operational Notes
|
|
- Keep fallback logic enabled even after MQTT rollout.
|
|
- Ensure all new timestamps are UTC ISO format.
|