fix(zwave_js): bridge missing unified events for User Code CC reports#1327
Conversation
On released drivers, report-driven User Code CC changes update the value database without emitting unified credential events (zwave-js/zwave-js#8930, merged but unreleased). Subscribe to raw value-updated events on nodes that advertise User Code CC and route userCode/userIdStatus updates through _confirm_slot so external changes and post-write verification reports reach the coordinator. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015tvvgVhy5F12XVyv6RQBv7 Entire-Checkpoint: b1d8814d72ff
There was a problem hiding this comment.
Pull request overview
This PR restores push-based state convergence for Z-Wave locks where the driver currently dispatches changes via User Code CC reports but does not emit unified access_control credential events on those report-driven updates. Since LCM disables periodic polling for push providers, the change ensures the coordinator still receives updates (including the driver’s own post-write verification reports) until upstream zwave-js fixes ship in a minimum-supported driver.
Changes:
- Extend Z-Wave JS push subscriptions to optionally include a User Code CC “value updated” shim on nodes advertising User Code CC.
- Add a handler that projects
userCode/userIdStatusupdates intoSlotCredentialupdates (including masked/all-zero handling) and routes them through_confirm_slotto confirm pending optimistic writes. - Add comprehensive tests covering shim subscription gating and the key value-update behaviors (masked, empty, zeros+AVAILABLE, stale AVAILABLE guard, pending-write confirmation).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
custom_components/lock_code_manager/providers/zwave_js.py |
Adds conditional subscription + handler logic for User Code CC report-driven value updated events and routes them through _confirm_slot. |
tests/providers/zwave_js/test_events.py |
Adds shim-focused unit tests and updates expected subscription counts for User Code CC nodes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1327 +/- ##
==========================================
- Coverage 96.97% 96.96% -0.01%
==========================================
Files 53 53
Lines 6383 6429 +46
Branches 473 473
==========================================
+ Hits 6190 6234 +44
- Misses 193 195 +2
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Proposed change
On locks the driver dispatches to User Code CC (User Code CC-only locks, and the #1251 dual-CC population that driver 15.24.3 now correctly defers to User Code CC per spec CL:0083.01.21.00.4), any change that arrives as a report — keypad programming, zwave-js-ui edits, Home Assistant's
zwave_js.set/clear_lock_usercodeservices, and the driver's own post-write verification polls — updates the driver's value database viapersistUserCodebut emits no unified credential event. LCM disables periodic polling for push providers, so those changes never reach the coordinator and sync cannot reconcile them.The upstream fix is zwave-js/zwave-js#8930 (merged 2026-07-03, not yet in a driver release), which makes the access-control API the source of truth for User Code CC. Until the minimum supported driver includes it, this PR adds a User Code CC report shim:
setup_push_subscriptionadditionally registers a rawvalue updatedlistener filtered to theuserCode/userIdStatusproperties.userCodeupdates are projected with the asymmetric in-use logic from the removed fix(zwave_js): fall back to User Code CC utilities when the unified access-control API is unusable (#1251) #1252 fallback (masked → unreadable unlessin_useis explicitly False; all-zeros → empty only whenin_useis explicitly False) and routed through_confirm_slot, so the driver's post-write verification report doubles as the confirming push for a pending optimistic write (feat: verified-credential lifecycle — close the silent-failure window #1259 lifecycle) on non-S2 User Code CC locks.userIdStatus=AVAILABLEclears the slot, guarded by the stale-AVAILABLE check (ignored when LCM expects a PIN on the slot) that prevents infinite sync loops.Unlike the #1252 fallback removed in #1299, this restores no legacy write paths and no capability detection — writes stay on the unified
access_controlAPI, which works on 15.24.3. The shim also self-sunsets: #8930 makes these User Code CC values internal, so once a driver with it ships the value events stop arriving and the unified events take over with no LCM change. The shim block carries a removal recipe for the eventual cleanup PR.Type of change
Additional information
zwave_js.clear_lock_usercodeclear correctly normalizes the driver's value database but is invisible to LCM without this shim; the remaining cache-truth symptoms there are upstream), [ISSUE] 4.0.2 Code rejected Credential slot for pin_code must be between 1 and 0 #1251, feat: verified-credential lifecycle — close the silent-failure window #1259, refactor(zwave_js): remove the legacy User Code CC fallback #1299 (removed the legacy fallback; this bridges the narrower event gap until the driver release containing refactor: make AccessControl API the source of truth for User Code CC zwave-js/zwave-js#8930)Checklist
Full suite passes locally (1245 passed, 3 skipped);
prekclean.🤖 Generated with Claude Code
https://claude.ai/code/session_015tvvgVhy5F12XVyv6RQBv7