You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(homebridge): propagate terminal stream faults to Presence and cached Wall Connector sensors (#118)
Closes the two P2 gaps deferred from PR #116: PresenceService's
OccupancySensor services now honestly fault via setStreamFault (HAP
declares StatusFault optional on OccupancySensor, so this is not a
misleading signal), and WallConnectorService now hydrates its per-DIN
connectors map from Homebridge's persisted accessory cache at
construction so already-restored sensors are fault-checked immediately,
including a fault already raised before the accessory was constructed.
Close two gaps left by the terminal stream health fault propagation: PresenceService's occupancy sensors now fault on a terminal stream failure and clear again once their signal reports a fresh value, and WallConnectorService's per-DIN sensors restored from Homebridge's accessory cache (before any `live_status` has arrived this run) are now hydrated and fault-checked immediately instead of being invisible to `setStreamFault()` until their first reading.
Copy file name to clipboardExpand all lines: AGENTS.md
+3-1Lines changed: 3 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -150,7 +150,9 @@ pnpm link --global n8n-nodes-teslemetry
150
150
151
151
**Gotcha**: not every feature can be gated ahead of time (model/config are known synchronously; whether a given vehicle *reports* a signal at all often isn't). `PresenceService` (`vehicle-services/presence.ts`) and `WallConnectorService` (`energy-services/wall-connector.ts`) don't extend `BaseService`/`BaseEnergyService` and create zero HAP services at construction time - each sub-sensor (per presence field, per Wall Connector DIN) is created lazily the first time its signal/live_status entry actually arrives, since a field withheld by scope or simply absent hardware may never fire. Contrast this with `TpmsService`, `GridOutageService`, and `StormWatchActiveService`, which construct their `ContactSensor`s eagerly (virtually every vehicle/site has the underlying hardware) but hold `StatusFault` at `GENERAL_FAULT` until the first real payload lands, clearing it only then - never default a not-yet-received reading to "safe" by leaving a fresh `ContactSensorState` at its HAP default. Both new and existing contact-sensor mappings in this package (`DoorService`, the TPMS/grid/storm/wall-connector services above) follow one polarity convention: `CONTACT_DETECTED` = normal/quiescent (door closed, no fault, cable seated, grid up), `CONTACT_NOT_DETECTED` = triggered/abnormal (door open, fault active, cable unseated, grid down) - keep new contact sensors on this convention rather than picking polarity per-service.
152
152
153
-
**Gotcha**: `BaseService`/`BaseEnergyService.setStreamFault()` (called from `VehicleAccessory`/`EnergyAccessory`/`TeslemetryPlatform` to reflect terminal account-stream health) only marks a service's `StatusFault` when that HomeKit service type actually declares it as an optional characteristic (checked via `service.optionalCharacteristics`, not `service.testCharacteristic()` - the latter only reports characteristics already added, which excludes `StatusFault` on a service like `DoorService` that never touches it during normal operation). Only sensor-type services (`ContactSensor` and similar) declare `StatusFault` at all; core control services (`LockMechanism`, `Switch`, `Thermostat`, `Battery`) don't, and forcing it onto them via `getCharacteristic()` would silently add an out-of-spec characteristic with a HAP warning - `setStreamFault()` is a no-op for those rather than inventing a misleading fault signal. Services owning more than one HAP `Service` instance (`TpmsService`, `DoorService`) override `setStreamFault()` to loop over all of them, not just the primary `this.service`.
153
+
**Gotcha**: `BaseService`/`BaseEnergyService.setStreamFault()` (called from `VehicleAccessory`/`EnergyAccessory`/`TeslemetryPlatform` to reflect terminal account-stream health) only marks a service's `StatusFault` when that HomeKit service type actually declares it as an optional characteristic (checked via `service.optionalCharacteristics`, not `service.testCharacteristic()` - the latter only reports characteristics already added, which excludes `StatusFault` on a service like `DoorService` that never touches it during normal operation). Only sensor-type services (`ContactSensor`, `OccupancySensor`, and similar) declare `StatusFault` at all; core control services (`LockMechanism`, `Switch`, `Thermostat`, `Battery`) don't, and forcing it onto them via `getCharacteristic()` would silently add an out-of-spec characteristic with a HAP warning - `setStreamFault()` is a no-op for those rather than inventing a misleading fault signal. Services owning more than one HAP `Service` instance (`TpmsService`, `DoorService`) override `setStreamFault()` to loop over all of them, not just the primary `this.service`. `PresenceService`/`WallConnectorService` don't extend `BaseService`/`BaseEnergyService` (see above) but hand-implement the same `setStreamFault()` contract over their own lazily-created sensor maps, clearing a sensor's fault the moment its own signal/DIN reading arrives - independent of any debounce applied to the reading's *value*.
154
+
155
+
**Gotcha**: `WallConnectorService`'s `connectors` map is otherwise only populated by `live_status`, so per-DIN sensors that already exist in Homebridge's persisted accessory cache from a prior run are invisible to `setStreamFault()` until this run's first `live_status` - its constructor hydrates `connectors` from any matching cached `ContactSensor` services up front (parsed off their `wall-connector-{fault,connected}-<din>` subtype) and immediately applies `TeslemetryPlatform.streamFault` (a public getter over the platform's private terminal-fault flag), so a fault already raised before this accessory was constructed still reaches them. Any other lazily-hydrated per-entity service map should follow the same hydrate-from-cache-at-construction pattern rather than assuming the live stream is the only source of a map's keys.
0 commit comments