From 7f6eb1c7ff7c1c85bc9d920b65f2ca2481ba0844 Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Tue, 18 Nov 2025 12:26:11 -0600 Subject: [PATCH 1/4] add more reliability to device type checking --- .../src/switch_utils/device_configuration.lua | 2 +- .../matter-switch/src/switch_utils/fields.lua | 1 + .../matter-switch/src/switch_utils/utils.lua | 34 ++++++++++++------- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/SmartThings/matter-switch/src/switch_utils/device_configuration.lua b/drivers/SmartThings/matter-switch/src/switch_utils/device_configuration.lua index adc0da500e..eebe734fcd 100644 --- a/drivers/SmartThings/matter-switch/src/switch_utils/device_configuration.lua +++ b/drivers/SmartThings/matter-switch/src/switch_utils/device_configuration.lua @@ -25,7 +25,7 @@ function SwitchDeviceConfiguration.assign_profile_for_onoff_ep(device, server_on -- per spec, the Switch device types support OnOff as CLIENT, though some vendors break spec and support it as SERVER. local primary_dt_id = switch_utils.find_max_subset_device_type(ep_info, fields.DEVICE_TYPE_ID.LIGHT) or switch_utils.find_max_subset_device_type(ep_info, fields.DEVICE_TYPE_ID.SWITCH) - or ep_info.device_types[1] and ep_info.device_types[1].device_type_id + or switch_utils.find_primary_device_type(ep_info) local generic_profile = fields.device_type_profile_map[primary_dt_id] diff --git a/drivers/SmartThings/matter-switch/src/switch_utils/fields.lua b/drivers/SmartThings/matter-switch/src/switch_utils/fields.lua index c350a7adaf..3a0bdc9fdb 100644 --- a/drivers/SmartThings/matter-switch/src/switch_utils/fields.lua +++ b/drivers/SmartThings/matter-switch/src/switch_utils/fields.lua @@ -36,6 +36,7 @@ SwitchFields.CURRENT_HUESAT_ATTR_MAX = 254 SwitchFields.DEVICE_TYPE_ID = { AGGREGATOR = 0x000E, + BRIDGED_NODE = 0x0013, CAMERA = 0x0142, CHIME = 0x0146, DIMMABLE_PLUG_IN_UNIT = 0x010B, diff --git a/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua b/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua index 718e186dcf..b6de70806f 100644 --- a/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua +++ b/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua @@ -93,23 +93,31 @@ function utils.device_type_supports_button_switch_combination(device, endpoint_i return utils.tbl_contains(dimmable_eps, endpoint_id) end --- Some devices report multiple device types which are a subset of --- a superset device type (Ex. Dimmable Light is a superset of On/Off Light). --- We should map to the largest superset device type supported. --- This can be done by matching to the device type with the highest ID +--- Some devices report multiple device types which are a subset of +--- a superset device type (Ex. Dimmable Light is a superset of On/Off Light). +--- We should map to the largest superset device type supported. +--- This can be done by matching to the device type with the highest ID function utils.find_max_subset_device_type(ep, device_type_set) if ep.endpoint_id == 0 then return end -- EP-scoped device types not permitted on Root Node - local primary_dt_id = ep.device_types[1] and ep.device_types[1].device_type_id - if utils.tbl_contains(device_type_set, primary_dt_id) then - for _, dt in ipairs(ep.device_types) do - -- only device types in the subset should be considered. - if utils.tbl_contains(device_type_set, dt.device_type_id) then - primary_dt_id = math.max(primary_dt_id, dt.device_type_id) - end + local primary_dt_id = -1 + for _, dt in ipairs(ep.device_types) do + -- only device types in the subset should be considered. + if utils.tbl_contains(device_type_set, dt.device_type_id) then + primary_dt_id = math.max(primary_dt_id, dt.device_type_id) + end + end + return (primary_dt_id > 0) and primary_dt_id or nil +end + +--- Lights and Switches are Device Types that have Superset-style functionality +--- For all other device types, this function should be used to identify the primary device type +function utils.find_primary_device_type(ep_info) + for _, dt in ipairs(ep_info.device_types) do + if dt.device_type_id ~= fields.DEVICE_TYPE_ID.BRIDGED_NODE then + -- if this is not a bridged node, return the first device type seen + return dt.device_type_id end - return primary_dt_id end - return nil end --- find_default_endpoint is a helper function to handle situations where From b11bf3f534b98b216464617aaeb215e58f970b65 Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Tue, 18 Nov 2025 13:09:02 -0600 Subject: [PATCH 2/4] update superset comment --- .../SmartThings/matter-switch/src/switch_utils/utils.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua b/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua index b6de70806f..4ad135784a 100644 --- a/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua +++ b/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua @@ -93,9 +93,11 @@ function utils.device_type_supports_button_switch_combination(device, endpoint_i return utils.tbl_contains(dimmable_eps, endpoint_id) end ---- Some devices report multiple device types which are a subset of ---- a superset device type (Ex. Dimmable Light is a superset of On/Off Light). ---- We should map to the largest superset device type supported. +--- Per spec, "A superset device type is a device type that is functionally similar to a +--- subset device type and has an overlap in its cluster requirements with a subset device type." +--- Per spec, "An endpoint implementing a superset device type MAY include the +--- subset device type(s) in the DeviceTypeList of the descriptor cluster of the endpoint." +--- That said, we should identify the largest superset device type supported on an endpoint. --- This can be done by matching to the device type with the highest ID function utils.find_max_subset_device_type(ep, device_type_set) if ep.endpoint_id == 0 then return end -- EP-scoped device types not permitted on Root Node From 1e4fcded7282086aad59da41ab68d54be4f050a3 Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Tue, 18 Nov 2025 15:05:48 -0600 Subject: [PATCH 3/4] update comment about superset device types again --- .../matter-switch/src/switch_utils/utils.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua b/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua index 4ad135784a..7cf5520ae7 100644 --- a/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua +++ b/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua @@ -93,12 +93,12 @@ function utils.device_type_supports_button_switch_combination(device, endpoint_i return utils.tbl_contains(dimmable_eps, endpoint_id) end ---- Per spec, "A superset device type is a device type that is functionally similar to a ---- subset device type and has an overlap in its cluster requirements with a subset device type." ---- Per spec, "An endpoint implementing a superset device type MAY include the ---- subset device type(s) in the DeviceTypeList of the descriptor cluster of the endpoint." ---- That said, we should identify the largest superset device type supported on an endpoint. +--- Some devices report multiple device types which are a subset of +--- a superset device type (Ex. Dimmable Light is a superset of On/Off Light). +--- We should map to the largest superset device type supported. --- This can be done by matching to the device type with the highest ID +--- note: that superset device types have a higher ID than their subset device types is heuristic +--- and could therefore break in the future if the spec were expanded function utils.find_max_subset_device_type(ep, device_type_set) if ep.endpoint_id == 0 then return end -- EP-scoped device types not permitted on Root Node local primary_dt_id = -1 From 98d0d611444ef1b30479fafd7f4a925343e06534 Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Wed, 19 Nov 2025 15:27:06 -0600 Subject: [PATCH 4/4] update comment --- .../matter-switch/src/switch_utils/utils.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua b/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua index 7cf5520ae7..01a9d2d971 100644 --- a/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua +++ b/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua @@ -93,12 +93,12 @@ function utils.device_type_supports_button_switch_combination(device, endpoint_i return utils.tbl_contains(dimmable_eps, endpoint_id) end ---- Some devices report multiple device types which are a subset of ---- a superset device type (Ex. Dimmable Light is a superset of On/Off Light). ---- We should map to the largest superset device type supported. +--- Some devices report multiple device types which are a subset of a superset +--- device type (Ex. Dimmable Light is a superset of On/Off Light). We should map +--- to the largest superset device type supported. --- This can be done by matching to the device type with the highest ID ---- note: that superset device types have a higher ID than their subset device types is heuristic ---- and could therefore break in the future if the spec were expanded +--- note: that superset device types have a higher ID than those of their subset +--- is heuristic and could therefore break in the future, were the spec expanded function utils.find_max_subset_device_type(ep, device_type_set) if ep.endpoint_id == 0 then return end -- EP-scoped device types not permitted on Root Node local primary_dt_id = -1