diff --git a/drivers/SmartThings/matter-switch/src/init.lua b/drivers/SmartThings/matter-switch/src/init.lua index 0535690a44..76b38ab3ee 100644 --- a/drivers/SmartThings/matter-switch/src/init.lua +++ b/drivers/SmartThings/matter-switch/src/init.lua @@ -51,7 +51,7 @@ local function find_default_endpoint(device, component) return res end -local function create_endpoint_to_component_map(device) +local function initialize_switch(device) local switch_eps = device:get_endpoints(clusters.OnOff.ID) table.sort(switch_eps) @@ -71,6 +71,21 @@ local function create_endpoint_to_component_map(device) end device:set_field(ENDPOINT_TO_COMPONENT_MAP, endpoint_map, {persist = true}) + + -- New profiles need to be added for devices that have more switch endpoints + local MAX_MULTI_SWITCH_EPS = 7 + -- Note: This profile switching is needed because of shortcoming in the generic fingerprints + -- where devices with multiple endpoints with the same device type cannot be detected + local num_switch_eps = #switch_eps + if num_switch_eps > 1 then + device:try_update_metadata({profile = string.format("switch-%d", math.min(num_switch_eps, MAX_MULTI_SWITCH_EPS))}) + end + if num_switch_eps > MAX_MULTI_SWITCH_EPS then + error(string.format( + "Matter multi switch device will have limited function. Profile doesn't exist with %d components", + num_switch_eps + )) + end end local function component_to_endpoint(device, component_name) @@ -91,7 +106,10 @@ end local function device_init(driver, device) log.info_with({hub_logs=true}, "device init") - create_endpoint_to_component_map(device) + if not device:get_field(ENDPOINT_TO_COMPONENT_MAP) then + -- create endpoint to component map and switch profile as needed + initialize_switch(device) + end device:set_component_to_endpoint_fn(component_to_endpoint) device:set_endpoint_to_component_fn(endpoint_to_component) device:subscribe() @@ -101,24 +119,6 @@ local function device_removed(driver, device) log.info("device removed") end -local function do_configure(driver, device) - -- New profiles need to be added for devices that have more switch endpoints - local MAX_MULTI_SWITCH_EPS = 7 - -- Note: This profile switching is needed because of shortcoming in the generic fingerprints - -- where devices with multiple endpoints with the same device type cannot be detected - local switch_eps = device:get_endpoints(clusters.OnOff.ID) - local num_switch_eps = #switch_eps - if num_switch_eps > 1 then - device:try_update_metadata({profile = string.format("switch-%d", math.min(num_switch_eps, MAX_MULTI_SWITCH_EPS))}) - end - if num_switch_eps > MAX_MULTI_SWITCH_EPS then - error(string.format( - "Matter multi switch device will have limited function. Profile doesn't exist with %d components", - num_switch_eps - )) - end -end - local function handle_switch_on(driver, device, cmd) local endpoint_id = device:component_to_endpoint(cmd.component) --TODO use OnWithRecallGlobalScene for devices with the LT feature @@ -302,8 +302,7 @@ end local matter_driver_template = { lifecycle_handlers = { init = device_init, - removed = device_removed, - doConfigure = do_configure, + removed = device_removed }, matter_handlers = { attr = { diff --git a/drivers/SmartThings/matter-switch/src/test/test_multi_switch.lua b/drivers/SmartThings/matter-switch/src/test/test_multi_switch.lua index 876079ed3f..92c4f843d8 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_multi_switch.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_multi_switch.lua @@ -146,8 +146,7 @@ local mock_3switch_non_sequential = test.mock_device.build_test_matter_device({ } }) - -local function test_init() +local function test_init_mock_3switch() local cluster_subscribe_list = { clusters.OnOff.attributes.OnOff, } @@ -155,37 +154,32 @@ local function test_init() local subscribe_request = cluster_subscribe_list[1]:subscribe(mock_3switch) test.socket.matter:__expect_send({mock_3switch.id, subscribe_request}) test.mock_device.add_test_device(mock_3switch) + mock_3switch:expect_metadata_update({ profile = "switch-3" }) +end + +local function test_init_mock_2switch() + local cluster_subscribe_list = { + clusters.OnOff.attributes.OnOff, + } + test.socket.matter:__set_channel_ordering("relaxed") local subscribe_request = cluster_subscribe_list[1]:subscribe(mock_2switch) test.socket.matter:__expect_send({mock_2switch.id, subscribe_request}) test.mock_device.add_test_device(mock_2switch) + mock_2switch:expect_metadata_update({ profile = "switch-2" }) +end + +local function test_init_mock_3switch_non_sequential() + local cluster_subscribe_list = { + clusters.OnOff.attributes.OnOff, + } + test.socket.matter:__set_channel_ordering("relaxed") local subscribe_request = cluster_subscribe_list[1]:subscribe(mock_3switch_non_sequential) test.socket.matter:__expect_send({mock_3switch_non_sequential.id, subscribe_request}) test.mock_device.add_test_device(mock_3switch_non_sequential) + mock_3switch_non_sequential:expect_metadata_update({ profile = "switch-3" }) end -test.set_test_init_function(test_init) - - -test.register_coroutine_test( - "Profile change for 3 switch device", function() - test.socket.device_lifecycle:__queue_receive({ mock_3switch.id, "doConfigure" }) - mock_3switch:expect_metadata_update({ profile = "switch-3" }) - mock_3switch:expect_metadata_update({ provisioning_state = "PROVISIONED" }) -end) - -test.register_coroutine_test( - "Profile change for 2 switch device", function() - test.socket.device_lifecycle:__queue_receive({ mock_2switch.id, "doConfigure" }) - mock_2switch:expect_metadata_update({ profile = "switch-2" }) - mock_2switch:expect_metadata_update({ provisioning_state = "PROVISIONED" }) -end) - -test.register_coroutine_test( - "Profile change for 3 switch device with non sequential endpoints", function() - test.socket.device_lifecycle:__queue_receive({ mock_3switch_non_sequential.id, "doConfigure" }) - mock_3switch_non_sequential:expect_metadata_update({ profile = "switch-3" }) - mock_3switch_non_sequential:expect_metadata_update({ provisioning_state = "PROVISIONED" }) -end) +-- The custom "test_init" function also checks that the appropriate profile is switched on init test.register_message_test( "On command to component switch should send the appropriate commands", { @@ -205,9 +199,35 @@ test.register_message_test( clusters.OnOff.server.commands.On(mock_3switch, 2) } } - } + }, + { test_init = test_init_mock_3switch } ) +-- The custom "test_init" function also checks that the appropriate profile is switched on init +test.register_message_test( + "On command to component switch should send the appropriate commands", + { + { + channel = "capability", + direction = "receive", + message = { + mock_2switch.id, + { capability = "switch", component = "main", command = "on", args = { } } + } + }, + { + channel = "matter", + direction = "send", + message = { + mock_2switch.id, + clusters.OnOff.server.commands.On(mock_2switch, 1) + } + } + }, + { test_init = test_init_mock_2switch } +) + +-- The custom "test_init" function also checks that the appropriate profile is switched on init test.register_message_test( "On command to component switch should send the appropriate commands for devices with non-sequential endpoints", { @@ -227,7 +247,8 @@ test.register_message_test( clusters.OnOff.server.commands.On(mock_3switch_non_sequential, 15) -- switch 3 is on endpoint 15 } } - } + }, + { test_init = test_init_mock_3switch_non_sequential } ) test.run_registered_tests()