Skip to content

Commit af6f071

Browse files
committed
This commit fix the issue of some device "false alarm" after hub switch-over.
We Add check_latest state before sending initial event(open/unlocked/presense) for following drivers: - SmartThings/zigbee-contact/src/aqara/ - SmartThings/zigbee-lock/src/samsungsds - SmartThings/zigbee-presence-sensor/src/arrival-sensor-v1 - SmartThings/zigbee-presence-sensor/src (top-most driver) - SmartThings/zigbee-thermostat/src/aqara - SmartThings/zwave-sensor/src/fibaro-door-window-sensor/fibaro-door-window-sensor-1 - SmartThings/zwave-sensor/src/fibaro-door-window-sensor/fibaro-door-window-sensor-2
1 parent 7ac3da8 commit af6f071

File tree

14 files changed

+206
-53
lines changed

14 files changed

+206
-53
lines changed

drivers/SmartThings/zigbee-contact/src/aqara/init.lua

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,17 @@ local function do_configure(self, device)
6363
PRIVATE_CLUSTER_ID, PRIVATE_ATTRIBUTE_ID, MFG_CODE, data_types.Uint8, 0x01))
6464
end
6565

66+
local function emit_event_if_latest_state_missing(device, component, capability, attribute_name, value)
67+
if device:get_latest_state(component, capability.ID, attribute_name) == nil and device:supports_capability(capability) then
68+
device:emit_event(value)
69+
end
70+
end
71+
6672
local function added_handler(driver, device)
6773
device:emit_event(capabilities.batteryLevel.type("CR1632"))
6874
device:emit_event(capabilities.batteryLevel.quantity(1))
6975
device:emit_event(capabilities.batteryLevel.battery("normal"))
70-
device:emit_event(capabilities.contactSensor.contact.closed())
76+
emit_event_if_latest_state_missing(device, "main", capabilities.contactSensor, capabilities.contactSensor.contact.NAME, capabilities.contactSensor.contact.open())
7177
end
7278

7379
local function contact_status_handler(self, device, value, zb_rx)

drivers/SmartThings/zigbee-contact/src/test/test_aqara_contact_sensor.lua

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,21 @@ test.register_coroutine_test(
8181
test.register_coroutine_test(
8282
"added lifecycle handler",
8383
function()
84+
-- The initial contactSensor event should be send during the device's first time onboarding
8485
test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" })
8586
test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.batteryLevel.type("CR1632")))
8687
test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.batteryLevel.quantity(1)))
8788
test.socket.capability:__expect_send(mock_device:generate_test_message("main",
8889
capabilities.batteryLevel.battery("normal")))
8990
test.socket.capability:__expect_send(mock_device:generate_test_message("main",
90-
capabilities.contactSensor.contact.closed()))
91+
capabilities.contactSensor.contact.open()))
92+
test.wait_for_events()
93+
-- Avoid sending the initial contactSensor event after driver switch-over, as the switch-over event itself re-triggers the added lifecycle.
94+
test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" })
95+
test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.batteryLevel.type("CR1632")))
96+
test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.batteryLevel.quantity(1)))
97+
test.socket.capability:__expect_send(mock_device:generate_test_message("main",
98+
capabilities.batteryLevel.battery("normal")))
9199
end
92100
)
93101

drivers/SmartThings/zigbee-lock/src/samsungsds/init.lua

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,15 @@ local refresh = function(driver, device, cmd)
5757
-- do nothing in refresh capability handler
5858
end
5959

60+
local function emit_event_if_latest_state_missing(device, component, capability, attribute_name, value)
61+
if device:get_latest_state(component, capability.ID, attribute_name) == nil and device:supports_capability(capability) then
62+
device:emit_event(value)
63+
end
64+
end
65+
6066
local device_added = function(self, device)
6167
lock_utils.populate_state_from_data(device)
62-
device:emit_event(capabilities.lock.lock.unlocked())
68+
emit_event_if_latest_state_missing(device, "main", capabilities.lock, capabilities.lock.lock.NAME, capabilities.lock.lock.unlocked())
6369
device:emit_event(capabilities.battery.battery(100))
6470
end
6571

drivers/SmartThings/zigbee-lock/src/test/test_zigbee_samsungsds.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,11 +1377,17 @@ test.register_coroutine_test(
13771377
test.register_coroutine_test(
13781378
"Device added function handler",
13791379
function()
1380+
-- The initial lock event should be send during the device's first time onboarding
13801381
test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added"})
13811382
test.socket.capability:__set_channel_ordering("relaxed")
13821383
test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(100)))
13831384
test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.lock.lock.unlocked()))
13841385
test.wait_for_events()
1386+
-- Avoid sending the initial lock event after driver switch-over, as the switch-over event itself re-triggers the added lifecycle.
1387+
test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added"})
1388+
test.socket.capability:__set_channel_ordering("relaxed")
1389+
test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(100)))
1390+
test.wait_for_events()
13851391
end
13861392
)
13871393

drivers/SmartThings/zigbee-presence-sensor/src/arrival-sensor-v1/init.lua

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,14 @@ local function beep_handler(self, device, command)
100100
end
101101
end
102102

103+
local function emit_event_if_latest_state_missing(device, component, capability, attribute_name, value)
104+
if device:get_latest_state(component, capability.ID, attribute_name) == nil and device:supports_capability(capability) then
105+
device:emit_event(value)
106+
end
107+
end
108+
103109
local function added_handler(self, device)
104-
device:emit_event(PresenceSensor.presence("present"))
110+
emit_event_if_latest_state_missing(device, "main", PresenceSensor, PresenceSensor.presence.NAME, PresenceSensor.presence("present"))
105111
end
106112

107113
local function init_handler(self, device, event, args)

drivers/SmartThings/zigbee-presence-sensor/src/init.lua

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,14 @@ local function beep_handler(self, device, command)
139139
device:send(IdentifyCluster.server.commands.Identify(device, BEEP_IDENTIFY_TIME))
140140
end
141141

142+
local function emit_event_if_latest_state_missing(device, component, capability, attribute_name, value)
143+
if device:get_latest_state(component, capability.ID, attribute_name) == nil and device:supports_capability(capability) then
144+
device:emit_event(value)
145+
end
146+
end
147+
142148
local function added_handler(self, device)
143-
device:emit_event(PresenceSensor.presence("present"))
149+
emit_event_if_latest_state_missing(device, "main", PresenceSensor, PresenceSensor.presence.NAME, PresenceSensor.presence("present"))
144150
device:set_field(IS_PRESENCE_BASED_ON_BATTERY_REPORTS, false, {persist = true})
145151
device:send(PowerConfiguration.attributes.BatteryVoltage:read(device))
146152
end

drivers/SmartThings/zigbee-presence-sensor/src/test/test_st_arrival_sensor_v1.lua

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,20 @@ end
6868
zigbee_test_utils.prepare_zigbee_env_info()
6969

7070
local add_device = function()
71+
-- The initial presenceSensor event should be send during the device's first time onboarding
7172
test.socket.device_lifecycle:__queue_receive({ mock_simple_device.id, "added"})
7273
test.socket.capability:__expect_send(mock_simple_device:generate_test_message("main",
7374
capabilities.presenceSensor.presence("present")
7475
))
7576
test.wait_for_events()
7677
end
7778

79+
local add_device_after_switch_over = function()
80+
-- Avoid sending the initial presenceSensor event after driver switch-over, as the switch-over event itself re-triggers the added lifecycle.
81+
test.socket.device_lifecycle:__queue_receive({ mock_simple_device.id, "added"})
82+
test.wait_for_events()
83+
end
84+
7885
local function test_init()
7986
test.mock_device.add_test_device(mock_simple_device)end
8087

@@ -126,6 +133,7 @@ test.register_coroutine_test(
126133
"Added lifecycle should be handlded",
127134
function ()
128135
add_device()
136+
add_device_after_switch_over()
129137
end
130138
)
131139

drivers/SmartThings/zigbee-presence-sensor/src/test/test_zigbee_presence_sensor.lua

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ test.register_message_test(
109109
)
110110

111111
local add_device = function()
112+
-- The initial presenceSensor event should be send during the device's first time onboarding
112113
test.socket.device_lifecycle:__queue_receive({ mock_simple_device.id, "added"})
113114
test.socket.capability:__expect_send(mock_simple_device:generate_test_message("main",
114115
capabilities.presenceSensor.presence("present")
@@ -120,6 +121,16 @@ local add_device = function()
120121
test.wait_for_events()
121122
end
122123

124+
local add_device_after_switch_over = function()
125+
-- Avoid sending the initial presenceSensor event after driver switch-over, as the switch-over event itself re-triggers the added lifecycle.
126+
test.socket.device_lifecycle:__queue_receive({ mock_simple_device.id, "added"})
127+
test.socket.zigbee:__expect_send({
128+
mock_simple_device.id,
129+
PowerConfiguration.attributes.BatteryVoltage:read(mock_simple_device)
130+
})
131+
test.wait_for_events()
132+
end
133+
123134
test.register_coroutine_test(
124135
"Battery Voltage test cases when polling from hub",
125136
function()
@@ -185,6 +196,7 @@ test.register_coroutine_test(
185196
"Added lifecycle should be handlded",
186197
function ()
187198
add_device()
199+
add_device_after_switch_over()
188200
end
189201
)
190202

drivers/SmartThings/zigbee-thermostat/src/aqara/init.lua

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,17 +110,29 @@ local function device_init(driver, device)
110110
do_refresh(driver, device)
111111
end
112112

113+
local function emit_event_if_latest_state_missing(device, component, capability, attribute_name, value)
114+
if device:get_latest_state(component, capability.ID, attribute_name) == nil and device:supports_capability(capability) then
115+
device:emit_event(value)
116+
end
117+
end
118+
119+
local function emit_component_event_if_latest_state_missing(device, component, capability, attribute_name, value)
120+
if device:get_latest_state(component.id, capability.ID, attribute_name) == nil and device:supports_capability(capability) then
121+
device:emit_component_event(component, value)
122+
end
123+
end
124+
113125
local function device_added(driver, device)
114126
supported_thermostat_modes_handler(driver, device, nil)
115127
device:emit_event(capabilities.thermostatHeatingSetpoint.heatingSetpoint({value = 21.0, unit = "C"}))
116128
device:emit_event(capabilities.temperatureMeasurement.temperature({value = 27.0, unit = "C"}))
117129
device:emit_event(capabilities.thermostatMode.thermostatMode.manual())
118-
device:emit_event(capabilities.valve.valve.open())
119-
device:emit_component_event(device.profile.components.ChildLock, capabilities.lock.lock.unlocked())
120130
device:emit_event(capabilities.hardwareFault.hardwareFault.clear())
121131
device:emit_event(valveCalibration.calibrationState.calibrationPending())
122132
device:emit_event(invisibleCapabilities.invisibleCapabilities({""}))
123133
device:emit_event(capabilities.battery.battery(100))
134+
emit_event_if_latest_state_missing(device, "main", capabilities.valve, capabilities.valve.valve.NAME, capabilities.valve.valve.open())
135+
emit_component_event_if_latest_state_missing(device, device.profile.components.ChildLock, capabilities.lock, capabilities.lock.lock.NAME, capabilities.lock.lock.unlocked())
124136
end
125137

126138
local function thermostat_alarm_status_handler(driver, device, value, zb_rx)

drivers/SmartThings/zigbee-thermostat/src/test/test_aqara_thermostat.lua

Lines changed: 74 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -73,46 +73,8 @@ end
7373

7474
test.set_test_init_function(test_init)
7575

76-
-- test.register_coroutine_test(
77-
-- "Handle added lifecycle",
78-
-- function()
79-
-- test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" })
80-
-- test.socket.capability:__expect_send(
81-
-- mock_device:generate_test_message("main",
82-
-- capabilities.thermostatMode.supportedThermostatModes({
83-
-- capabilities.thermostatMode.thermostatMode.manual.NAME,
84-
-- capabilities.thermostatMode.thermostatMode.antifreezing.NAME
85-
-- }, { visibility = { displayed = false } }))
86-
-- )
87-
-- test.socket.capability:__expect_send(
88-
-- mock_device:generate_test_message("main", capabilities.thermostatHeatingSetpoint.heatingSetpoint({value = 21.0, unit = "C"}))
89-
-- )
90-
-- test.socket.capability:__expect_send(
91-
-- mock_device:generate_test_message("main", capabilities.temperatureMeasurement.temperature({value = 27.0, unit = "C"}))
92-
-- )
93-
-- test.socket.capability:__expect_send(
94-
-- mock_device:generate_test_message("main", capabilities.thermostatMode.thermostatMode.manual())
95-
-- )
96-
-- test.socket.capability:__expect_send(
97-
-- mock_device:generate_test_message("main", capabilities.valve.valve.open())
98-
-- )
99-
-- test.socket.capability:__expect_send(
100-
-- mock_device:generate_test_message("ChildLock", capabilities.lock.lock.unlocked())
101-
-- )
102-
-- test.socket.capability:__expect_send(
103-
-- mock_device:generate_test_message("main", capabilities.hardwareFault.hardwareFault.clear())
104-
-- )
105-
-- test.socket.capability:__expect_send(
106-
-- mock_device:generate_test_message("main", valveCalibration.calibrationState.calibrationPending())
107-
-- )
108-
-- test.socket.capability:__expect_send(
109-
-- mock_device:generate_test_message("main", invisibleCapabilities.invisibleCapabilities({""}))
110-
-- )
111-
-- test.socket.capability:__expect_send(
112-
-- mock_device:generate_test_message("main", capabilities.battery.battery(100))
113-
-- )
114-
-- end
115-
-- )
76+
77+
11678

11779

11880
test.register_coroutine_test(
@@ -312,4 +274,76 @@ test.register_coroutine_test(
312274
end
313275
)
314276
--]]
277+
test.register_coroutine_test(
278+
"Handle added lifecycle",
279+
function()
280+
-- The initial valve and lock event should be send during the device's first time onboarding
281+
test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" })
282+
test.socket.capability:__expect_send(
283+
mock_device:generate_test_message("main",
284+
capabilities.thermostatMode.supportedThermostatModes({
285+
capabilities.thermostatMode.thermostatMode.manual.NAME,
286+
capabilities.thermostatMode.thermostatMode.antifreezing.NAME
287+
}, { visibility = { displayed = false } }))
288+
)
289+
test.socket.capability:__expect_send(
290+
mock_device:generate_test_message("main", capabilities.thermostatHeatingSetpoint.heatingSetpoint({value = 21.0, unit = "C"}))
291+
)
292+
test.socket.capability:__expect_send(
293+
mock_device:generate_test_message("main", capabilities.temperatureMeasurement.temperature({value = 27.0, unit = "C"}))
294+
)
295+
test.socket.capability:__expect_send(
296+
mock_device:generate_test_message("main", capabilities.thermostatMode.thermostatMode.manual())
297+
)
298+
test.socket.capability:__expect_send(
299+
mock_device:generate_test_message("main", capabilities.hardwareFault.hardwareFault.clear())
300+
)
301+
test.socket.capability:__expect_send(
302+
mock_device:generate_test_message("main", valveCalibration.calibrationState.calibrationPending())
303+
)
304+
test.socket.capability:__expect_send(
305+
mock_device:generate_test_message("main", invisibleCapabilities.invisibleCapabilities({""}))
306+
)
307+
test.socket.capability:__expect_send(
308+
mock_device:generate_test_message("main", capabilities.battery.battery(100))
309+
)
310+
test.socket.capability:__expect_send(
311+
mock_device:generate_test_message("main", capabilities.valve.valve.open())
312+
)
313+
test.socket.capability:__expect_send(
314+
mock_device:generate_test_message("ChildLock", capabilities.lock.lock.unlocked())
315+
)
316+
-- Avoid sending the initial open and lock event after driver switch-over, as the switch-over event itself re-triggers the added lifecycle.
317+
test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" })
318+
test.socket.capability:__expect_send(
319+
mock_device:generate_test_message("main",
320+
capabilities.thermostatMode.supportedThermostatModes({
321+
capabilities.thermostatMode.thermostatMode.manual.NAME,
322+
capabilities.thermostatMode.thermostatMode.antifreezing.NAME
323+
}, { visibility = { displayed = false } }))
324+
)
325+
test.socket.capability:__expect_send(
326+
mock_device:generate_test_message("main", capabilities.thermostatHeatingSetpoint.heatingSetpoint({value = 21.0, unit = "C"}))
327+
)
328+
test.socket.capability:__expect_send(
329+
mock_device:generate_test_message("main", capabilities.temperatureMeasurement.temperature({value = 27.0, unit = "C"}))
330+
)
331+
test.socket.capability:__expect_send(
332+
mock_device:generate_test_message("main", capabilities.thermostatMode.thermostatMode.manual())
333+
)
334+
test.socket.capability:__expect_send(
335+
mock_device:generate_test_message("main", capabilities.hardwareFault.hardwareFault.clear())
336+
)
337+
test.socket.capability:__expect_send(
338+
mock_device:generate_test_message("main", valveCalibration.calibrationState.calibrationPending())
339+
)
340+
test.socket.capability:__expect_send(
341+
mock_device:generate_test_message("main", invisibleCapabilities.invisibleCapabilities({""}))
342+
)
343+
test.socket.capability:__expect_send(
344+
mock_device:generate_test_message("main", capabilities.battery.battery(100))
345+
)
346+
end
347+
)
348+
315349
test.run_registered_tests()

0 commit comments

Comments
 (0)