Skip to content

Commit 9daef3c

Browse files
committed
re-profile device if a matter_version update occurs
1 parent 9b2d2bf commit 9daef3c

14 files changed

+128
-73
lines changed

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

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ function SwitchLifecycleHandlers.device_added(driver, device)
3636
-- refresh child devices to get an initial attribute state for OnOff in case child device
3737
-- was created after the initial subscription report
3838
if device.network_type == device_lib.NETWORK_TYPE_CHILD then
39+
print("???1")
3940
device:send(clusters.OnOff.attributes.OnOff:read(device))
4041
elseif device.network_type == device_lib.NETWORK_TYPE_MATTER then
42+
print("???2")
4143
switch_utils.handle_electrical_sensor_info(device)
4244
end
4345

@@ -60,16 +62,21 @@ end
6062

6163
function SwitchLifecycleHandlers.info_changed(driver, device, event, args)
6264
if device.profile.id ~= args.old_st_store.profile.id then
63-
device:subscribe()
64-
local button_eps = device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH})
65-
if #button_eps > 0 and device.network_type == device_lib.NETWORK_TYPE_MATTER then
66-
button_cfg.configure_buttons(device)
65+
if device.network_type == device_lib.NETWORK_TYPE_MATTER then
66+
device:subscribe()
67+
button_cfg.configure_buttons(device,
68+
device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH})
69+
)
70+
elseif device.network_type == device_lib.NETWORK_TYPE_CHILD then
71+
switch_utils.update_subscriptions(device:get_parent_device()) -- parent device required to scan through EPs and update subscriptions
6772
end
6873
end
69-
end
7074

71-
function SwitchLifecycleHandlers.device_removed(driver, device)
72-
device.log.info("device removed")
75+
if device.network_type == device_lib.NETWORK_TYPE_MATTER and not switch_utils.detect_bridge(device) then
76+
if device.matter_version.software ~= args.old_st_store.matter_version.software then
77+
device_cfg.match_profile(driver, device)
78+
end
79+
end
7380
end
7481

7582
function SwitchLifecycleHandlers.device_init(driver, device)
@@ -80,26 +87,7 @@ function SwitchLifecycleHandlers.device_init(driver, device)
8087
if device:get_field(fields.IS_PARENT_CHILD_DEVICE) then
8188
device:set_find_child(switch_utils.find_child)
8289
end
83-
local default_endpoint_id = switch_utils.find_default_endpoint(device)
84-
-- ensure subscription to all endpoint attributes- including those mapped to child devices
85-
for _, ep in ipairs(device.endpoints) do
86-
if ep.endpoint_id ~= default_endpoint_id then
87-
local id = 0
88-
for _, dt in ipairs(ep.device_types) do
89-
id = math.max(id, dt.device_type_id)
90-
end
91-
for _, attr in pairs(fields.device_type_attribute_map[id] or {}) do
92-
if id == fields.DEVICE_TYPE_ID.GENERIC_SWITCH and
93-
attr ~= clusters.PowerSource.attributes.BatPercentRemaining and
94-
attr ~= clusters.PowerSource.attributes.BatChargeLevel then
95-
device:add_subscribed_event(attr)
96-
else
97-
device:add_subscribed_attribute(attr)
98-
end
99-
end
100-
end
101-
end
102-
device:subscribe()
90+
switch_utils.update_subscriptions(device)
10391

10492
-- device energy reporting must be handled cumulatively, periodically, or by both simulatanously.
10593
-- To ensure a single source of truth, we only handle a device's periodic reporting if cumulative reporting is not supported.
@@ -110,6 +98,10 @@ function SwitchLifecycleHandlers.device_init(driver, device)
11098
end
11199
end
112100

101+
function SwitchLifecycleHandlers.device_removed(driver, device)
102+
device.log.info("device removed")
103+
end
104+
113105
local matter_driver_template = {
114106
lifecycle_handlers = {
115107
added = SwitchLifecycleHandlers.device_added,

drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ function CameraDeviceConfiguration.match_profile(device, status_light_enabled_pr
120120
if #doorbell_endpoints > 0 then
121121
table.insert(doorbell_component_capabilities, capabilities.button.ID)
122122
CameraDeviceConfiguration.update_doorbell_component_map(device, doorbell_endpoints[1])
123-
button_cfg.configure_buttons(device)
123+
button_cfg.configure_buttons(device, device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH}))
124124
end
125125
if status_light_enabled_present then
126126
table.insert(status_led_component_capabilities, capabilities.switch.ID)

drivers/SmartThings/matter-switch/src/sub_drivers/camera/init.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ function CameraLifecycleHandlers.info_changed(driver, device, event, args)
4343
if camera_utils.profile_changed(device.profile.components, args.old_st_store.profile.components) then
4444
camera_cfg.initialize_camera_capabilities(device)
4545
if #switch_utils.get_endpoints_by_device_type(device, fields.DEVICE_TYPE_ID.DOORBELL) > 0 then
46-
button_cfg.configure_buttons(device)
46+
button_cfg.configure_buttons(device, device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH}))
4747
end
4848
device:subscribe()
4949
end

drivers/SmartThings/matter-switch/src/switch_utils/device_configuration.lua

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ function SwitchDeviceConfiguration.assign_profile_for_onoff_ep(device, server_on
4343
return generic_profile or "switch-binary"
4444
end
4545

46-
function SwitchDeviceConfiguration.create_child_devices(driver, device, server_onoff_ep_ids, default_endpoint_id)
46+
function SwitchDeviceConfiguration.create_or_update_child_devices(driver, device, server_onoff_ep_ids, default_endpoint_id)
4747
if #server_onoff_ep_ids == 1 and server_onoff_ep_ids[1] == default_endpoint_id then -- no children will be created
4848
return
4949
end
@@ -53,16 +53,21 @@ function SwitchDeviceConfiguration.create_child_devices(driver, device, server_o
5353
if ep_id ~= default_endpoint_id then -- don't create a child device that maps to the main endpoint
5454
local label_and_name = string.format("%s %d", device.label, device_num)
5555
local child_profile = SwitchDeviceConfiguration.assign_profile_for_onoff_ep(device, ep_id, true)
56-
driver:try_create_device(
57-
{
56+
local existing_child_device = device:get_field(fields.IS_PARENT_CHILD_DEVICE) and switch_utils.find_child(device, ep_id)
57+
if not existing_child_device then
58+
driver:try_create_device({
5859
type = "EDGE_CHILD",
5960
label = label_and_name,
6061
profile = child_profile,
6162
parent_device_id = device.id,
6263
parent_assigned_child_key = string.format("%d", ep_id),
6364
vendor_provided_label = label_and_name
64-
}
65-
)
65+
})
66+
else
67+
existing_child_device:try_update_metadata({
68+
profile = child_profile
69+
})
70+
end
6671
end
6772
end
6873

@@ -121,13 +126,12 @@ function ButtonDeviceConfiguration.update_button_component_map(device, default_e
121126
end
122127

123128

124-
function ButtonDeviceConfiguration.configure_buttons(device)
125-
local ms_eps = device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH})
129+
function ButtonDeviceConfiguration.configure_buttons(device, momentary_switch_ep_ids)
126130
local msr_eps = device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH_RELEASE})
127131
local msl_eps = device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH_LONG_PRESS})
128132
local msm_eps = device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH_MULTI_PRESS})
129133

130-
for _, ep in ipairs(ms_eps) do
134+
for _, ep in ipairs(momentary_switch_ep_ids or {}) do
131135
if device.profile.components[switch_utils.endpoint_to_component(device, ep)] then
132136
device.log.info_with({hub_logs=true}, string.format("Configuring Supported Values for generic switch endpoint %d", ep))
133137
local supportedButtonValues_event
@@ -184,7 +188,7 @@ function DeviceConfiguration.match_profile(driver, device)
184188

185189
local server_onoff_ep_ids = device:get_endpoints(clusters.OnOff.ID) -- get_endpoints defaults to return EPs supporting SERVER or BOTH
186190
if #server_onoff_ep_ids > 0 then
187-
SwitchDeviceConfiguration.create_child_devices(driver, device, server_onoff_ep_ids, default_endpoint_id)
191+
SwitchDeviceConfiguration.create_or_update_child_devices(driver, device, server_onoff_ep_ids, default_endpoint_id)
188192
end
189193

190194
if switch_utils.tbl_contains(server_onoff_ep_ids, default_endpoint_id) then
@@ -206,12 +210,12 @@ function DeviceConfiguration.match_profile(driver, device)
206210
end
207211

208212
-- initialize the main device card with buttons if applicable
209-
local button_eps = device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH})
210-
if switch_utils.tbl_contains(fields.STATIC_BUTTON_PROFILE_SUPPORTED, #button_eps) then
211-
ButtonDeviceConfiguration.update_button_profile(device, default_endpoint_id, #button_eps)
213+
local momemtary_switch_ep_ids = device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH})
214+
if switch_utils.tbl_contains(fields.STATIC_BUTTON_PROFILE_SUPPORTED, #momemtary_switch_ep_ids) then
215+
ButtonDeviceConfiguration.update_button_profile(device, default_endpoint_id, #momemtary_switch_ep_ids)
212216
-- All button endpoints found will be added as additional components in the profile containing the default_endpoint_id.
213-
ButtonDeviceConfiguration.update_button_component_map(device, default_endpoint_id, button_eps)
214-
ButtonDeviceConfiguration.configure_buttons(device)
217+
ButtonDeviceConfiguration.update_button_component_map(device, default_endpoint_id, momemtary_switch_ep_ids)
218+
ButtonDeviceConfiguration.configure_buttons(device, momemtary_switch_ep_ids)
215219
return
216220
end
217221

drivers/SmartThings/matter-switch/src/switch_utils/utils.lua

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ function utils.mired_to_kelvin(value, minOrMax)
7676
end
7777

7878
function utils.get_product_override_field(device, override_key)
79-
if fields.vendor_overrides[device.manufacturer_info.vendor_id]
79+
if device.manufacturer_info
80+
and fields.vendor_overrides[device.manufacturer_info.vendor_id]
8081
and fields.vendor_overrides[device.manufacturer_info.vendor_id][device.manufacturer_info.product_id]
8182
then
8283
return fields.vendor_overrides[device.manufacturer_info.vendor_id][device.manufacturer_info.product_id][override_key]
@@ -416,4 +417,27 @@ function utils.lazy_load(sub_driver_name)
416417
end
417418
end
418419

420+
function utils.update_subscriptions(device)
421+
local default_endpoint_id = utils.find_default_endpoint(device)
422+
-- ensure subscription to all endpoint attributes- including those mapped to child devices
423+
for idx, ep in ipairs(device.endpoints) do
424+
if ep.endpoint_id ~= default_endpoint_id then
425+
local id = 0
426+
for _, dt in ipairs(ep.device_types) do
427+
id = math.max(id, dt.device_type_id)
428+
end
429+
for _, attr in pairs(fields.device_type_attribute_map[id] or {}) do
430+
if id == fields.DEVICE_TYPE_ID.GENERIC_SWITCH and
431+
attr ~= clusters.PowerSource.attributes.BatPercentRemaining and
432+
attr ~= clusters.PowerSource.attributes.BatChargeLevel then
433+
device:add_subscribed_event(attr)
434+
else
435+
device:add_subscribed_attribute(attr)
436+
end
437+
end
438+
end
439+
end
440+
device:subscribe()
441+
end
442+
419443
return utils

drivers/SmartThings/matter-switch/src/test/test_aqara_climate_sensor_w100.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ local button_attr = capabilities.button.button
1414
local aqara_mock_device = test.mock_device.build_test_matter_device({
1515
profile = t_utils.get_profile_definition("3-button-battery-temperature-humidity.yml"),
1616
manufacturer_info = {vendor_id = 0x115F, product_id = 0x2004, product_name = "Aqara Climate Sensor W100"},
17+
matter_version = {hardware = 1, software = 1},
1718
label = "Climate Sensor W100",
1819
device_id = "00000000-1111-2222-3333-000000000001",
1920
endpoints = {

drivers/SmartThings/matter-switch/src/test/test_aqara_light_switch_h2.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ local aqara_child2_ep = 2
2323
local aqara_mock_device = test.mock_device.build_test_matter_device({
2424
profile = t_utils.get_profile_definition("4-button.yml"),
2525
manufacturer_info = {vendor_id = 0x115F, product_id = 0x1009, product_name = "Aqara Light Switch H2"},
26+
matter_version = {hardware = 1, software = 1},
2627
label = "Aqara Light Switch",
2728
device_id = "00000000-1111-2222-3333-000000000001",
2829
endpoints = {

drivers/SmartThings/matter-switch/src/test/test_matter_button.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ local uint32 = require "st.matter.data_types.Uint32"
1515
local mock_device = test.mock_device.build_test_matter_device({
1616
profile = t_utils.get_profile_definition("button-battery.yml"),
1717
manufacturer_info = {vendor_id = 0x0000, product_id = 0x0000},
18+
matter_version = {hardware = 1, software = 1},
1819
endpoints = {
1920
{
2021
endpoint_id = 0,

drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ local CAMERA_EP, FLOODLIGHT_EP, CHIME_EP, DOORBELL_EP = 1, 2, 3, 4
1313
local mock_device = test.mock_device.build_test_matter_device({
1414
profile = t_utils.get_profile_definition("camera.yml"),
1515
manufacturer_info = {vendor_id = 0x0000, product_id = 0x0000},
16+
matter_version = {hardware = 1, software = 1},
1617
endpoints = {
1718
{
1819
endpoint_id = 0,

drivers/SmartThings/matter-switch/src/test/test_matter_multi_button.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ local mock_device = test.mock_device.build_test_matter_device(
1515
{
1616
profile = t_utils.get_profile_definition("5-button-battery.yml"),
1717
manufacturer_info = {vendor_id = 0x0000, product_id = 0x0000},
18+
matter_version = {hardware = 1, sofrware = 1},
1819
endpoints = {
1920
{
2021
endpoint_id = 0,
@@ -92,8 +93,7 @@ local mock_device = test.mock_device.build_test_matter_device(
9293
}
9394
},
9495
},
95-
}
96-
)
96+
})
9797

9898
-- add device for each mock device
9999
local CLUSTER_SUBSCRIBE_LIST ={

0 commit comments

Comments
 (0)