TEL-05: read the meter, not Home Assistant's opinion of the meter
A fourth meter_source, `homewizard_local`, polling a HomeWizard P1's own local API (GET /api/v1/data) instead of watching an HA entity. The point is the age sensor. sensor.p1_sample_age_s is FW-01's watchdog input, and on every transport we had it measured "time since the value CHANGED", not "time since the meter REPORTED". Home Assistant offers nothing better: a repeated reading emits no state_changed, advances last_reported on neither serialiser, and state_reported cannot be subscribed to at all. Measured twice - 70 s of a frozen meter on the ENV-01 rig, and ten repeated readings against the live house. Our own capture of this house's meter goes 42.2 s and 97.0 s between changes, both past the default meter_max_age_s of 30, so the age sensor would have commanded 0 W on a perfectly healthy meter. Here every HTTP response is an arrival. The meter answered, now, with its current reading; whether the number moved is not consulted. Five identical readings are five arrivals. Reuses TEL-01's pipeline rather than restructuring it: same split_signed sign convention as ha_signed, same make_sample, same ingest stamping, meter_max_age_s, clock-recomputed age, plausibility bounds and the §20 unsigned-decode rejection. A failed or timed-out poll submits nothing, so it is a missing reading - never 0 W - and does not reset the age. meter_poll_s (default 5 s, the meter's own rate) is checked against meter_max_age_s once at startup, like the ha_signed entity ids. ⚠️ An arrival stamp cannot see a FROZEN meter, and no arrival detector can - one answering 200 OK with a stale number is arriving. The local API does expose what HA never had (the total_power_*_kwh registers stop advancing) and the transport tracks it as `unchanged_s`, but it is deliberately not folded into the age and not thresholded: this controller regulates grid toward ~0 W, and at a converged -10 W the export register needs six minutes to move by its 1 Wh resolution while the power figure legitimately repeats. Thresholding that would rebuild the false-trip limit cycle at the exact operating point we aim for. test_p1.py 179 -> 236 checks. Still defaults to off. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Du77usMj8XNKNFZGmUiWDa
This commit is contained in:
co-authored by
Claude Opus 5
parent
ad9c5772a4
commit
98109a9b91
@@ -2,6 +2,44 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
**TEL-05.** A fourth `meter_source`, `homewizard_local`, which polls a
|
||||
HomeWizard P1's **own local API** (`GET /api/v1/data`) instead of watching a
|
||||
Home Assistant entity. Set `p1_host` to the meter's address; `meter_poll_s`
|
||||
(default 5 s, the meter's own update rate) sets the cadence.
|
||||
|
||||
✅ **This is the first transport whose `sensor.p1_sample_age_s` measures when
|
||||
the meter *reported*, and therefore the first one a firmware watchdog may
|
||||
threshold.** Every HTTP response is an arrival: the meter answered, now, with
|
||||
its current reading, and whether the *number* moved is not consulted. Home
|
||||
Assistant cannot express that at all — a repeated reading emits no
|
||||
`state_changed`, advances `last_reported` on neither serialiser, and
|
||||
`state_reported` is not subscribable ("Event filter is required"). On
|
||||
`ha_signed` that made a healthy meter under a flat load indistinguishable from
|
||||
a dead one, and our own capture of this house's meter goes 42.2 s and 97.0 s
|
||||
between changes — both past the default `meter_max_age_s` of 30, i.e. a false
|
||||
trip to 0 W on a meter that is fine. If you have a HomeWizard P1, move to this
|
||||
mode.
|
||||
|
||||
Everything TEL-01 established is reused, not re-implemented: ingest
|
||||
timestamping, `meter_max_age_s`, the clock-recomputed age, the plausibility
|
||||
bounds and the §20 unsigned-decode rejection, and the same `split_signed` sign
|
||||
convention `ha_signed` uses. A failed or timed-out poll submits nothing, so it
|
||||
is a *missing* reading — never 0 W — and it does not reset the age.
|
||||
|
||||
Verified on the ENV-01 rig against `sim/hwsim.py`, steady and with `--fault
|
||||
freeze` injected. Still defaults to `off`.
|
||||
|
||||
⚠️ **An arrival stamp still cannot see a *frozen* meter**, and no arrival
|
||||
detector can: a meter answering `200 OK` forever with a stale number is
|
||||
arriving. The local API does expose what the HA path never had — the
|
||||
`total_power_*_kwh` registers stop advancing — and the transport tracks it as
|
||||
`unchanged_s`, but that is deliberately **not** folded into the age and not
|
||||
thresholded: this controller regulates grid power toward ~0 W, and at a
|
||||
converged −10 W the export register needs six minutes to move by its 1 Wh
|
||||
resolution while the power figure legitimately repeats. Thresholding it at 30 s
|
||||
would rebuild the false-trip limit cycle at the exact operating point we aim
|
||||
for. Freeze detection needs the low-power case solved first, separately.
|
||||
|
||||
**TEL-04.** A third `meter_source`, `ha_signed`, reading **one signed** Home
|
||||
Assistant entity: positive = import, negative = export. That is the shape a
|
||||
HomeWizard P1 publishes (`sensor.p1_meter_active_power`), and it is the meter
|
||||
|
||||
Reference in New Issue
Block a user