Coordinator polls the API snapshot and rebuilds the sensors' data
Feature 18: the shared coordinator's refresh pass now fetches GET /api/v1/panel/snapshot through the NestQuestApiClient and reconstructs the exact core dataclasses (NestQuestSnapshot, ChildDaySnapshot, QuestInstanceView) the Feature 10 entities read, so sensor.py and binary_sensor.py are untouched and every entity_id and attribute payload keeps its shape. Why: the integration becomes an API client of the NestQuest service instead of a second reader of the SQLite file, and the panel cards and the four blueprints keep working without changes. - snapshot_from_api_payload maps the route's JSON back onto the dataclasses field by field (state 'completed' -> 'done' so instance_payload renders 'completed' again; counts, presence, next_present, overdue, on_time, completed_at pass through verbatim; due_date is stamped from today_iso, the only date the route serves). - The panel payload omits missed instances (D-009), so admin_instances can no longer carry missed rows — the admin surface for missed quests is the PWA reading the API directly. Documented in the module docstring and pinned by tests. - An unconfigured panel token (the shipped default) gets a typed-error stub instead of a construction crash: setup succeeds, the first refresh fails cleanly, entities come up unavailable and HA's retry cycle applies. Fetch failures log the typed error and mark the entities unavailable while data keeps its last good snapshot. - The runtime record registers before the first refresh so the refresh path always finds the live entry state; the update interval and the serialized forced-refresh behaviour are unchanged. - Tests: a fixture snapshot drives the coordinator (stub client, no network) asserting per-child values, household rollups, cycle day, and the exact instance payload shape, plus unconfigured and failed-fetch cases; DB-seeded tests ride a lazy local-snapshot client through the same JSON path.
This commit is contained in:
+18
-16
@@ -221,19 +221,23 @@ async def test_due_today_attributes_carry_the_panel_payload(
|
||||
assert bo_instance["on_time"] is None
|
||||
|
||||
|
||||
async def test_due_today_payload_omits_missed_for_panel_includes_for_admin(
|
||||
async def test_due_today_payload_omits_missed_admin_equals_panel(
|
||||
hass, make_entry, monkeypatch
|
||||
) -> None:
|
||||
"""D-009: the panel payload omits missed instances, the admin one keeps them.
|
||||
"""D-009: the panel payload omits missed instances.
|
||||
|
||||
A missed instance is derived (``due_date`` before the snapshot's
|
||||
"today"), never stored. The coordinator's day listing is keyed on
|
||||
``_local_now``'s date, so pinning the clock forward would move the
|
||||
listing window off today's rows entirely; the pinned FUTURE clock
|
||||
is therefore applied at the ``derive_state`` boundary instead —
|
||||
today's open instances then read as missed through the same
|
||||
derivation rule, without back-dating instance rows past the DAO's
|
||||
no-past guard or touching append-only completion events.
|
||||
Since Feature 18 the snapshot comes from the API panel route,
|
||||
which omits missed rows entirely (the admin surface for missed
|
||||
quests is the PWA, reading the API directly). The entity payload
|
||||
therefore cannot carry missed rows any more: ``admin_instances``
|
||||
equals ``instances`` — open and completed rows only. A missed
|
||||
instance is still derived locally (``due_date`` before the
|
||||
snapshot's "today"); the pinned-FUTURE clock at the
|
||||
``derive_state`` boundary makes today's open instances read
|
||||
missed through the same derivation rule, and this test pins the
|
||||
change: neither payload carries them, and the count rollups
|
||||
(precomputed server-side from the full day) are unaffected here
|
||||
because the API counts arrive per the route's own build.
|
||||
"""
|
||||
entry, coordinator, (ada, bo, cory) = await _setup_seeded_entry(
|
||||
hass, make_entry
|
||||
@@ -256,12 +260,10 @@ async def test_due_today_payload_omits_missed_for_panel_includes_for_admin(
|
||||
assert attributes["instances"] == [], (
|
||||
"missed instances are omitted from the panel payload"
|
||||
)
|
||||
[missed] = attributes["admin_instances"]
|
||||
assert missed["state"] == "missed"
|
||||
assert missed["completed_at"] is None
|
||||
# Counts still roll the missed instance up as not-completed.
|
||||
assert _sensor(hass, bo.id, "quests_completed_today").native_value == 0
|
||||
assert _sensor(hass, bo.id, "quests_remaining_today").native_value == 1
|
||||
assert attributes["admin_instances"] == [], (
|
||||
"the API payload omits missed rows, so the admin payload "
|
||||
"carries none either (the PWA is the admin surface now)"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("kind", SENSOR_KINDS)
|
||||
|
||||
Reference in New Issue
Block a user