1+ -- Copyright 2025 SmartThings
2+ --
3+ -- Licensed under the Apache License, Version 2.0 (the "License");
4+ -- you may not use this file except in compliance with the License.
5+ -- You may obtain a copy of the License at
6+ --
7+ -- http://www.apache.org/licenses/LICENSE-2.0
8+ --
9+ -- Unless required by applicable law or agreed to in writing, software
10+ -- distributed under the License is distributed on an "AS IS" BASIS,
11+ -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ -- See the License for the specific language governing permissions and
13+ -- limitations under the License.
14+
15+ -- Mock out globals
16+ local test = require " integration_test"
17+ local capabilities = require " st.capabilities"
18+ local zw = require " st.zwave"
19+ --- @type st.zwave.CommandClass.DoorLock
20+ local DoorLock = (require " st.zwave.CommandClass.DoorLock" )({ version = 1 })
21+ --- @type st.zwave.CommandClass.Battery
22+ local Battery = (require " st.zwave.CommandClass.Battery" )({ version = 1 })
23+ --- @type st.zwave.CommandClass.UserCode
24+ local UserCode = (require " st.zwave.CommandClass.UserCode" )({ version = 1 })
25+ local Configuration = (require " st.zwave.CommandClass.Configuration" )({ version = 2 })
26+ local t_utils = require " integration_test.utils"
27+ local zw_test_utils = require " integration_test.zwave_test_utils"
28+ local utils = require " st.utils"
29+ local mock_datastore = require " integration_test.mock_env_datastore"
30+ local json = require " dkjson"
31+
32+ local SCHLAGE_MANUFACTURER_ID = 0x003B
33+ local SCHLAGE_PRODUCT_TYPE = 0x0002
34+ local SCHLAGE_PRODUCT_ID = 0x0469
35+
36+ local zwave_lock_endpoints = {
37+ {
38+ command_classes = {
39+ { value = zw .BATTERY },
40+ { value = zw .DOOR_LOCK },
41+ { value = zw .USER_CODE },
42+ { value = zw .NOTIFICATION }
43+ }
44+ }
45+ }
46+
47+ local lockCodes = {
48+ [" 1" ] = " Zach" ,
49+ [" 5" ] = " Steven"
50+ }
51+
52+ local mock_device = test .mock_device .build_test_zwave_device (
53+ {
54+ profile = t_utils .get_profile_definition (" base-lock-tamper.yml" ),
55+ zwave_endpoints = zwave_lock_endpoints ,
56+ data = {
57+ lockCodes = json .encode (utils .deep_copy (lockCodes ))
58+ }
59+ }
60+ )
61+
62+ local schlage_mock_device = test .mock_device .build_test_zwave_device (
63+ {
64+ profile = t_utils .get_profile_definition (" base-lock.yml" ),
65+ zwave_endpoints = zwave_lock_endpoints ,
66+ zwave_manufacturer_id = SCHLAGE_MANUFACTURER_ID ,
67+ zwave_product_type = SCHLAGE_PRODUCT_TYPE ,
68+ zwave_product_id = SCHLAGE_PRODUCT_ID ,
69+ data = {
70+ lockCodes = json .encode (utils .deep_copy (lockCodes ))
71+ }
72+ }
73+ )
74+
75+ local SCHLAGE_LOCK_CODE_LENGTH_PARAM = {number = 16 , size = 1 }
76+
77+ test .register_coroutine_test (
78+ " Device called 'migrate' command" ,
79+ function ()
80+ test .mock_device .add_test_device (mock_device )
81+ test .socket .device_lifecycle :__queue_receive ({ mock_device .id , " added" })
82+ test .socket .zwave :__expect_send (
83+ zw_test_utils .zwave_test_build_send_command (
84+ mock_device ,
85+ DoorLock :OperationGet ({})
86+ )
87+ )
88+ test .socket .zwave :__expect_send (
89+ zw_test_utils .zwave_test_build_send_command (
90+ mock_device ,
91+ Battery :Get ({})
92+ )
93+ )
94+ test .socket .capability :__expect_send (mock_device :generate_test_message (" main" , capabilities .tamperAlert .tamper .clear ()))
95+ test .wait_for_events ()
96+ -- Validate lockCodes field
97+ mock_datastore .__assert_device_store_contains (mock_device .id , " _lock_codes" , { [" 1" ] = " Zach" , [" 5" ] = " Steven" })
98+ -- Validate migration complete flag
99+ mock_datastore .__assert_device_store_contains (mock_device .id , " migrationComplete" , true )
100+ -- setup codes
101+ test .socket .zwave :__queue_receive ({mock_device .id , UserCode :UsersNumberReport ({ supported_users = 4 }) })
102+ test .socket .capability :__expect_send ( mock_device :generate_test_message (" main" , capabilities .lockCodes .maxCodes (4 , { visibility = { displayed = false } })))
103+ test .wait_for_events ()
104+ -- Validate migrate command
105+ test .socket .capability :__queue_receive ({ mock_device .id , { capability = capabilities .lockCodes .ID , command = " migrate" , args = {} } })
106+ test .socket .capability :__expect_send ( mock_device :generate_test_message (" main" , capabilities .lockCredentials .minPinCodeLen (4 , { visibility = { displayed = false } })))
107+ test .socket .capability :__expect_send ( mock_device :generate_test_message (" main" , capabilities .lockCredentials .maxPinCodeLen (10 , { visibility = { displayed = false } })))
108+ test .socket .capability :__expect_send ( mock_device :generate_test_message (" main" , capabilities .lockCredentials .pinUsersSupported (4 , { visibility = { displayed = false } })))
109+ 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 } })))
110+ test .socket .capability :__expect_send ( mock_device :generate_test_message (" main" , capabilities .lockCredentials .supportedCredentials ({" pin" }, { visibility = { displayed = false } })))
111+ 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 } })))
112+ test .socket .capability :__expect_send ( mock_device :generate_test_message (" main" , capabilities .lockCodes .migrated (true , { visibility = { displayed = false } })))
113+
114+ end
115+ )
116+
117+ test .register_coroutine_test (
118+ " Schlage-Lock device called 'migrate' command, validate codeLength is being properly set" ,
119+ function ()
120+ test .mock_device .add_test_device (schlage_mock_device )
121+ test .socket .device_lifecycle :__queue_receive ({ schlage_mock_device .id , " added" })
122+ test .socket .zwave :__expect_send (
123+ zw_test_utils .zwave_test_build_send_command (
124+ schlage_mock_device ,
125+ DoorLock :OperationGet ({})
126+ )
127+ )
128+ test .socket .zwave :__expect_send (
129+ zw_test_utils .zwave_test_build_send_command (
130+ schlage_mock_device ,
131+ Battery :Get ({})
132+ )
133+ )
134+ test .wait_for_events ()
135+ -- Validate lockCodes field
136+ mock_datastore .__assert_device_store_contains (schlage_mock_device .id , " _lock_codes" , { [" 1" ] = " Zach" , [" 5" ] = " Steven" })
137+ -- Validate migration complete flag
138+ mock_datastore .__assert_device_store_contains (schlage_mock_device .id , " migrationComplete" , true )
139+ -- setup codes
140+ test .socket .zwave :__queue_receive ({schlage_mock_device .id , UserCode :UsersNumberReport ({ supported_users = 4 }) })
141+ test .socket .zwave :__queue_receive ({schlage_mock_device .id , Configuration :Report ({ parameter_number = SCHLAGE_LOCK_CODE_LENGTH_PARAM .number , configuration_value = 6 })})
142+ test .socket .capability :__expect_send ( schlage_mock_device :generate_test_message (" main" , capabilities .lockCodes .maxCodes (4 , { visibility = { displayed = false } })))
143+ test .socket .capability :__expect_send ( schlage_mock_device :generate_test_message (" main" , capabilities .lockCodes .codeLength (6 )))
144+ test .wait_for_events ()
145+ -- Validate migrate command
146+ test .socket .capability :__queue_receive ({ schlage_mock_device .id , { capability = capabilities .lockCodes .ID , command = " migrate" , args = {} } })
147+ test .socket .capability :__expect_send ( schlage_mock_device :generate_test_message (" main" , capabilities .lockCredentials .minPinCodeLen (6 , { visibility = { displayed = false } })))
148+ test .socket .capability :__expect_send ( schlage_mock_device :generate_test_message (" main" , capabilities .lockCredentials .maxPinCodeLen (6 , { visibility = { displayed = false } })))
149+ test .socket .capability :__expect_send ( schlage_mock_device :generate_test_message (" main" , capabilities .lockCredentials .pinUsersSupported (4 , { visibility = { displayed = false } })))
150+ 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 } })))
151+ test .socket .capability :__expect_send ( schlage_mock_device :generate_test_message (" main" , capabilities .lockCredentials .supportedCredentials ({" pin" }, { visibility = { displayed = false } })))
152+ 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 } })))
153+ test .socket .capability :__expect_send ( schlage_mock_device :generate_test_message (" main" , capabilities .lockCodes .migrated (true , { visibility = { displayed = false } })))
154+
155+ end
156+ )
157+
158+ test .run_registered_tests ()
0 commit comments