Task b1ed9c45: SSE subscription re-fires the four HA bus events #168

Member

Summary

The integration now subscribes to the API service's panel event stream, so transitions that happen through the panel plane (e.g. a PWA tap) reach Home Assistant's event bus — until now the four blueprints only fired for completions made through the integration's own services.

Changes

  • api_client.py — NestQuestApiClient.stream_events(): async generator over GET /api/v1/panel/events (Bearer header, shared base URL/token/session). Parses SSE frames (event:/data: lines, blank-line frame ends, chunk-split line buffering, multi-line data joins) and yields (event_type, payload). Opens with the same one-timeout, typed-error contract as every other call; NestQuestApiError on non-2xx, connection failure, mid-stream drop, or malformed frame; cancellation stops cleanly and the response closes on every path.
  • sse.py (new) — NestQuestEventStream: consumes stream_events() in one background task, firing each documented event type (nestquest_quest_completed, nestquest_quest_uncompleted, nestquest_quest_missed, nestquest_child_day_complete) with its documented payload on hass.bus.async_fire. Reconnects forever with a bounded exponential backoff (5 s, doubling, capped at 60 s; a received frame resets it), logs every failure with its reason, and never lets an exception escape the task. start() / stop() (stop cancels and awaits, so no frame fires after unload).
  • __init__.py — setup builds one shared API client for the coordinator and the subscription, starts the stream alongside the runtime record (records gain event_stream), stops it first in both the setup-failure unwind and unload; a client without a stream surface (unconfigured-token stub) starts no subscription.
  • tests/test_sse_subscription.py (new, 13 tests) — stub-driven, no network: client frame parsing/wire format/typed failures/cancellation; manager firing of the four documented events with their documented payload fields, stop() teardown (task cancelled, no firing after stop), and bounded-backoff reconnect (asserted delay sequence with cap and reset) without crashing; full setup/unload wiring starts and tears the task down.

Task

  • Task: b1ed9c45-e317-4ace-9b27-00cf1add739b — "SSE subscription re-fires the four HA bus events"
  • Done-condition met: subscribing to the panel SSE stream re-fires nestquest_quest_completed, nestquest_quest_uncompleted, nestquest_quest_missed and nestquest_child_day_complete on the HA bus with the documented payloads, with bounded-backoff reconnection, clean unload, and no task leak.

Tests

  • TZ=UTC uv run pytest -q → 1810 passed
  • TZ=UTC uv run pytest -q tests/test_sse_subscription.py → 13 passed
## Summary The integration now subscribes to the API service's panel event stream, so transitions that happen through the panel plane (e.g. a PWA tap) reach Home Assistant's event bus — until now the four blueprints only fired for completions made through the integration's own services. ## Changes - **`api_client.py`** — `NestQuestApiClient.stream_events()`: async generator over `GET /api/v1/panel/events` (Bearer header, shared base URL/token/session). Parses SSE frames (`event:`/`data:` lines, blank-line frame ends, chunk-split line buffering, multi-line data joins) and yields `(event_type, payload)`. Opens with the same one-timeout, typed-error contract as every other call; `NestQuestApiError` on non-2xx, connection failure, mid-stream drop, or malformed frame; cancellation stops cleanly and the response closes on every path. - **`sse.py`** (new) — `NestQuestEventStream`: consumes `stream_events()` in one background task, firing each documented event type (`nestquest_quest_completed`, `nestquest_quest_uncompleted`, `nestquest_quest_missed`, `nestquest_child_day_complete`) with its documented payload on `hass.bus.async_fire`. Reconnects forever with a bounded exponential backoff (5 s, doubling, capped at 60 s; a received frame resets it), logs every failure with its reason, and never lets an exception escape the task. `start()` / `stop()` (stop cancels and awaits, so no frame fires after unload). - **`__init__.py`** — setup builds one shared API client for the coordinator and the subscription, starts the stream alongside the runtime record (records gain `event_stream`), stops it first in both the setup-failure unwind and unload; a client without a stream surface (unconfigured-token stub) starts no subscription. - **`tests/test_sse_subscription.py`** (new, 13 tests) — stub-driven, no network: client frame parsing/wire format/typed failures/cancellation; manager firing of the four documented events with their documented payload fields, `stop()` teardown (task cancelled, no firing after stop), and bounded-backoff reconnect (asserted delay sequence with cap and reset) without crashing; full setup/unload wiring starts and tears the task down. ## Task - Task: `b1ed9c45-e317-4ace-9b27-00cf1add739b` — "SSE subscription re-fires the four HA bus events" - Done-condition met: subscribing to the panel SSE stream re-fires `nestquest_quest_completed`, `nestquest_quest_uncompleted`, `nestquest_quest_missed` and `nestquest_child_day_complete` on the HA bus with the documented payloads, with bounded-backoff reconnection, clean unload, and no task leak. ## Tests - `TZ=UTC uv run pytest -q` → **1810 passed** - `TZ=UTC uv run pytest -q tests/test_sse_subscription.py` → **13 passed**
dev_agent added 1 commit 2026-09-23 06:57:17 -04:00
WHY: transitions that happen through the API service's panel route
(e.g. a tap on the PWA) published on the API's SSE stream but never
reached Home Assistant's event bus, so the four blueprints only fired
for completions made through the integration's own services. The
integration now subscribes: NestQuestApiClient.stream_events parses
the GET /api/v1/panel/events frames (typed NestQuestApiError on
non-2xx/transport failure, clean stop on cancellation), a new
NestQuestEventStream consumes it in a background task — firing each
documented event type with its documented payload on hass.bus,
reconnecting forever with a 5s-to-60s bounded backoff, never letting
an exception escape — and setup starts it / unload stops it, so no
task leaks.
review_agent left a comment
Member

Independent Claude Sonnet 5 review completed for this exact commit.

Independent Claude Sonnet 5 review completed for this exact commit.
dev_agent merged commit 84d179336b into feature/430f7f98-7650-43e9-aa98-4b340303602a-ha-integration-as-api-client 2026-09-23 07:04:40 -04:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Maniacs_Mansion/NestQuest#168