From db690b0b6710cc1484c00075aa7a31bec8dd8350 Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Fri, 30 Oct 2026 14:04:24 -0500 Subject: [PATCH] Zwave lock: let Schlage masked code reports advance credential sync Co-Authored-By: Claude Sonnet 5.5 --- .../zwave-lock/src/schlage-lock/init.lua | 5 ++ .../zwave-lock/src/test/test_schlage_lock.lua | 77 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 drivers/SmartThings/zwave-lock/src/test/test_schlage_lock.lua diff --git a/drivers/SmartThings/zwave-lock/src/schlage-lock/init.lua b/drivers/SmartThings/zwave-lock/src/schlage-lock/init.lua index ee04fe42a0..5d15d507f2 100644 --- a/drivers/SmartThings/zwave-lock/src/schlage-lock/init.lua +++ b/drivers/SmartThings/zwave-lock/src/schlage-lock/init.lua @@ -11,6 +11,7 @@ local Configuration = (require "st.zwave.CommandClass.Configuration")({version=2 local Basic = (require "st.zwave.CommandClass.Basic")({version=1}) local Association = (require "st.zwave.CommandClass.Association")({version=1}) +local consts = require "lock_utils.constants" local tables = require "lock_utils.tables" local zwave_handlers = require "lock_handlers.zwave_responses" local cap_handlers = require "lock_handlers.capabilities" @@ -58,6 +59,10 @@ local function is_user_code_report_mfr_specific(device, cmd) end local function user_code_report_handler(self, device, cmd) + if device:get_field(consts.DRIVER_STATE.COMMAND_IN_PROGRESS) == consts.SYNC.CODES_FROM_LOCK then + zwave_handlers.user_code_report(self, device, cmd) + return + end local credential_index = cmd.args.user_identifier if is_user_code_report_mfr_specific(device, cmd) then local reported_user_id_status = cmd.args.user_id_status diff --git a/drivers/SmartThings/zwave-lock/src/test/test_schlage_lock.lua b/drivers/SmartThings/zwave-lock/src/test/test_schlage_lock.lua new file mode 100644 index 0000000000..cc608b7d2a --- /dev/null +++ b/drivers/SmartThings/zwave-lock/src/test/test_schlage_lock.lua @@ -0,0 +1,77 @@ +-- Copyright 2026 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local test = require "integration_test" +local t_utils = require "integration_test.utils" +local capabilities = require "st.capabilities" +local zw = require "st.zwave" +local constants = require "lock_utils.constants" + +--- @type st.zwave.CommandClass.UserCode +local UserCode = (require "st.zwave.CommandClass.UserCode")({ version = 1 }) + +local zwave_lock_endpoints = { + { + command_classes = { + { value = zw.BATTERY }, + { value = zw.DOOR_LOCK }, + { value = zw.USER_CODE }, + { value = zw.NOTIFICATION }, + } + } +} + +local mock_device = test.mock_device.build_test_zwave_device({ + profile = t_utils.get_profile_definition("base-lock.yml"), + zwave_endpoints = zwave_lock_endpoints, + zwave_manufacturer_id = 0x003B, + zwave_product_type = 0x0002, + zwave_product_id = 0x0469, +}) + +local function test_init() + test.disable_startup_messages() + test.mock_device.add_test_device(mock_device) + mock_device:set_field(constants.DRIVER_STATE.SLGA_MIGRATED, true, {}) +end +test.set_test_init_function(test_init) + +test.register_coroutine_test( + "Masked occupied USER_CODE_REPORT during code sync advances to the next slot", + function() + mock_device:set_field(constants.DRIVER_STATE.BUSY, os.time(), {}) + mock_device:set_field(constants.DRIVER_STATE.COMMAND_IN_PROGRESS, constants.SYNC.CODES_FROM_LOCK, {}) + mock_device:set_field(constants.SYNC.CODE_INDEX, 1, {}) + + test.socket.zwave:__queue_receive({ + mock_device.id, + UserCode:Report({ + user_identifier = 1, + user_id_status = UserCode.user_id_status.ENABLED_GRANT_ACCESS, + user_code = "**********", + }), + }) + + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", + capabilities.lockUsers.users( + { { userIndex = 1, userName = "Guest 1", userType = "guest" } }, + { visibility = { displayed = false } } + )) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", + capabilities.lockCredentials.credentials( + { { userIndex = 1, credentialIndex = 1, credentialType = "pin", credentialName = "Guest 1" } }, + { visibility = { displayed = false } } + )) + ) + test.socket.zwave:__expect_send( + UserCode:Get({ user_identifier = 2 }):build_test_tx(mock_device.id) + ) + test.wait_for_events() + end, + { min_api_version = 15 } +) + +test.run_registered_tests()