fix: stop re-fetching masked usercodes every poll cycle#590
fix: stop re-fetching masked usercodes every poll cycle#590tykeal merged 1 commit intoFutureTense:mainfrom
Conversation
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #590 +/- ##
==========================================
+ Coverage 84.14% 89.09% +4.95%
==========================================
Files 10 27 +17
Lines 801 3210 +2409
==========================================
+ Hits 674 2860 +2186
- Misses 127 350 +223 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Fixes an infinite masked-usercode refresh loop for Schlage BE469 locks by adjusting _sync_usercode() refresh handling and adding targeted tests to cover masked refresh outcomes (issue #589).
Changes:
- Add post-refresh masking detection and local-PIN fallback logic in
_sync_usercode()to avoid repeated refresh attempts for persistently masked locks. - Add a new test suite covering refresh outcomes when the provider returns masked/None/real codes.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
custom_components/keymaster/coordinator.py |
Updates _sync_usercode() refresh logic to handle persistently masked usercodes and optionally fall back to a local PIN. |
tests/test_coordinator.py |
Adds a new test class covering masked refresh behaviors and fallback scenarios. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
628c310 to
56146f9
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
56146f9 to
eef50f0
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
eef50f0 to
fa676f1
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
fa676f1 to
792f995
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Schlage BE469 locks return masked usercodes (e.g. '**********') with in_use=True on every poll. The refresh logic detected this as needing a re-fetch but the lock always returns the same masked value, creating an infinite polling loop that drains battery via repeated Z-Wave UserCodeCCGet commands every 60 seconds. After async_refresh_usercode(), check if the result is still masked. If so, fall back to the locally stored PIN rather than accepting the masked value that will trigger another refresh next cycle. Closes FutureTense#589 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Andrew Grimberg <tykeal@bardicgrove.org>
792f995 to
a421775
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
firstof9
left a comment
There was a problem hiding this comment.
Logic behind this seems sound, looks good.
Summary
Schlage BE469 locks return masked usercodes (e.g.
**********) within_use=Trueon every poll. The refresh logic detected this as needing a re-fetch, but the lock always returns the same masked value — creating an infinite polling loop that sends Z-WaveUserCodeCCGetcommands every 60 seconds, draining the lock battery.Root Cause
In
_sync_usercode(), whenin_use=Trueand the code appears masked,async_refresh_usercode()is called. But if the lock always masks its responses, the refresh returns the same masked value, and the next poll cycle triggers the same refresh again.Fix
_is_masked_code()helper that specifically checks for known mask patterns (all*, all0, orNone) — avoids false positives on valid PINs like1111masked_code_slotsonKeymasterLock(transient, not persisted) so a masked slot is only refreshed once, then skipped on subsequent pollsin_use=False, let downstream empty-slot handling run instead of forcing local PIN fallbackinit=Falsefields from persistence in both_dict_to_kmlocksand_kmlocks_to_dictTests
10 new tests in
TestSyncUsercodeRefreshMaskedcovering:1111not mistaken for masked codein_use=False)Closes #589