🐛 fix: skip QUANTITY/HOUR reconciliation buckets with untrusted units #63
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/reconcile-skip-unreliable"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
The hourly energy reconciliation in
_fetch_device_metricssnaps the live ∫W·dt total against the server'sQUANTITY/HOURbucket once per hour. It assumed the server value was in Wh. It is not, consistently: the Comwatt endpoint returns mixed units per device with no unit field anywhere in the API response or device metadata. A grid-injection child device returns kWh (serverval=0.9for an hour averaging ~900 W), so the reconciliation didlive_total += 0.9 - 900 ≈ -899and snapped ~900 Wh down every hour — a hundred-Wh jump onsensor.echange_reseau_injection_total_energy(and similarly on soutirage). This is the latentQUANTITY-unit bug the handoff describes, surfaced by the streaming reconciliation.Investigation (live data, documented in the reconciliation docstring):
hourkeying is correct — unchanged.deviceKind/threePhase/globaldo not predict the unit (solar isthreePhase=True& Wh; injection isthreePhase=True& kWh; batteries arethreePhase=False& anomalous). No static kind map works.live_by_hour.This is slice 1 of 2. Slice 1 stops the bleeding: buckets whose unit cannot be trusted are skipped (live total left untouched, high-water mark still advances). Slice 2 (stacked on this) will add kWh→Wh conversion so grid devices get a bounded drift correction too.
Impact
*_total_energysensor makes a hundred-Wh jump at the hourly snap anymore. The reconciliation either applies a bounded drift correction (Wh devices, ratio to live ≈ 1.0) or skips (kWh / no live reference / incoherent ratio). The live ∫W·dt path (Slice 4) is untouched and remains the real-time source of truth.live_total is None→state.total_wh += val, the pre-streaming path) is byte-for-byte unchanged — its latent unit bug is out of scope here.custom_components/comwatt/coordinator.pyandtests/test_coordinator.py.Considerations
last_bucket_ts, so a bogus night value (solar/injection returning non-zero when idle) or an anomalous virtual-device aggregation (EV one-off, battery) is never reconsidered. This is intended: re-evaluating would just re-skip, and holding the high-water mark back would also stall the stale-live_by_hourprune._RECONCILE_MIN_LIVE_WH = 10.0(below this, no reliable reference), Wh bandratio ∈ [0.5, 2.0](drift tolerance). Tunable constants, kept narrow to stay conservative.Tests
test_reconcile_prunes_stale_live_by_hour) to give the reconciled hour a live reference, preserving its prune intent.77/77 passing,ruffclean,mypyclean.WIP: 🐛 fix: skip QUANTITY/HOUR reconciliation buckets with untrusted unitsto 🐛 fix: skip QUANTITY/HOUR reconciliation buckets with untrusted units