Skip to content

Commit 55a009f

Browse files
authored
Merge pull request #3020 from SmartThingsCommunity/main
Beta release 6/10
2 parents 2feb8bc + 42a6a23 commit 55a009f

9 files changed

Lines changed: 132 additions & 34 deletions

File tree

drivers/SmartThings/matter-lock/src/init.lua

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,13 @@ local function lock_state_handler(driver, device, ib, response)
8383
}
8484

8585
if ib.data.value ~= nil then
86-
device:emit_event(LOCK_STATE[ib.data.value])
86+
local event = LOCK_STATE[ib.data.value]
87+
if event ~= nil then
88+
device:emit_event(event)
89+
else
90+
device.log.warn(string.format("Received unknown lock state value (%s), emitting unknown", ib.data.value))
91+
device:emit_event(attr.unknown())
92+
end
8793
else
8894
device:emit_event(LOCK_STATE[LockState.NOT_FULLY_LOCKED])
8995
end

drivers/SmartThings/matter-lock/src/new-matter-lock/fingerprints.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ local NEW_MATTER_LOCK_PRODUCTS = {
77
{0x115f, 0x2807}, -- AQARA, U200 Lite
88
{0x115f, 0x2804}, -- AQARA, U400
99
{0x115f, 0x286A}, -- AQARA, U200 US
10+
{0x115f, 0x2805}, -- Aqara Smart Lock J200 Set
11+
{0x115f, 0x280e}, -- AQARA Smart Gate Lock U500
12+
{0x115f, 0x280f}, -- AQARA Smart Rim Lock U500
13+
{0x115f, 0x2810}, -- AQARA Smart Glass Door Lock U500
1014
{0x147F, 0x0001}, -- U-tec
1115
{0x147F, 0x0007}, -- ULTRALOQ Bolt Pro Smart Matter Door Lock
1216
{0x147F, 0x0008}, -- Ultraloq, Bolt Smart Matter Door Lock

drivers/SmartThings/matter-lock/src/test/test_matter_lock.lua

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,29 @@ test.register_message_test(
191191
}
192192
)
193193

194+
test.register_message_test(
195+
"Handle unknown LockState value from Matter device.", {
196+
{
197+
channel = "matter",
198+
direction = "receive",
199+
message = {
200+
mock_device.id,
201+
clusters.DoorLock.attributes.LockState:build_test_report_data(
202+
mock_device, 10, 0xFF
203+
),
204+
},
205+
},
206+
{
207+
channel = "capability",
208+
direction = "send",
209+
message = mock_device:generate_test_message("main", capabilities.lock.lock.unknown()),
210+
},
211+
},
212+
{
213+
min_api_version = 17
214+
}
215+
)
216+
194217
test.register_message_test(
195218
"Handle received BatPercentRemaining from device.", {
196219
{

drivers/SmartThings/matter-switch/fingerprints.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,11 @@ matterManufacturer:
542542
vendorId: 0x1339
543543
productId: 0x0016
544544
deviceProfileName: light-color-level-2000K-7000K
545+
- id: "4921/86"
546+
deviceLabel: Cync Smart Shop Light
547+
vendorId: 0x1339
548+
productId: 0x0056
549+
deviceProfileName: light-color-level
545550
#Govee
546551
- id: "4999/24740"
547552
deviceLabel: Govee Square Ceiling Light (12 inch)
@@ -4149,6 +4154,11 @@ matterManufacturer:
41494154
vendorId: 0x1392
41504155
productId: 0x010D
41514156
deviceProfileName: plug-binary
4157+
- id: "20496/610"
4158+
deviceLabel: Mini Smart Wi-Fi Plug Energy Monitoring Matter
4159+
vendorId: 0x5010
4160+
productId: 0x0262
4161+
deviceProfileName: plug-power-energy-powerConsumption
41524162

41534163

41544164
matterGeneric:

drivers/SmartThings/samsung-audio/src/command.lua

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,19 @@ local function is_empty(t)
3434
return not t or (type(t) == "table" and #t == 0)
3535
end
3636

37+
local function get_uic_response(ret, command_name)
38+
local root = ret and ret.handler_res and ret.handler_res.root
39+
local uic = root and root.UIC
40+
local response = uic and uic.response
41+
42+
if not uic then
43+
log.warn(string.format("Missing UIC data in %s response", tostring(command_name)))
44+
return nil, nil
45+
end
46+
47+
return uic, response
48+
end
49+
3750
local function tr(s,mappings)
3851
return string.gsub(s,
3952
"(.)",
@@ -94,8 +107,9 @@ function Command.volume(ip)
94107
if ip then
95108
local url = format_url(ip, "/UIC?cmd=<name>GetVolume</name>")
96109
local ret = handle_http_request(ip, url)
97-
if ret then
98-
response_map = { volume = ret.handler_res.root.UIC.response.volume, }
110+
local _, response = get_uic_response(ret, "GetVolume")
111+
if response and response.volume ~= nil then
112+
response_map = { volume = response.volume, }
99113
end
100114
end
101115
return response_map
@@ -114,8 +128,9 @@ function Command.set_volume(ip, level)
114128
local encoded_str_vol = "/UIC?cmd=%3Cpwron%3Eon%3C/pwron%3E%3Cname%3ESetVolume%3C/name%3E%3Cp%20type=%22dec%22%20name=%22volume%22%20val=%22" .. level .. "%22%3E%3C/p%3E"
115129
local url = format_url(ip, encoded_str_vol)
116130
local ret = handle_http_request(ip, url)
117-
if ret then
118-
response_map = { volume = ret.handler_res.root.UIC.response.volume, }
131+
local _, response = get_uic_response(ret, "SetVolume")
132+
if response and response.volume ~= nil then
133+
response_map = { volume = response.volume, }
119134
end
120135
end
121136
return response_map
@@ -326,8 +341,9 @@ function Command.getMute(ip)
326341
if ip then
327342
local url = format_url(ip, "/UIC?cmd=<name>GetMute</name>")
328343
local ret = handle_http_request(ip, url)
329-
if ret then
330-
response_map = { muted = ret.handler_res.root.UIC.response.mute,}
344+
local _, response = get_uic_response(ret, "GetMute")
345+
if response and response.mute ~= nil then
346+
response_map = { muted = response.mute,}
331347
end
332348
end
333349
return response_map
@@ -342,8 +358,9 @@ function Command.getPlayStatus(ip)
342358
if ip then
343359
local url = format_url(ip, "/UIC?cmd=<name>GetPlayStatus</name>")
344360
local ret = handle_http_request(ip, url)
345-
if ret then
346-
response_map = { playstatus = ret.handler_res.root.UIC.response.playstatus,}
361+
local _, response = get_uic_response(ret, "GetPlayStatus")
362+
if response and response.playstatus ~= nil then
363+
response_map = { playstatus = response.playstatus,}
347364
end
348365
end
349366
return response_map

drivers/SmartThings/samsung-audio/src/handlers.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ end
137137
function CapabilityHandlers.handle_audio_notification(driver, device, cmd)
138138
local ip = device:get_field("ip")
139139
local mute_status = command.getMute(ip)
140-
if mute_status.muted ~= "off" then
140+
if mute_status and mute_status.muted ~= nil and mute_status.muted ~= "off" then
141141
--unmute before playig notification
142142
command.unmute(ip)
143143
end

drivers/SmartThings/samsung-audio/src/init.lua

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,23 @@ local function emit_refresh_data_to_server(driver, device, cmd)
9494

9595
-- get volume
9696
local vol = command.volume(device:get_field("ip"))
97-
device:emit_event(capabilities.audioVolume.volume(tonumber(vol.volume)))
97+
local current_volume = vol and tonumber(vol.volume)
98+
if current_volume ~= nil then
99+
device:emit_event(capabilities.audioVolume.volume(current_volume))
100+
else
101+
log.warn("Unable to read speaker volume from refresh response")
102+
end
98103

99104
-- get mute status
100105
local muteStatus = command.getMute(device:get_field("ip"))
101-
if muteStatus.muted ~= "off" then
102-
device:emit_event(capabilities.audioMute.mute.muted())
106+
if muteStatus and muteStatus.muted ~= nil then
107+
if muteStatus.muted ~= "off" then
108+
device:emit_event(capabilities.audioMute.mute.muted())
109+
else
110+
device:emit_event(capabilities.audioMute.mute.unmuted())
111+
end
103112
else
104-
device:emit_event(capabilities.audioMute.mute.unmuted())
113+
log.warn("Unable to read speaker mute state from refresh response")
105114
end
106115
end
107116

drivers/SmartThings/zigbee-switch/src/zll-polling/init.lua

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,63 @@ local device_lib = require "st.device"
55
local clusters = require "st.zigbee.zcl.clusters"
66
local configurationMap = require "configurations"
77

8-
local function set_up_zll_polling(driver, device)
9-
local INFREQUENT_POLL_COUNTER = "_infrequent_poll_counter"
10-
local function poll()
11-
local infrequent_counter = device:get_field(INFREQUENT_POLL_COUNTER) or 1
12-
if infrequent_counter == 12 then
13-
-- do a full refresh once an hour
14-
device:refresh()
15-
infrequent_counter = 0
16-
else
17-
-- Read On/Off every poll
18-
for _, ep in pairs(device.zigbee_endpoints) do
19-
if device:supports_server_cluster(clusters.OnOff.ID, ep.id) then
20-
device:send(clusters.OnOff.attributes.OnOff:read(device):to_endpoint(ep.id))
21-
end
8+
local INFREQUENT_POLL_COUNTER = "_infrequent_poll_counter"
9+
local ZLL_POLL_TIMER = "_zll_poll_timer"
10+
11+
local function do_zll_poll(device)
12+
if device == nil or type(device.get_field) ~= "function" then
13+
return
14+
end
15+
16+
local infrequent_counter = device:get_field(INFREQUENT_POLL_COUNTER) or 1
17+
if infrequent_counter == 12 then
18+
-- do a full refresh once an hour
19+
device:refresh()
20+
infrequent_counter = 0
21+
else
22+
-- Read On/Off every poll
23+
for _, ep in pairs(device.zigbee_endpoints) do
24+
if device:supports_server_cluster(clusters.OnOff.ID, ep.id) then
25+
device:send(clusters.OnOff.attributes.OnOff:read(device):to_endpoint(ep.id))
2226
end
23-
infrequent_counter = infrequent_counter + 1
2427
end
25-
device:set_field(INFREQUENT_POLL_COUNTER, infrequent_counter)
28+
infrequent_counter = infrequent_counter + 1
2629
end
30+
device:set_field(INFREQUENT_POLL_COUNTER, infrequent_counter)
31+
end
2732

33+
local function set_up_zll_polling(driver, device)
2834
-- only set this up for non-child devices
29-
if device.network_type == device_lib.NETWORK_TYPE_ZIGBEE then
30-
device.thread:call_on_schedule(5 * 60, poll, "zll_polling")
35+
if device.network_type ~= device_lib.NETWORK_TYPE_ZIGBEE then
36+
return
37+
end
38+
39+
-- should never happen, but defensive check
40+
local existing_timer = device:get_field(ZLL_POLL_TIMER)
41+
if existing_timer ~= nil then
42+
device.thread:cancel_timer(existing_timer)
43+
end
44+
45+
local timer = device.thread:call_on_schedule(5 * 60, function()
46+
do_zll_poll(device)
47+
end, "zll_polling")
48+
49+
device:set_field(ZLL_POLL_TIMER, timer)
50+
end
51+
52+
local function remove_zll_polling(driver, device)
53+
local existing_timer = device:get_field(ZLL_POLL_TIMER)
54+
if existing_timer ~= nil then
55+
device.thread:cancel_timer(existing_timer)
56+
device:set_field(ZLL_POLL_TIMER, nil)
3157
end
3258
end
3359

3460
local ZLL_polling = {
3561
NAME = "ZLL Polling",
3662
lifecycle_handlers = {
37-
init = configurationMap.reconfig_wrapper(set_up_zll_polling)
63+
init = configurationMap.reconfig_wrapper(set_up_zll_polling),
64+
removed = remove_zll_polling
3865
},
3966
can_handle = require("zll-polling.can_handle"),
4067
}

drivers/SmartThings/zigbee-valve/src/sinope/init.lua

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ local PowerConfiguration = clusters.PowerConfiguration
1212
local function device_init(driver, device)
1313
battery_defaults.use_battery_voltage_handling(device)
1414
-- according to the DTH, this attribute cannot be configured for reporting
15-
device.thread:call_on_schedule(900, function() device:send(PowerConfiguration.attributes.BatteryVoltage:read()) end)
15+
device.thread:call_on_schedule(900, function()
16+
device:send(PowerConfiguration.attributes.BatteryVoltage:read(device))
17+
end)
1618
end
1719

1820
local function battery_voltage_handler(driver, device, command)

0 commit comments

Comments
 (0)