From 3bf70ac3f885591b0744c37b1000f0b5a06983d9 Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Wed, 5 Nov 2025 18:07:01 -0600 Subject: [PATCH 1/4] write to control options during device configuration --- .../SmartThings/matter-switch/src/init.lua | 1 + .../src/switch_utils/device_configuration.lua | 15 ++++++ .../matter-switch/src/switch_utils/utils.lua | 16 +++++++ .../src/test/test_matter_light_fan.lua | 2 + .../test_matter_multi_button_switch_mcd.lua | 3 ++ .../src/test/test_matter_switch.lua | 21 ++++++++- .../test/test_matter_switch_device_types.lua | 47 ++++++++++++++++++- .../test_multi_switch_parent_child_lights.lua | 41 +++++++++------- 8 files changed, 126 insertions(+), 20 deletions(-) diff --git a/drivers/SmartThings/matter-switch/src/init.lua b/drivers/SmartThings/matter-switch/src/init.lua index 2302ffc4dc..3be68c255b 100644 --- a/drivers/SmartThings/matter-switch/src/init.lua +++ b/drivers/SmartThings/matter-switch/src/init.lua @@ -40,6 +40,7 @@ end function SwitchLifecycleHandlers.do_configure(driver, device) if device.network_type == device_lib.NETWORK_TYPE_MATTER and not switch_utils.detect_bridge(device) then + switch_cfg.set_device_control_options(device) device_cfg.match_profile(driver, device) end end 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 626080b147..adc0da500e 100644 --- a/drivers/SmartThings/matter-switch/src/switch_utils/device_configuration.lua +++ b/drivers/SmartThings/matter-switch/src/switch_utils/device_configuration.lua @@ -72,6 +72,21 @@ function SwitchDeviceConfiguration.create_child_devices(driver, device, server_o device:set_find_child(switch_utils.find_child) end +-- Per the spec, these attributes are "meant to be changed only during commissioning." +function SwitchDeviceConfiguration.set_device_control_options(device) + for _, ep_info in ipairs(device.endpoints) do + -- before the Matter 1.3 lua libs update (HUB FW 54), OptionsBitmap was defined as LevelControlOptions + if switch_utils.ep_supports_cluster(ep_info, clusters.LevelControl.ID) then + device:send(clusters.LevelControl.attributes.Options:write(device, ep_info.endpoint_id, clusters.LevelControl.types.LevelControlOptions.EXECUTE_IF_OFF)) + end + -- before the Matter 1.4 lua libs update (HUB FW 56), there was no OptionsBitmap type defined + if switch_utils.ep_supports_cluster(ep_info, clusters.ColorControl.ID) then + local excute_if_off_bit = clusters.ColorControl.types.OptionsBitmap and clusters.ColorControl.types.OptionsBitmap.EXECUTE_IF_OFF or 0x0001 + device:send(clusters.ColorControl.attributes.Options:write(device, ep_info.endpoint_id, excute_if_off_bit)) + end + end +end + function ButtonDeviceConfiguration.update_button_profile(device, default_endpoint_id, num_button_eps) local profile_name = string.gsub(num_button_eps .. "-button", "1%-", "") -- remove the "1-" in a device with 1 button ep if switch_utils.device_type_supports_button_switch_combination(device, default_endpoint_id) then diff --git a/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua b/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua index 0f7ac435cb..7e6137cc6c 100644 --- a/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua +++ b/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua @@ -187,6 +187,22 @@ function utils.get_endpoint_info(device, endpoint_id) return {} end +function utils.ep_supports_cluster(ep_info, cluster_id, opts) + opts = opts or {} + local clus_has_features = function(cluster, checked_feature) + return (cluster.feature_map & checked_feature) == checked_feature + end + for _, cluster in ipairs(ep_info.clusters) do + if ((cluster.cluster_id == cluster_id) + and (opts.feature_bitmap == nil or clus_has_features(cluster, opts.feature_bitmap)) + and ((opts.cluster_type == nil and cluster.cluster_type == "SERVER" or cluster.cluster_type == "BOTH") + or (opts.cluster_type == cluster.cluster_type)) + or (cluster_id == nil)) then + return true + end + end +end + -- Fallback handler for responses that dont have their own handler function utils.matter_handler(driver, device, response_block) device.log.info(string.format("Fallback handler for %s", response_block)) diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_light_fan.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_light_fan.lua index d50d16b8fe..a35f5bda50 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_light_fan.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_light_fan.lua @@ -87,6 +87,8 @@ local function test_init() test.socket.matter:__expect_send({mock_device.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device.id, "doConfigure" }) + test.socket.matter:__expect_send({mock_device.id, clusters.LevelControl.attributes.Options:write(mock_device, mock_device_ep1, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF)}) + test.socket.matter:__expect_send({mock_device.id, clusters.ColorControl.attributes.Options:write(mock_device, mock_device_ep1, clusters.ColorControl.types.OptionsBitmap.EXECUTE_IF_OFF)}) mock_device:expect_metadata_update({ profile = "light-color-level-fan" }) mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button_switch_mcd.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button_switch_mcd.lua index ab35eff35c..0eb10ba6f7 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button_switch_mcd.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button_switch_mcd.lua @@ -226,6 +226,9 @@ local function test_init() parent_assigned_child_key = string.format("%d", mock_device_ep5) }) expect_configure_buttons() + test.socket.matter:__expect_send({mock_device.id, clusters.LevelControl.attributes.Options:write(mock_device, mock_device_ep1, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF)}) + test.socket.matter:__expect_send({mock_device.id, clusters.LevelControl.attributes.Options:write(mock_device, mock_device_ep5, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF)}) + test.socket.matter:__expect_send({mock_device.id, clusters.ColorControl.attributes.Options:write(mock_device, mock_device_ep5, clusters.ColorControl.types.OptionsBitmap.EXECUTE_IF_OFF)}) test.socket.device_lifecycle:__queue_receive({ mock_device.id, "doConfigure" }) -- simulate the profile change update taking affect and the device info changing diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_switch.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_switch.lua index ba9ae3c921..e38003ce5a 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_switch.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_switch.lua @@ -200,7 +200,7 @@ local function test_init_color_temp() subscribe_request:merge(cluster:subscribe(mock_device_color_temp)) end end - test.socket.matter:__expect_send({mock_device_color_temp.id, subscribe_request}) + test.socket.device_lifecycle:__queue_receive({ mock_device_color_temp.id, "added" }) test.socket.matter:__expect_send({mock_device_color_temp.id, subscribe_request}) @@ -208,7 +208,16 @@ local function test_init_color_temp() test.socket.matter:__expect_send({mock_device_color_temp.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device_color_temp.id, "doConfigure" }) + test.socket.matter:__expect_send({ + mock_device_color_temp.id, + clusters.LevelControl.attributes.Options:write(mock_device_color_temp, 1, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF) + }) + test.socket.matter:__expect_send({ + mock_device_color_temp.id, + clusters.ColorControl.attributes.Options:write(mock_device_color_temp, 1, clusters.ColorControl.types.OptionsBitmap.EXECUTE_IF_OFF) + }) mock_device_color_temp:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + test.socket.matter:__expect_send({mock_device_color_temp.id, subscribe_request}) end local function test_init_extended_color() @@ -221,13 +230,21 @@ local function test_init_extended_color() end test.socket.matter:__expect_send({mock_device_extended_color.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device_extended_color.id, "added" }) - test.socket.matter:__expect_send({mock_device_extended_color.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device_extended_color.id, "init" }) test.socket.matter:__expect_send({mock_device_extended_color.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device_extended_color.id, "doConfigure" }) + test.socket.matter:__expect_send({ + mock_device_extended_color.id, + clusters.LevelControl.attributes.Options:write(mock_device_extended_color, 1, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF) + }) + test.socket.matter:__expect_send({ + mock_device_extended_color.id, + clusters.ColorControl.attributes.Options:write(mock_device_extended_color, 1, clusters.ColorControl.types.OptionsBitmap.EXECUTE_IF_OFF) + }) mock_device_extended_color:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + test.socket.matter:__expect_send({mock_device_extended_color.id, subscribe_request}) end test.register_message_test( diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_switch_device_types.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_switch_device_types.lua index 560230cdc7..5a29e0b6c5 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_switch_device_types.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_switch_device_types.lua @@ -143,7 +143,7 @@ local mock_device_mounted_on_off_control = test.mock_device.build_test_matter_de endpoint_id = 7, clusters = { {cluster_id = clusters.OnOff.ID, cluster_type = "SERVER", cluster_revision = 1, feature_map = 0}, - {cluster_id = clusters.LevelControl.ID, cluster_type = "CLIENT", feature_map = 2}, + {cluster_id = clusters.LevelControl.ID, cluster_type = "SERVER", feature_map = 2}, }, device_types = { @@ -173,7 +173,7 @@ local mock_device_mounted_dimmable_load_control = test.mock_device.build_test_ma endpoint_id = 7, clusters = { {cluster_id = clusters.OnOff.ID, cluster_type = "SERVER", cluster_revision = 1, feature_map = 0}, - {cluster_id = clusters.LevelControl.ID, cluster_type = "CLIENT", feature_map = 2}, + {cluster_id = clusters.LevelControl.ID, cluster_type = "SERVER", feature_map = 2}, }, device_types = { @@ -420,6 +420,10 @@ local function test_init_parent_child_switch_types() test.socket.matter:__expect_send({mock_device_parent_child_switch_types.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device_parent_child_switch_types.id, "doConfigure" }) + test.socket.matter:__expect_send({ + mock_device_parent_child_switch_types.id, + clusters.LevelControl.attributes.Options:write(mock_device_parent_child_switch_types, 7, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF) + }) mock_device_parent_child_switch_types:expect_metadata_update({ profile = "switch-level" }) mock_device_parent_child_switch_types:expect_metadata_update({ provisioning_state = "PROVISIONED" }) @@ -463,6 +467,10 @@ end local function test_init_dimmer() test.mock_device.add_test_device(mock_device_dimmer) test.socket.device_lifecycle:__queue_receive({ mock_device_dimmer.id, "doConfigure" }) + test.socket.matter:__expect_send({ + mock_device_dimmer.id, + clusters.LevelControl.attributes.Options:write(mock_device_dimmer, 1, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF) + }) mock_device_dimmer:expect_metadata_update({ profile = "switch-level" }) mock_device_dimmer:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end @@ -472,6 +480,14 @@ local function test_init_color_dimmer() test.socket.device_lifecycle:__queue_receive({ mock_device_color_dimmer.id, "added" }) test.socket.device_lifecycle:__queue_receive({ mock_device_color_dimmer.id, "init" }) test.socket.device_lifecycle:__queue_receive({ mock_device_color_dimmer.id, "doConfigure" }) + -- test.socket.matter:__expect_send({ + -- mock_device_color_dimmer.id, + -- clusters.LevelControl.attributes.Options:write(mock_device_color_dimmer, 7, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF) + -- }) + -- test.socket.matter:__expect_send({ + -- mock_device_color_dimmer.id, + -- clusters.ColorControl.attributes.Options:write(mock_device_color_dimmer, 7, clusters.ColorControl.types.OptionsBitmap.EXECUTE_IF_OFF) + -- }) mock_device_color_dimmer:expect_metadata_update({ profile = "switch-color-level" }) mock_device_color_dimmer:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end @@ -494,6 +510,10 @@ local function test_init_mounted_on_off_control() test.socket.matter:__expect_send({mock_device_mounted_on_off_control.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device_mounted_on_off_control.id, "doConfigure" }) + test.socket.matter:__expect_send({ + mock_device_mounted_on_off_control.id, + clusters.LevelControl.attributes.Options:write(mock_device_mounted_on_off_control, 7, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF) + }) mock_device_mounted_on_off_control:expect_metadata_update({ profile = "switch-binary" }) mock_device_mounted_on_off_control:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end @@ -502,6 +522,9 @@ local function test_init_mounted_dimmable_load_control() test.mock_device.add_test_device(mock_device_mounted_dimmable_load_control) local cluster_subscribe_list = { clusters.OnOff.attributes.OnOff, + clusters.LevelControl.attributes.CurrentLevel, + clusters.LevelControl.attributes.MinLevel, + clusters.LevelControl.attributes.MaxLevel, } local subscribe_request = cluster_subscribe_list[1]:subscribe(mock_device_mounted_dimmable_load_control) for i, cluster in ipairs(cluster_subscribe_list) do @@ -516,6 +539,10 @@ local function test_init_mounted_dimmable_load_control() test.socket.matter:__expect_send({mock_device_mounted_dimmable_load_control.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device_mounted_dimmable_load_control.id, "doConfigure" }) + test.socket.matter:__expect_send({ + mock_device_mounted_dimmable_load_control.id, + clusters.LevelControl.attributes.Options:write(mock_device_mounted_dimmable_load_control, 7, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF) + }) mock_device_mounted_dimmable_load_control:expect_metadata_update({ profile = "switch-level" }) mock_device_mounted_dimmable_load_control:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end @@ -557,6 +584,14 @@ local function test_init_parent_child_different_types() test.socket.matter:__expect_send({mock_device_parent_child_different_types.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device_parent_child_different_types.id, "doConfigure" }) + test.socket.matter:__expect_send({ + mock_device_parent_child_different_types.id, + clusters.LevelControl.attributes.Options:write(mock_device_parent_child_different_types, 10, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF) + }) + test.socket.matter:__expect_send({ + mock_device_parent_child_different_types.id, + clusters.ColorControl.attributes.Options:write(mock_device_parent_child_different_types, 10, clusters.ColorControl.types.OptionsBitmap.EXECUTE_IF_OFF) + }) mock_device_parent_child_different_types:expect_metadata_update({ profile = "switch-binary" }) mock_device_parent_child_different_types:expect_metadata_update({ provisioning_state = "PROVISIONED" }) @@ -575,6 +610,10 @@ local function test_init_parent_child_unsupported_device_type() test.socket.device_lifecycle:__queue_receive({ mock_device_parent_child_unsupported_device_type.id, "init" }) test.socket.device_lifecycle:__queue_receive({ mock_device_parent_child_unsupported_device_type.id, "doConfigure" }) mock_device_parent_child_unsupported_device_type:expect_metadata_update({ profile = "switch-binary" }) + test.socket.matter:__expect_send({ + mock_device_parent_child_unsupported_device_type.id, + clusters.LevelControl.attributes.Options:write(mock_device_parent_child_unsupported_device_type, 10, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF) + }) mock_device_parent_child_unsupported_device_type:expect_metadata_update({ provisioning_state = "PROVISIONED" }) mock_device_parent_child_unsupported_device_type:expect_device_create({ @@ -609,6 +648,10 @@ local function test_init_light_level_motion() test.socket.matter:__expect_send({mock_device_light_level_motion.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device_light_level_motion.id, "doConfigure" }) + test.socket.matter:__expect_send({ + mock_device_light_level_motion.id, + clusters.LevelControl.attributes.Options:write(mock_device_light_level_motion, 1, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF) + }) mock_device_light_level_motion:expect_metadata_update({ profile = "light-level-motion" }) mock_device_light_level_motion:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end diff --git a/drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_lights.lua b/drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_lights.lua index 0d3cd90854..178a5bf37d 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_lights.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_lights.lua @@ -178,6 +178,9 @@ local function test_init() test.socket.matter:__expect_send({mock_device.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device.id, "doConfigure" }) + test.socket.matter:__expect_send({mock_device.id, clusters.LevelControl.attributes.Options:write(mock_device, child1_ep, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF)}) + test.socket.matter:__expect_send({mock_device.id, clusters.LevelControl.attributes.Options:write(mock_device, child2_ep, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF)}) + test.socket.matter:__expect_send({mock_device.id, clusters.ColorControl.attributes.Options:write(mock_device, child2_ep, clusters.ColorControl.types.OptionsBitmap.EXECUTE_IF_OFF)}) mock_device:expect_metadata_update({ profile = "light-binary" }) mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) @@ -222,7 +225,9 @@ for i, endpoint in ipairs(mock_device_parent_child_endpoints_non_sequential.endp end local function test_init_parent_child_endpoints_non_sequential() - test.mock_device.add_test_device(mock_device_parent_child_endpoints_non_sequential) + local unsup_mock_device = mock_device_parent_child_endpoints_non_sequential + + test.mock_device.add_test_device(unsup_mock_device) local cluster_subscribe_list = { clusters.OnOff.attributes.OnOff, clusters.LevelControl.attributes.CurrentLevel, @@ -236,49 +241,53 @@ local function test_init_parent_child_endpoints_non_sequential() clusters.ColorControl.attributes.CurrentX, clusters.ColorControl.attributes.CurrentY } - local subscribe_request = cluster_subscribe_list[1]:subscribe(mock_device_parent_child_endpoints_non_sequential) + local subscribe_request = cluster_subscribe_list[1]:subscribe(unsup_mock_device) for i, cluster in ipairs(cluster_subscribe_list) do if i > 1 then - subscribe_request:merge(cluster:subscribe(mock_device_parent_child_endpoints_non_sequential)) + subscribe_request:merge(cluster:subscribe(unsup_mock_device)) end end - test.socket.device_lifecycle:__queue_receive({ mock_device_parent_child_endpoints_non_sequential.id, "added" }) - test.socket.matter:__expect_send({mock_device_parent_child_endpoints_non_sequential.id, subscribe_request}) + test.socket.device_lifecycle:__queue_receive({ unsup_mock_device.id, "added" }) + test.socket.matter:__expect_send({unsup_mock_device.id, subscribe_request}) + + test.socket.device_lifecycle:__queue_receive({ unsup_mock_device.id, "init" }) + test.socket.matter:__expect_send({unsup_mock_device.id, subscribe_request}) - test.socket.device_lifecycle:__queue_receive({ mock_device_parent_child_endpoints_non_sequential.id, "init" }) - test.socket.matter:__expect_send({mock_device_parent_child_endpoints_non_sequential.id, subscribe_request}) + test.socket.device_lifecycle:__queue_receive({ unsup_mock_device.id, "doConfigure" }) + test.socket.matter:__expect_send({unsup_mock_device.id, clusters.LevelControl.attributes.Options:write(unsup_mock_device, child1_ep_non_sequential, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF)}) + test.socket.matter:__expect_send({unsup_mock_device.id, clusters.LevelControl.attributes.Options:write(unsup_mock_device, child2_ep_non_sequential, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF)}) + test.socket.matter:__expect_send({unsup_mock_device.id, clusters.ColorControl.attributes.Options:write(unsup_mock_device, child2_ep_non_sequential, clusters.ColorControl.types.OptionsBitmap.EXECUTE_IF_OFF)}) - test.socket.device_lifecycle:__queue_receive({ mock_device_parent_child_endpoints_non_sequential.id, "doConfigure" }) - mock_device_parent_child_endpoints_non_sequential:expect_metadata_update({ profile = "light-binary" }) - mock_device_parent_child_endpoints_non_sequential:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + unsup_mock_device:expect_metadata_update({ profile = "light-binary" }) + unsup_mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) for _, child in pairs(mock_children_non_sequential) do test.mock_device.add_test_device(child) end - mock_device_parent_child_endpoints_non_sequential:expect_device_create({ + unsup_mock_device:expect_device_create({ type = "EDGE_CHILD", label = "Matter Switch 2", profile = "light-color-level", - parent_device_id = mock_device_parent_child_endpoints_non_sequential.id, + parent_device_id = unsup_mock_device.id, parent_assigned_child_key = string.format("%d", child2_ep_non_sequential) }) -- switch-binary will be selected as an overridden child device profile - mock_device_parent_child_endpoints_non_sequential:expect_device_create({ + unsup_mock_device:expect_device_create({ type = "EDGE_CHILD", label = "Matter Switch 3", profile = "switch-binary", - parent_device_id = mock_device_parent_child_endpoints_non_sequential.id, + parent_device_id = unsup_mock_device.id, parent_assigned_child_key = string.format("%d", child3_ep_non_sequential) }) - mock_device_parent_child_endpoints_non_sequential:expect_device_create({ + unsup_mock_device:expect_device_create({ type = "EDGE_CHILD", label = "Matter Switch 4", profile = "light-level", - parent_device_id = mock_device_parent_child_endpoints_non_sequential.id, + parent_device_id = unsup_mock_device.id, parent_assigned_child_key = string.format("%d", child1_ep_non_sequential) }) end From ebfe276fec124fab22cab426d40bbf9144c99c0c Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Thu, 6 Nov 2025 09:35:30 -0600 Subject: [PATCH 2/4] fix missed test --- .../matter-switch/src/test/test_electrical_sensor.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/SmartThings/matter-switch/src/test/test_electrical_sensor.lua b/drivers/SmartThings/matter-switch/src/test/test_electrical_sensor.lua index 920e24c6aa..7d2f962f49 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_electrical_sensor.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_electrical_sensor.lua @@ -400,6 +400,7 @@ test.register_coroutine_test( "Test profile change on init for Electrical Sensor device type", function() test.socket.device_lifecycle:__queue_receive({ mock_device.id, "doConfigure" }) + test.socket.matter:__expect_send({mock_device.id, clusters.LevelControl.attributes.Options:write(mock_device, 2, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF)}) mock_device:expect_metadata_update({ profile = "plug-level-power-energy-powerConsumption" }) mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, From 417020b8b5f60ded716de27a1b269e6e325f32a9 Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Thu, 6 Nov 2025 12:17:57 -0600 Subject: [PATCH 3/4] remove commented-out test lines --- .../src/test/test_matter_switch_device_types.lua | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_switch_device_types.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_switch_device_types.lua index 5a29e0b6c5..920b9a4b5f 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_switch_device_types.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_switch_device_types.lua @@ -480,14 +480,6 @@ local function test_init_color_dimmer() test.socket.device_lifecycle:__queue_receive({ mock_device_color_dimmer.id, "added" }) test.socket.device_lifecycle:__queue_receive({ mock_device_color_dimmer.id, "init" }) test.socket.device_lifecycle:__queue_receive({ mock_device_color_dimmer.id, "doConfigure" }) - -- test.socket.matter:__expect_send({ - -- mock_device_color_dimmer.id, - -- clusters.LevelControl.attributes.Options:write(mock_device_color_dimmer, 7, clusters.LevelControl.types.OptionsBitmap.EXECUTE_IF_OFF) - -- }) - -- test.socket.matter:__expect_send({ - -- mock_device_color_dimmer.id, - -- clusters.ColorControl.attributes.Options:write(mock_device_color_dimmer, 7, clusters.ColorControl.types.OptionsBitmap.EXECUTE_IF_OFF) - -- }) mock_device_color_dimmer:expect_metadata_update({ profile = "switch-color-level" }) mock_device_color_dimmer:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end From 1a962efc3c453b18087bccb6dc55c8c9f6c5852b Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Tue, 11 Nov 2025 14:34:29 -0600 Subject: [PATCH 4/4] fix spacing --- .../matter-switch/src/switch_utils/utils.lua | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua b/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua index 7e6137cc6c..7611d403de 100644 --- a/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua +++ b/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua @@ -193,13 +193,13 @@ function utils.ep_supports_cluster(ep_info, cluster_id, opts) return (cluster.feature_map & checked_feature) == checked_feature end for _, cluster in ipairs(ep_info.clusters) do - if ((cluster.cluster_id == cluster_id) - and (opts.feature_bitmap == nil or clus_has_features(cluster, opts.feature_bitmap)) - and ((opts.cluster_type == nil and cluster.cluster_type == "SERVER" or cluster.cluster_type == "BOTH") - or (opts.cluster_type == cluster.cluster_type)) - or (cluster_id == nil)) then - return true - end + if ((cluster.cluster_id == cluster_id) + and (opts.feature_bitmap == nil or clus_has_features(cluster, opts.feature_bitmap)) + and ((opts.cluster_type == nil and cluster.cluster_type == "SERVER" or cluster.cluster_type == "BOTH") + or (opts.cluster_type == cluster.cluster_type)) + or (cluster_id == nil)) then + return true + end end end