From 6c621cb6ac06af8a1aba39291117fa447534cbd4 Mon Sep 17 00:00:00 2001 From: Pegor Date: Fri, 19 Sep 2025 12:21:53 -0700 Subject: [PATCH 1/4] CHAD-16364: SLGA: Add lockUsers and lockCredentials capabilities to profiles --- drivers/SmartThings/zigbee-lock/profiles/base-lock.yml | 4 ++++ drivers/SmartThings/zwave-lock/profiles/base-lock-tamper.yml | 4 ++++ drivers/SmartThings/zwave-lock/profiles/base-lock.yml | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/drivers/SmartThings/zigbee-lock/profiles/base-lock.yml b/drivers/SmartThings/zigbee-lock/profiles/base-lock.yml index 159e6939f3..c9c98898c6 100644 --- a/drivers/SmartThings/zigbee-lock/profiles/base-lock.yml +++ b/drivers/SmartThings/zigbee-lock/profiles/base-lock.yml @@ -6,6 +6,10 @@ components: version: 1 - id: lockCodes version: 1 + - id: lockCredentials + version: 1 + - id: lockUsers + version: 1 - id: battery version: 1 - id: firmwareUpdate diff --git a/drivers/SmartThings/zwave-lock/profiles/base-lock-tamper.yml b/drivers/SmartThings/zwave-lock/profiles/base-lock-tamper.yml index 5fbfb13f3d..e3a25ab57a 100644 --- a/drivers/SmartThings/zwave-lock/profiles/base-lock-tamper.yml +++ b/drivers/SmartThings/zwave-lock/profiles/base-lock-tamper.yml @@ -6,6 +6,10 @@ components: version: 1 - id: lockCodes version: 1 + - id: lockCredentials + version: 1 + - id: lockUsers + version: 1 - id: battery version: 1 - id: tamperAlert diff --git a/drivers/SmartThings/zwave-lock/profiles/base-lock.yml b/drivers/SmartThings/zwave-lock/profiles/base-lock.yml index f4957f9ad0..efb97c8b27 100644 --- a/drivers/SmartThings/zwave-lock/profiles/base-lock.yml +++ b/drivers/SmartThings/zwave-lock/profiles/base-lock.yml @@ -6,6 +6,10 @@ components: version: 1 - id: lockCodes version: 1 + - id: lockCredentials + version: 1 + - id: lockUsers + version: 1 - id: battery version: 1 - id: refresh From 88d8d990a4df21b47ae178fc01b43b8bc5faed12 Mon Sep 17 00:00:00 2001 From: Pegor Date: Tue, 30 Sep 2025 12:31:58 -0700 Subject: [PATCH 2/4] CHAD-16365: SLGA: Add implementation for Zigbee lockCodes:migrate command --- drivers/SmartThings/zigbee-lock/src/init.lua | 38 +++++++++ .../test_zigbee_lock_code_slga_migration.lua | 82 +++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 drivers/SmartThings/zigbee-lock/src/test/test_zigbee_lock_code_slga_migration.lua diff --git a/drivers/SmartThings/zigbee-lock/src/init.lua b/drivers/SmartThings/zigbee-lock/src/init.lua index ce6894b868..f76eaf51e0 100644 --- a/drivers/SmartThings/zigbee-lock/src/init.lua +++ b/drivers/SmartThings/zigbee-lock/src/init.lua @@ -28,6 +28,8 @@ local capabilities = require "st.capabilities" local Battery = capabilities.battery local Lock = capabilities.lock local LockCodes = capabilities.lockCodes +local LockCredentials = capabilities.lockCredentials +local LockUsers = capabilities.lockUsers -- Enums local UserStatusEnum = LockCluster.types.DrlkUserStatus @@ -291,6 +293,41 @@ local name_slot = function(driver, device, command) end end +local migrate = function(driver, device, command) + local lock_users = {} + local lock_credentials = {} + local lock_codes = lock_utils.get_lock_codes(device) + local ordered_codes = {} + + for code in pairs(lock_codes) do + table.insert(ordered_codes, code) + end + + table.sort(ordered_codes) + for index, code_slot in ipairs(ordered_codes) do + table.insert(lock_users, {userIndex = index, userType = "guest", userName = lock_codes[code_slot]}) + table.insert(lock_credentials, {userIndex = index, credentialIndex = tonumber(code_slot), credentialType = "pin"}) + end + + local code_length = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.codeLength.NAME) + local max_code_len = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.maxCodeLength.NAME) + local min_code_len = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.minCodeLength.NAME) + local max_codes = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.maxCodes.NAME) + + if (code_length ~= nil) then + max_code_len = code_length + min_code_len = code_length + end + + device:emit_event(LockCredentials.minPinCodeLen(min_code_len, { visibility = { displayed = false } })) + device:emit_event(LockCredentials.maxPinCodeLen(max_code_len, { visibility = { displayed = false } })) + device:emit_event(LockCredentials.pinUsersSupported(max_codes, { visibility = { displayed = false } })) + device:emit_event(LockCredentials.credentials(lock_credentials, { visibility = { displayed = false } })) + device:emit_event(LockCredentials.supportedCredentials({"pin"}, { visibility = { displayed = false } })) + device:emit_event(LockUsers.users(lock_users, { visibility = { displayed = false } })) + device:emit_event(LockCodes.migrated(true, { visibility = { displayed = false } })) +end + local function device_added(driver, device) lock_utils.populate_state_from_data(device) @@ -436,6 +473,7 @@ local zigbee_lock_driver = { [LockCodes.commands.requestCode.NAME] = request_code, [LockCodes.commands.setCode.NAME] = set_code, [LockCodes.commands.nameSlot.NAME] = name_slot, + [LockCodes.commands.migrate.NAME] = migrate, }, [Lock.ID] = { [Lock.commands.lock.NAME] = lock, diff --git a/drivers/SmartThings/zigbee-lock/src/test/test_zigbee_lock_code_slga_migration.lua b/drivers/SmartThings/zigbee-lock/src/test/test_zigbee_lock_code_slga_migration.lua new file mode 100644 index 0000000000..569dca5236 --- /dev/null +++ b/drivers/SmartThings/zigbee-lock/src/test/test_zigbee_lock_code_slga_migration.lua @@ -0,0 +1,82 @@ +-- Copyright 2025 SmartThings +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + +-- Mock out globals +local test = require "integration_test" +local zigbee_test_utils = require "integration_test.zigbee_test_utils" +local t_utils = require "integration_test.utils" + +local clusters = require "st.zigbee.zcl.clusters" +local PowerConfiguration = clusters.PowerConfiguration +local DoorLock = clusters.DoorLock +local Alarm = clusters.Alarms +local capabilities = require "st.capabilities" + +local json = require "st.json" + +local mock_datastore = require "integration_test.mock_env_datastore" + +local mock_device = test.mock_device.build_test_zigbee_device( + { + profile = t_utils.get_profile_definition("base-lock.yml"), + data = { + lockCodes = json.encode({ + ["1"] = "Zach", + ["5"] = "Steven" + }), + } + } +) + +zigbee_test_utils.prepare_zigbee_env_info() +local function test_init()end + +test.set_test_init_function(test_init) + +test.register_coroutine_test( + "Device called 'migrate' command", + function() + test.mock_device.add_test_device(mock_device) + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" }) + test.socket.zigbee:__expect_send({ mock_device.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device) }) + test.socket.zigbee:__expect_send({ mock_device.id, DoorLock.attributes.LockState:read(mock_device) }) + test.socket.zigbee:__expect_send({ mock_device.id, Alarm.attributes.AlarmCount:read(mock_device) }) + test.wait_for_events() + -- Validate lockCodes field + mock_datastore.__assert_device_store_contains(mock_device.id, "lockCodes", { ["1"] = "Zach", ["5"] = "Steven" }) + -- Validate migration complete flag + mock_datastore.__assert_device_store_contains(mock_device.id, "migrationComplete", true) + + -- Set min/max code length attributes + test.socket.zigbee:__queue_receive({ mock_device.id, DoorLock.attributes.MinPINCodeLength:build_test_attr_report(mock_device, 5) }) + test.socket.zigbee:__queue_receive({ mock_device.id, DoorLock.attributes.MaxPINCodeLength:build_test_attr_report(mock_device, 10) }) + test.socket.zigbee:__queue_receive({ mock_device.id, DoorLock.attributes.NumberOfPINUsersSupported:build_test_attr_report(mock_device, 4) }) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCodes.minCodeLength(5, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCodes.maxCodeLength(10, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCodes.maxCodes(4, { visibility = { displayed = false } }))) + test.wait_for_events() + -- Validate `migrate` command functionality. + test.socket.capability:__queue_receive({ mock_device.id, { capability = capabilities.lockCodes.ID, command = "migrate", args = {} } }) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCredentials.minPinCodeLen(5, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCredentials.maxPinCodeLen(10, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCredentials.pinUsersSupported(4, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCredentials.credentials({{credentialIndex=1, credentialType="pin", userIndex=1}, {credentialIndex=5, credentialType="pin", userIndex=2}}, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCredentials.supportedCredentials({"pin"}, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockUsers.users({{userIndex=1, userName="Zach", userType="guest"}, {userIndex=2, userName="Steven", userType="guest"}}, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCodes.migrated(true, { visibility = { displayed = false } }))) + test.wait_for_events() + end +) + +test.run_registered_tests() \ No newline at end of file From c2486785bbaff31d7c9ab12b600006b7f6d1cce4 Mon Sep 17 00:00:00 2001 From: Pegor Date: Tue, 30 Sep 2025 15:29:37 -0700 Subject: [PATCH 3/4] CHAD-16365: SLGA: Add implementation for ZWave lockCodes:migrate command --- drivers/SmartThings/zwave-lock/src/init.lua | 54 ++++++ .../test_zwave_lock_code_slga_migration.lua | 156 ++++++++++++++++++ 2 files changed, 210 insertions(+) create mode 100644 drivers/SmartThings/zwave-lock/src/test/test_zwave_lock_code_slga_migration.lua diff --git a/drivers/SmartThings/zwave-lock/src/init.lua b/drivers/SmartThings/zwave-lock/src/init.lua index b83b196256..cb44541ebf 100644 --- a/drivers/SmartThings/zwave-lock/src/init.lua +++ b/drivers/SmartThings/zwave-lock/src/init.lua @@ -146,6 +146,55 @@ local function update_codes(driver, device, cmd) end end +--- @param driver st.zwave.Driver +--- @param device st.zwave.Device +--- @param cmd table +local function migrate(driver, device, cmd) + local lock_users = {} + local lock_credentials = {} + local lc_data = json.decode(device.data.lockCodes) + local lock_codes = {} + local ordered_codes = {} + for k, v in pairs(lc_data) do + lock_codes[k] = v + end + + for code in pairs(lock_codes) do + table.insert(ordered_codes, code) + end + + table.sort(ordered_codes) + for index = 1, #ordered_codes do + local code_slot, code_name = ordered_codes[index], lock_codes[ ordered_codes[index] ] + table.insert(lock_users, {userIndex = index, userType = "guest", userName = code_name}) + table.insert(lock_credentials, {userIndex = index, credentialIndex = tonumber(code_slot), credentialType = "pin"}) + end + + local code_length = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.codeLength.NAME) + local min_code_len = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.minCodeLength.NAME) + local max_code_len = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.maxCodeLength.NAME) + local max_codes = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.maxCodes.NAME) + + if (min_code_len == nil) then + min_code_len = 4 -- per ZWave spec + end + if (max_code_len == nil) then + max_code_len = 10 -- per ZWave spec + end + if (code_length ~= nil) then + max_code_len = code_length + min_code_len = code_length + end + + device:emit_event(capabilities.lockCredentials.minPinCodeLen(min_code_len, { visibility = { displayed = false } })) + device:emit_event(capabilities.lockCredentials.maxPinCodeLen(max_code_len, { visibility = { displayed = false } })) + device:emit_event(capabilities.lockCredentials.pinUsersSupported(max_codes, { visibility = { displayed = false } })) + device:emit_event(capabilities.lockCredentials.credentials(lock_credentials, { visibility = { displayed = false } })) + device:emit_event(capabilities.lockCredentials.supportedCredentials({"pin"}, { visibility = { displayed = false } })) + device:emit_event(capabilities.lockUsers.users(lock_users, { visibility = { displayed = false } })) + device:emit_event(capabilities.lockCodes.migrated(true, { visibility = { displayed = false } })) +end + local function time_get_handler(driver, device, cmd) local time = os.date("*t") device:send_to_component( @@ -162,6 +211,8 @@ local driver_template = { supported_capabilities = { capabilities.lock, capabilities.lockCodes, + capabilities.lockUsers, + capabilities.lockCredentials, capabilities.battery, capabilities.tamperAlert }, @@ -173,6 +224,9 @@ local driver_template = { [capabilities.lockCodes.ID] = { [capabilities.lockCodes.commands.updateCodes.NAME] = update_codes }, + [capabilities.lockCodes.ID] = { + [capabilities.lockCodes.commands.migrate.NAME] = migrate + }, [capabilities.refresh.ID] = { [capabilities.refresh.commands.refresh.NAME] = do_refresh } diff --git a/drivers/SmartThings/zwave-lock/src/test/test_zwave_lock_code_slga_migration.lua b/drivers/SmartThings/zwave-lock/src/test/test_zwave_lock_code_slga_migration.lua new file mode 100644 index 0000000000..17629c1912 --- /dev/null +++ b/drivers/SmartThings/zwave-lock/src/test/test_zwave_lock_code_slga_migration.lua @@ -0,0 +1,156 @@ +-- Copyright 2025 SmartThings +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + +-- Mock out globals +local test = require "integration_test" +local capabilities = require "st.capabilities" +local zw = require "st.zwave" +--- @type st.zwave.CommandClass.DoorLock +local DoorLock = (require "st.zwave.CommandClass.DoorLock")({ version = 1 }) +--- @type st.zwave.CommandClass.Battery +local Battery = (require "st.zwave.CommandClass.Battery")({ version = 1 }) +--- @type st.zwave.CommandClass.UserCode +local UserCode = (require "st.zwave.CommandClass.UserCode")({ version = 1 }) +local Configuration = (require "st.zwave.CommandClass.Configuration")({ version = 2 }) +local t_utils = require "integration_test.utils" +local zw_test_utils = require "integration_test.zwave_test_utils" +local utils = require "st.utils" +local mock_datastore = require "integration_test.mock_env_datastore" +local json = require "dkjson" + +local SCHLAGE_MANUFACTURER_ID = 0x003B +local SCHLAGE_PRODUCT_TYPE = 0x0002 +local SCHLAGE_PRODUCT_ID = 0x0469 + +local zwave_lock_endpoints = { + { + command_classes = { + { value = zw.BATTERY }, + { value = zw.DOOR_LOCK }, + { value = zw.USER_CODE }, + { value = zw.NOTIFICATION } + } + } +} + +local lockCodes = { + ["1"] = "Zach", + ["5"] = "Steven" +} + +local mock_device = test.mock_device.build_test_zwave_device( + { + profile = t_utils.get_profile_definition("base-lock-tamper.yml"), + zwave_endpoints = zwave_lock_endpoints, + data = { + lockCodes = json.encode(utils.deep_copy(lockCodes)) + } + } +) + +local schlage_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 = SCHLAGE_MANUFACTURER_ID, + zwave_product_type = SCHLAGE_PRODUCT_TYPE, + zwave_product_id = SCHLAGE_PRODUCT_ID, + data = { + lockCodes = json.encode(utils.deep_copy(lockCodes)) + } + } +) + +local SCHLAGE_LOCK_CODE_LENGTH_PARAM = {number = 16, size = 1} + +test.register_coroutine_test( + "Device called 'migrate' command", + function() + test.mock_device.add_test_device(mock_device) + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" }) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_device, + DoorLock:OperationGet({}) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_device, + Battery:Get({}) + ) + ) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.tamperAlert.tamper.clear())) + test.wait_for_events() + -- Validate lockCodes field + mock_datastore.__assert_device_store_contains(mock_device.id, "_lock_codes", { ["1"] = "Zach", ["5"] = "Steven" }) + -- Validate migration complete flag + mock_datastore.__assert_device_store_contains(mock_device.id, "migrationComplete", true) + -- setup codes + test.socket.zwave:__queue_receive({mock_device.id, UserCode:UsersNumberReport({ supported_users = 4 }) }) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCodes.maxCodes(4, { visibility = { displayed = false } }))) + test.wait_for_events() + -- Validate migrate command + test.socket.capability:__queue_receive({ mock_device.id, { capability = capabilities.lockCodes.ID, command = "migrate", args = {} } }) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCredentials.minPinCodeLen(4, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCredentials.maxPinCodeLen(10, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCredentials.pinUsersSupported(4, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCredentials.credentials({{credentialIndex=1, credentialType="pin", userIndex=1}, {credentialIndex=5, credentialType="pin", userIndex=2}}, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCredentials.supportedCredentials({"pin"}, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockUsers.users({{userIndex=1, userName="Zach", userType="guest"}, {userIndex=2, userName="Steven", userType="guest"}}, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCodes.migrated(true, { visibility = { displayed = false } }))) + end +) + +test.register_coroutine_test( + "Schlage-Lock device called 'migrate' command, validate codeLength is being properly set", + function() + test.mock_device.add_test_device(schlage_mock_device) + test.socket.device_lifecycle:__queue_receive({ schlage_mock_device.id, "added" }) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + schlage_mock_device, + DoorLock:OperationGet({}) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + schlage_mock_device, + Battery:Get({}) + ) + ) + test.wait_for_events() + -- Validate lockCodes field + mock_datastore.__assert_device_store_contains(schlage_mock_device.id, "_lock_codes", { ["1"] = "Zach", ["5"] = "Steven" }) + -- Validate migration complete flag + mock_datastore.__assert_device_store_contains(schlage_mock_device.id, "migrationComplete", true) + -- setup codes + test.socket.zwave:__queue_receive({schlage_mock_device.id, UserCode:UsersNumberReport({ supported_users = 4 }) }) + test.socket.zwave:__queue_receive({schlage_mock_device.id, Configuration:Report({ parameter_number = SCHLAGE_LOCK_CODE_LENGTH_PARAM.number, configuration_value = 6 })}) + test.socket.capability:__expect_send( schlage_mock_device:generate_test_message("main", capabilities.lockCodes.maxCodes(4, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( schlage_mock_device:generate_test_message("main", capabilities.lockCodes.codeLength(6))) + test.wait_for_events() + -- Validate migrate command + test.socket.capability:__queue_receive({ schlage_mock_device.id, { capability = capabilities.lockCodes.ID, command = "migrate", args = {} } }) + test.socket.capability:__expect_send( schlage_mock_device:generate_test_message("main", capabilities.lockCredentials.minPinCodeLen(6, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( schlage_mock_device:generate_test_message("main", capabilities.lockCredentials.maxPinCodeLen(6, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( schlage_mock_device:generate_test_message("main", capabilities.lockCredentials.pinUsersSupported(4, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( schlage_mock_device:generate_test_message("main", capabilities.lockCredentials.credentials({{credentialIndex=1, credentialType="pin", userIndex=1}, {credentialIndex=5, credentialType="pin", userIndex=2}}, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( schlage_mock_device:generate_test_message("main", capabilities.lockCredentials.supportedCredentials({"pin"}, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( schlage_mock_device:generate_test_message("main", capabilities.lockUsers.users({{userIndex=1, userName="Zach", userType="guest"}, {userIndex=2, userName="Steven", userType="guest"}}, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send( schlage_mock_device:generate_test_message("main", capabilities.lockCodes.migrated(true, { visibility = { displayed = false } }))) + end +) + +test.run_registered_tests() \ No newline at end of file From be53bc50f7f5170b39de9f1b96acd788b4a3fc79 Mon Sep 17 00:00:00 2001 From: Pegor Date: Wed, 1 Oct 2025 14:36:58 -0700 Subject: [PATCH 4/4] PR discussion fixes --- drivers/SmartThings/zigbee-lock/src/init.lua | 5 ++--- drivers/SmartThings/zwave-lock/src/init.lua | 19 ++++++------------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/SmartThings/zigbee-lock/src/init.lua b/drivers/SmartThings/zigbee-lock/src/init.lua index f76eaf51e0..8fc0a3499c 100644 --- a/drivers/SmartThings/zigbee-lock/src/init.lua +++ b/drivers/SmartThings/zigbee-lock/src/init.lua @@ -310,10 +310,9 @@ local migrate = function(driver, device, command) end local code_length = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.codeLength.NAME) - local max_code_len = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.maxCodeLength.NAME) - local min_code_len = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.minCodeLength.NAME) + local max_code_len = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.maxCodeLength.NAME, 4) + local min_code_len = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.minCodeLength.NAME, 8) local max_codes = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.maxCodes.NAME) - if (code_length ~= nil) then max_code_len = code_length min_code_len = code_length diff --git a/drivers/SmartThings/zwave-lock/src/init.lua b/drivers/SmartThings/zwave-lock/src/init.lua index cb44541ebf..2710ee7a59 100644 --- a/drivers/SmartThings/zwave-lock/src/init.lua +++ b/drivers/SmartThings/zwave-lock/src/init.lua @@ -160,27 +160,20 @@ local function migrate(driver, device, cmd) end for code in pairs(lock_codes) do - table.insert(ordered_codes, code) + table.insert(ordered_codes, code) end table.sort(ordered_codes) for index = 1, #ordered_codes do - local code_slot, code_name = ordered_codes[index], lock_codes[ ordered_codes[index] ] - table.insert(lock_users, {userIndex = index, userType = "guest", userName = code_name}) - table.insert(lock_credentials, {userIndex = index, credentialIndex = tonumber(code_slot), credentialType = "pin"}) + local code_slot, code_name = ordered_codes[index], lock_codes[ ordered_codes[index] ] + table.insert(lock_users, {userIndex = index, userType = "guest", userName = code_name}) + table.insert(lock_credentials, {userIndex = index, credentialIndex = tonumber(code_slot), credentialType = "pin"}) end local code_length = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.codeLength.NAME) - local min_code_len = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.minCodeLength.NAME) - local max_code_len = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.maxCodeLength.NAME) + local min_code_len = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.minCodeLength.NAME, 4) + local max_code_len = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.maxCodeLength.NAME, 10) local max_codes = device:get_latest_state("main", capabilities.lockCodes.ID, capabilities.lockCodes.maxCodes.NAME) - - if (min_code_len == nil) then - min_code_len = 4 -- per ZWave spec - end - if (max_code_len == nil) then - max_code_len = 10 -- per ZWave spec - end if (code_length ~= nil) then max_code_len = code_length min_code_len = code_length