From 671c82681d5087cabddddeb7053e80d61a007e29 Mon Sep 17 00:00:00 2001 From: justdaniel-gh <68163487+justdaniel-gh@users.noreply.github.com> Date: Sun, 1 Feb 2026 17:43:07 -0600 Subject: [PATCH] Fix clearing codes on Schlage locks that have user codes of lengths other than 4. Fixes #561 --- .../keymaster/providers/zwave_js.py | 7 ++-- tests/providers/test_zwave_js.py | 36 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/custom_components/keymaster/providers/zwave_js.py b/custom_components/keymaster/providers/zwave_js.py index c8b71394..b2be8cf6 100644 --- a/custom_components/keymaster/providers/zwave_js.py +++ b/custom_components/keymaster/providers/zwave_js.py @@ -554,8 +554,11 @@ async def async_clear_usercode(self, slot_num: int) -> bool: # Verify the code was cleared try: usercode = get_usercode(self._node, slot_num) - # Treat both "" and "0000" as cleared (Schlage BE469 firmware bug workaround) - if usercode[ZWAVEJS_ATTR_USERCODE] not in ("", "0000"): + # Treat both "" and full string of "0" as cleared (Schlage BE469 firmware bug workaround) + if not ( + usercode[ZWAVEJS_ATTR_USERCODE] == "" + or all(char == "0" for char in usercode[ZWAVEJS_ATTR_USERCODE]) + ): _LOGGER.debug( "[ZWaveJSProvider] Slot %s not yet cleared, will retry", slot_num, diff --git a/tests/providers/test_zwave_js.py b/tests/providers/test_zwave_js.py index 026067ce..efda5a61 100644 --- a/tests/providers/test_zwave_js.py +++ b/tests/providers/test_zwave_js.py @@ -401,6 +401,42 @@ async def test_clear_usercode_error(self, zwave_provider, mock_zwave_node): assert result is False + async def test_clear_usercode_schlage_bug_length_4(self, zwave_provider, mock_zwave_node): + """Test clear_usercode returns True when the returned value is 0000. Tests Schlage Bug.""" + zwave_provider._node = mock_zwave_node + + with ( + patch( + "custom_components.keymaster.providers.zwave_js.clear_usercode", + new_callable=AsyncMock, + ), + patch( + "custom_components.keymaster.providers.zwave_js.get_usercode", + return_value={"usercode": "0000"}, + ), + ): + result = await zwave_provider.async_clear_usercode(1) + + assert result is True + + async def test_clear_usercode_schlage_bug_length_6(self, zwave_provider, mock_zwave_node): + """Test clear_usercode returns True when the returned value is 000000. Tests Schlage Bug.""" + zwave_provider._node = mock_zwave_node + + with ( + patch( + "custom_components.keymaster.providers.zwave_js.clear_usercode", + new_callable=AsyncMock, + ), + patch( + "custom_components.keymaster.providers.zwave_js.get_usercode", + return_value={"usercode": "000000"}, + ), + ): + result = await zwave_provider.async_clear_usercode(1) + + assert result is True + class TestZWaveJSLockProviderEventSubscription: """Test ZWaveJSLockProvider event subscription."""