Context for developing and debugging Hubitat Elevation apps, drivers, and hub environment — sandbox constraints, lifecycle idioms, capability contracts, plus grounded deploy/log-tail/lint mechanisms.
74
93%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Captured live on 2026-07-15 against the "Apps" hub (C-8 Pro, zwaveJS backend, Z-Wave LR) by
tailing ws://<ip>/zwaveLogsocket (skills/_scripts/hub_radiolog.py) through a real inclusion and a real
graceful exclusion of a Zooz LR leak sensor. These are the signatures the mesh-health skill uses
to confirm a lifecycle event happened — the tooling observes and confirms, it does not trigger
(inclusion/exclusion is hub-UI + physical, with no endpoint to trigger it; force-remove of a FAILED
orphan and a full network rebuild are groundable — skills/_reference/endpoints.md).
LR devices join via SmartStart, verified against Silicon Labs: the device DSK/QR is added to
the hub's provisioning list ahead of time, and the device auto-includes on power-up — no
inclusion mode, no button press. Confirmed on the wire (new node 374, id ≥ 256 = LR):
Security2CCMessageEncapsulation, security class: S2_Authenticated (LR is S2-mandatory).WakeUpCCIntervalReport (a sleepy leak
sensor reported 43200 s / 12 h), VersionCCReport, ManufacturerSpecificCCReport
(manufacturer 0x027a = Zooz), BatteryCCReport, AssociationCCSet (lifeline group 1 → node 1).failed to decode... retrying with SPAN extension → Security2CCNonceReport SOS: true → the hub sends a fresh SPAN sender-EI.[DRIVER] line (RSSI: -NN dBm).Confirm inclusion: the snapshot node count rises and a new id (≥ 256 for LR) appears; the node's
nodeState settles to OK with security: S2_Authenticated.
Even an LR node excludes via the classic RemoveNodeFromNetwork API (verified — the node id
appears in the callback bytes). Signature, in order:
[DRIVER] hub: « [REQ] [RemoveNodeFromNetwork] # hub entered exclusion mode
[SERIAL] 0x...4b1a03 0176 07... status 0x03 (node found), node 0x176 = 374
[SERIAL] 0x...4b1a06 0176 07... status 0x06 (remove DONE), node 0x176
[CNTRLR] hub: the exclusion process was stopped
[CNTRLR] hub: Node 374 was removed # THE event lineThen zwaveJS purges the node's value DB ([-] <CC> ... (was ...) teardown lines) — that is the
aftermath, not the exclusion. Read the Node <n> was removed line, not the teardown.
Confirm exclusion: Node <n> was removed on the wire and the node id drops out of the snapshot.
Graceful removal of a SmartStart device is two steps: remove it from the provisioning list (else it re-includes on next power-up), and exclude/factory-reset the physical device.
RemoveFailedNode is the force-remove for a node the controller has marked FAILED; it applies only
to an orphan ghost (FAILED with no bound deviceId), never a recoverable real device. Its exact
wire signature was not captured this session (we declined to remove real devices), so it is not
asserted here — capture it before documenting the frames.
Every hub→device Z-Wave command emits a [DRIVER] hub: TransmitReport line the JSON snapshot never
shows. hub_radiolog.py parses it into a transmit sub-dict (and --summary medians it). Real
line and fields:
callback id: 244 transmit status: OK, took 40 ms routing attempts: 2 ... TX power: 14 dBm
ACK RSSI: -91 dBm measured noise floor: -92 dBm ← at the HUB
measured RSSI of ACK from destination: -85 dBm measured noise floor by destination: -96 dBm ← at the DEVICEstatus (OK / NoAck — the definitive send result), took_ms (real latency), routing_attempts (retransmits), tx_power (max US LR is 14 dBm).hub_noise_floor + hub_ack_rssi → hub_snr (device→hub headroom, measured at the controller).dest_noise_floor + dest_rssi → dest_snr (hub→device headroom, measured at the device).hub_snr well below dest_snr means the hub's own receiver is the bottleneck (its RF environment — co-located radios, USB3, a gear cluster), not the device and not distance. The opposite asymmetry points at the device end. This is the one measurement that localizes a flapping/high-latency link; the snapshot's single lwrRssi cannot.+78) are dropped — a received RSSI on these logs is always negative dBm.hub_snr ~1–8 dB while dest_snr ~11–15; 8 LR devices flapped OK↔FAILED with a 100 ms latency tail. Moving the hub to a quiet room dropped the noise floor to median −97 (spikes gone, worst −94), eliminated the retransmits and the latency tail (max took_ms 100 → 10 ms), and recovered all 8 — even though the devices' own signal got weaker. The noise floor, not the signal, was the fault.A nodeState: FAILED node with a bound deviceId is a real device currently unreachable (may
be transient — recover it, do not delete). Only a FAILED node with no deviceId is an orphan
ghost. Verified live: 8 nodes went FAILED during a session of heavy LR-channel activity, all with
deviceIds — real devices knocked offline, not ghosts. hub_mesh.py tags each failure_kind.