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
+ end
114
+ )
115
+
116
+ test .register_coroutine_test (
117
+ " Schlage-Lock device called 'migrate' command, validate codeLength is being properly set" ,
118
+ function ()
119
+ test .mock_device .add_test_device (schlage_mock_device )
120
+ test .socket .device_lifecycle :__queue_receive ({ schlage_mock_device .id , " added" })
121
+ test .socket .zwave :__expect_send (
122
+ zw_test_utils .zwave_test_build_send_command (
123
+ schlage_mock_device ,
124
+ DoorLock :OperationGet ({})
125
+ )
126
+ )
127
+ test .socket .zwave :__expect_send (
128
+ zw_test_utils .zwave_test_build_send_command (
129
+ schlage_mock_device ,
130
+ Battery :Get ({})
131
+ )
132
+ )
133
+ test .wait_for_events ()
134
+ -- Validate lockCodes field
135
+ mock_datastore .__assert_device_store_contains (schlage_mock_device .id , " _lock_codes" , { [" 1" ] = " Zach" , [" 5" ] = " Steven" })
136
+ -- Validate migration complete flag
137
+ mock_datastore .__assert_device_store_contains (schlage_mock_device .id , " migrationComplete" , true )
138
+ -- setup codes
139
+ test .socket .zwave :__queue_receive ({schlage_mock_device .id , UserCode :UsersNumberReport ({ supported_users = 4 }) })
140
+ test .socket .zwave :__queue_receive ({schlage_mock_device .id , Configuration :Report ({ parameter_number = SCHLAGE_LOCK_CODE_LENGTH_PARAM .number , configuration_value = 6 })})
141
+ test .socket .capability :__expect_send ( schlage_mock_device :generate_test_message (" main" , capabilities .lockCodes .maxCodes (4 , { visibility = { displayed = false } })))
142
+ test .socket .capability :__expect_send ( schlage_mock_device :generate_test_message (" main" , capabilities .lockCodes .codeLength (6 )))
143
+ test .wait_for_events ()
144
+ -- Validate migrate command
145
+ test .socket .capability :__queue_receive ({ schlage_mock_device .id , { capability = capabilities .lockCodes .ID , command = " migrate" , args = {} } })
146
+ test .socket .capability :__expect_send ( schlage_mock_device :generate_test_message (" main" , capabilities .lockCredentials .minPinCodeLen (6 , { visibility = { displayed = false } })))
147
+ test .socket .capability :__expect_send ( schlage_mock_device :generate_test_message (" main" , capabilities .lockCredentials .maxPinCodeLen (6 , { visibility = { displayed = false } })))
148
+ test .socket .capability :__expect_send ( schlage_mock_device :generate_test_message (" main" , capabilities .lockCredentials .pinUsersSupported (4 , { visibility = { displayed = false } })))
149
+ 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 } })))
150
+ test .socket .capability :__expect_send ( schlage_mock_device :generate_test_message (" main" , capabilities .lockCredentials .supportedCredentials ({" pin" }, { visibility = { displayed = false } })))
151
+ 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 } })))
152
+ test .socket .capability :__expect_send ( schlage_mock_device :generate_test_message (" main" , capabilities .lockCodes .migrated (true , { visibility = { displayed = false } })))
153
+ end
154
+ )
155
+
156
+ test .run_registered_tests ()
0 commit comments