From 9a008a5b7c0fbecf268bc96d399666a3da146014 Mon Sep 17 00:00:00 2001 From: nickolas-deboom <158304111+nickolas-deboom@users.noreply.github.com> Date: Mon, 30 Sep 2024 14:20:54 -0500 Subject: [PATCH] Sort endpoints before initializing switch (#1657) Sort endpoints before initializing switch --- .../SmartThings/matter-switch/src/init.lua | 2 + .../test_multi_switch_parent_child_lights.lua | 146 +++++++++++++++++- 2 files changed, 147 insertions(+), 1 deletion(-) diff --git a/drivers/SmartThings/matter-switch/src/init.lua b/drivers/SmartThings/matter-switch/src/init.lua index 6368b237da..9c6da7f50f 100644 --- a/drivers/SmartThings/matter-switch/src/init.lua +++ b/drivers/SmartThings/matter-switch/src/init.lua @@ -458,6 +458,8 @@ end local function initialize_switch(driver, device) local switch_eps = device:get_endpoints(clusters.OnOff.ID) local button_eps = device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.Feature.MOMENTARY_SWITCH}) + table.sort(switch_eps) + table.sort(button_eps) local profile_name = nil 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 b198834a1e..bb004c00ce 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 @@ -76,9 +76,75 @@ local mock_device = test.mock_device.build_test_matter_device({ } }) +local child1_ep_non_sequential = 50 +local child2_ep_non_sequential = 30 +local child3_ep_non_sequential = 40 + +local mock_device_parent_child_endpoints_non_sequential = test.mock_device.build_test_matter_device({ + label = "Matter Switch", + profile = t_utils.get_profile_definition("light-level-colorTemperature.yml"), + manufacturer_info = { + vendor_id = 0x0000, + product_id = 0x0000, + }, + endpoints = { + { + endpoint_id = 0, + clusters = { + {cluster_id = clusters.Basic.ID, cluster_type = "SERVER"}, + }, + device_types = { + {device_type_id = 0x0016, device_type_revision = 1} -- RootNode + } + }, + { + endpoint_id = parent_ep, + clusters = { + {cluster_id = clusters.OnOff.ID, cluster_type = "SERVER"}, + }, + device_types = { + {device_type_id = 0x0100, device_type_revision = 2} -- On/Off Light + } + }, + { + endpoint_id = child1_ep_non_sequential, + clusters = { + {cluster_id = clusters.OnOff.ID, cluster_type = "SERVER"}, + {cluster_id = clusters.LevelControl.ID, cluster_type = "SERVER", feature_map = 2} + }, + device_types = { + {device_type_id = 0x0100, device_type_revision = 2}, -- On/Off Light + {device_type_id = 0x0101, device_type_revision = 2} -- Dimmable Light + } + }, + { + endpoint_id = child2_ep_non_sequential, + clusters = { + {cluster_id = clusters.OnOff.ID, cluster_type = "SERVER"}, + {cluster_id = clusters.LevelControl.ID, cluster_type = "SERVER", feature_map = 2}, + {cluster_id = clusters.ColorControl.ID, cluster_type = "BOTH", feature_map = 30}, + }, + device_types = { + {device_type_id = 0x010D, device_type_revision = 2} -- Extended Color Light + } + }, + { + endpoint_id = child3_ep_non_sequential, + clusters = { + {cluster_id = clusters.OnOff.ID, cluster_type = "SERVER"}, + {cluster_id = clusters.LevelControl.ID, cluster_type = "SERVER", feature_map = 2}, + {cluster_id = clusters.ColorControl.ID, cluster_type = "BOTH", feature_map = 30}, + }, + device_types = { + {device_type_id = 0x010D, device_type_revision = 2} -- Extended Color Light + } + }, + } +}) + local child_profiles = { [child1_ep] = t_utils.get_profile_definition("light-level.yml"), - [child2_ep] = t_utils.get_profile_definition("light-color-level.yml") + [child2_ep] = t_utils.get_profile_definition("light-color-level.yml"), } local mock_children = {} @@ -138,6 +204,77 @@ local function test_init() }) end +local child_profiles_non_sequential = { + [child1_ep_non_sequential] = t_utils.get_profile_definition("light-level.yml"), + [child2_ep_non_sequential] = t_utils.get_profile_definition("light-color-level.yml"), + [child3_ep_non_sequential] = t_utils.get_profile_definition("light-color-level.yml"), +} + +local mock_children_non_sequential = {} +for i, endpoint in ipairs(mock_device_parent_child_endpoints_non_sequential.endpoints) do + if endpoint.endpoint_id ~= parent_ep and endpoint.endpoint_id ~= 0 then + local child_data = { + profile = child_profiles_non_sequential[endpoint.endpoint_id], + device_network_id = string.format("%s:%d", mock_device_parent_child_endpoints_non_sequential.id, endpoint.endpoint_id), + parent_device_id = mock_device_parent_child_endpoints_non_sequential.id, + parent_assigned_child_key = string.format("%d", endpoint.endpoint_id) + } + mock_children_non_sequential[endpoint.endpoint_id] = test.mock_device.build_test_child_device(child_data) + end +end + +local function test_init_parent_child_endpoints_non_sequential() + local cluster_subscribe_list = { + clusters.OnOff.attributes.OnOff, + clusters.LevelControl.attributes.CurrentLevel, + clusters.LevelControl.attributes.MaxLevel, + clusters.LevelControl.attributes.MinLevel, + clusters.ColorControl.attributes.ColorTemperatureMireds, + clusters.ColorControl.attributes.ColorTempPhysicalMaxMireds, + clusters.ColorControl.attributes.ColorTempPhysicalMinMireds, + clusters.ColorControl.attributes.CurrentHue, + clusters.ColorControl.attributes.CurrentSaturation, + clusters.ColorControl.attributes.CurrentX, + clusters.ColorControl.attributes.CurrentY + } + local subscribe_request = cluster_subscribe_list[1]:subscribe(mock_device_parent_child_endpoints_non_sequential) + 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)) + end + end + test.socket.matter:__expect_send({mock_device_parent_child_endpoints_non_sequential.id, subscribe_request}) + + test.mock_device.add_test_device(mock_device_parent_child_endpoints_non_sequential) + 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({ + type = "EDGE_CHILD", + label = "Matter Switch 2", + profile = "light-color-level", + parent_device_id = mock_device_parent_child_endpoints_non_sequential.id, + parent_assigned_child_key = string.format("%d", child2_ep_non_sequential) + }) + + mock_device_parent_child_endpoints_non_sequential:expect_device_create({ + type = "EDGE_CHILD", + label = "Matter Switch 3", + profile = "light-color-level", + parent_device_id = mock_device_parent_child_endpoints_non_sequential.id, + parent_assigned_child_key = string.format("%d", child3_ep_non_sequential) + }) + + mock_device_parent_child_endpoints_non_sequential: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_assigned_child_key = string.format("%d", child1_ep_non_sequential) + }) +end + test.set_test_init_function(test_init) test.register_message_test( @@ -494,4 +631,11 @@ test.register_message_test( } ) +test.register_coroutine_test( + "Test child devices are created in order of their endpoints", + function() + end, + { test_init = test_init_parent_child_endpoints_non_sequential } +) + test.run_registered_tests()