From 7b5daf1f4b0de5faa58805b6a135a053f6fd9fb2 Mon Sep 17 00:00:00 2001 From: Nick DeBoom Date: Tue, 1 Apr 2025 12:56:44 -0500 Subject: [PATCH] Matter Switch move initialization to doConfigure This change moves the initialization logic for buttons and switches to doConfigure. This keeps all of the profile selection logic all within doConfigure and allows the removal of logic gates from device_init that were there to ensure init code only ran one time. Also added is a new function that runs at init that can rename or delete persisted fields on the device. --- .../SmartThings/matter-switch/src/init.lua | 146 +++++++++--------- .../test/test_aqara_climate_sensor_w100.lua | 88 ++++++----- .../src/test/test_aqara_light_switch_h2.lua | 8 +- .../src/test/test_matter_button.lua | 6 +- .../src/test/test_matter_multi_button.lua | 6 +- .../test_matter_multi_button_switch_mcd.lua | 20 ++- .../test/test_matter_switch_device_types.lua | 27 +++- .../test_multi_switch_parent_child_lights.lua | 6 + .../test_multi_switch_parent_child_plugs.lua | 7 + 9 files changed, 189 insertions(+), 125 deletions(-) diff --git a/drivers/SmartThings/matter-switch/src/init.lua b/drivers/SmartThings/matter-switch/src/init.lua index d2bf9aa22e..57bc1ef153 100644 --- a/drivers/SmartThings/matter-switch/src/init.lua +++ b/drivers/SmartThings/matter-switch/src/init.lua @@ -44,19 +44,12 @@ local SWITCH_LEVEL_LIGHTING_MIN = 1 local CURRENT_HUESAT_ATTR_MIN = 0 local CURRENT_HUESAT_ATTR_MAX = 254 -local SWITCH_INITIALIZED = "__switch_intialized" --- COMPONENT_TO_ENDPOINT_MAP is here only to preserve the endpoint mapping for +-- COMPONENT_TO_ENDPOINT_MAP is here to preserve the endpoint mapping for -- devices that were joined to this driver as MCD devices before the transition --- to join all matter-switch devices as parent-child. This value will only exist --- in the device table for devices that joined prior to this transition, and it --- will not be set for new devices. +-- to join switch devices as parent-child. This value will exist in the device +-- table for devices that joined prior to this transition, and is also used for +-- button devices that require component mapping. local COMPONENT_TO_ENDPOINT_MAP = "__component_to_endpoint_map" --- COMPONENT_TO_ENDPOINT_MAP_BUTTON is for devices with button endpoints, to --- preserve the MCD functionality for button devices from the matter-button --- driver after it was merged into the matter-switch driver. Note that devices --- containing both button endpoints and switch endpoints will use this field --- rather than COMPONENT_TO_ENDPOINT_MAP. -local COMPONENT_TO_ENDPOINT_MAP_BUTTON = "__component_to_endpoint_map_button" local ENERGY_MANAGEMENT_ENDPOINT = "__energy_management_endpoint" local IS_PARENT_CHILD_DEVICE = "__is_parent_child_device" local COLOR_TEMP_BOUND_RECEIVED_KELVIN = "__colorTemp_bound_received_kelvin" @@ -67,6 +60,12 @@ local LEVEL_BOUND_RECEIVED = "__level_bound_received" local LEVEL_MIN = "__level_min" local LEVEL_MAX = "__level_max" local COLOR_MODE = "__color_mode" + +local updated_fields = { + { field_name = "__component_to_endpoint_map_button", updated_field_name = COMPONENT_TO_ENDPOINT_MAP }, + { field_name = "__switch_intialized", updated_field_name = nil } +} + local HUE_SAT_COLOR_MODE = clusters.ColorControl.types.ColorMode.CURRENT_HUE_AND_CURRENT_SATURATION local X_Y_COLOR_MODE = clusters.ColorControl.types.ColorMode.CURRENTX_AND_CURRENTY @@ -292,8 +291,6 @@ local HELD_THRESHOLD = 1 -- this is the number of buttons for which we have a static profile already made local STATIC_BUTTON_PROFILE_SUPPORTED = {1, 2, 3, 4, 5, 6, 7, 8} -local BUTTON_DEVICE_PROFILED = "__button_device_profiled" - -- Some switches will send a MultiPressComplete event as part of a long press sequence. Normally the driver will create a -- button capability event on receipt of MultiPressComplete, but in this case that would result in an extra event because -- the "held" capability event is generated when the LongPress event is received. The IGNORE_NEXT_MPC flag is used @@ -406,6 +403,7 @@ local function device_type_supports_button_switch_combination(device, endpoint_i end local function get_first_non_zero_endpoint(endpoints) + table.sort(endpoints) for _,ep in ipairs(endpoints) do if ep ~= 0 then -- 0 is the matter RootNode endpoint return ep @@ -425,8 +423,6 @@ local function find_default_endpoint(device) local switch_eps = device:get_endpoints(clusters.OnOff.ID) local button_eps = device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH}) - table.sort(switch_eps) - table.sort(button_eps) -- Return the first switch endpoint as the default endpoint if no button endpoints are present if #button_eps == 0 and #switch_eps > 0 then @@ -456,7 +452,7 @@ local function find_default_endpoint(device) end local function component_to_endpoint(device, component) - local map = device:get_field(COMPONENT_TO_ENDPOINT_MAP_BUTTON) or device:get_field(COMPONENT_TO_ENDPOINT_MAP) or {} + local map = device:get_field(COMPONENT_TO_ENDPOINT_MAP) or {} if map[component] then return map[component] end @@ -464,7 +460,7 @@ local function component_to_endpoint(device, component) end local function endpoint_to_component(device, ep) - local map = device:get_field(COMPONENT_TO_ENDPOINT_MAP_BUTTON) or device:get_field(COMPONENT_TO_ENDPOINT_MAP) or {} + local map = device:get_field(COMPONENT_TO_ENDPOINT_MAP) or {} for component, endpoint in pairs(map) do if endpoint == ep then return component @@ -473,6 +469,17 @@ local function endpoint_to_component(device, ep) return "main" end +local function check_field_name_updates(device) + for _, field in ipairs(updated_fields) do + if device:get_field(field.field_name) then + if field.updated_field_name ~= nil then + device:set_field(field.updated_field_name, device:get_field(field.field_name), {persist = true}) + end + device:set_field(field.field_name, nil) + end + end +end + local function assign_child_profile(device, child_ep) local profile @@ -512,41 +519,6 @@ local function assign_child_profile(device, child_ep) return profile or "switch-binary" end -local function do_configure(driver, device) - if device:get_field(BUTTON_DEVICE_PROFILED) then - return - end - local fan_eps = device:get_endpoints(clusters.FanControl.ID) - local level_eps = device:get_endpoints(clusters.LevelControl.ID) - local energy_eps = embedded_cluster_utils.get_endpoints(device, clusters.ElectricalEnergyMeasurement.ID) - local power_eps = embedded_cluster_utils.get_endpoints(device, clusters.ElectricalPowerMeasurement.ID) - local valve_eps = embedded_cluster_utils.get_endpoints(device, clusters.ValveConfigurationAndControl.ID) - local profile_name = nil - local level_support = "" - if #level_eps > 0 then - level_support = "-level" - end - if #energy_eps > 0 and #power_eps > 0 then - profile_name = "plug" .. level_support .. "-power-energy-powerConsumption" - elseif #energy_eps > 0 then - profile_name = "plug" .. level_support .. "-energy-powerConsumption" - elseif #power_eps > 0 then - profile_name = "plug" .. level_support .. "-power" - elseif #valve_eps > 0 then - profile_name = "water-valve" - if #embedded_cluster_utils.get_endpoints(device, clusters.ValveConfigurationAndControl.ID, - {feature_bitmap = clusters.ValveConfigurationAndControl.types.Feature.LEVEL}) > 0 then - profile_name = profile_name .. "-level" - end - elseif #fan_eps > 0 then - profile_name = "light-color-level-fan" - end - - if profile_name then - device:try_update_metadata({ profile = profile_name }) - end -end - local function configure_buttons(device) if device.network_type == device_lib.NETWORK_TYPE_CHILD then return @@ -603,7 +575,7 @@ local function build_button_component_map(device, main_endpoint, button_eps) component_map[button_component] = ep end end - device:set_field(COMPONENT_TO_ENDPOINT_MAP_BUTTON, component_map, {persist = true}) + device:set_field(COMPONENT_TO_ENDPOINT_MAP, component_map, {persist = true}) end local function build_button_profile(device, main_endpoint, num_button_eps) @@ -613,13 +585,10 @@ local function build_button_profile(device, main_endpoint, num_button_eps) end local battery_supported = #device:get_endpoints(clusters.PowerSource.ID, {feature_bitmap = clusters.PowerSource.types.PowerSourceFeature.BATTERY}) > 0 if battery_supported then -- battery profiles are configured later, in power_source_attribute_list_handler - local attribute_list_read = im.InteractionRequest(im.InteractionRequest.RequestType.READ, {}) - attribute_list_read:merge(clusters.PowerSource.attributes.AttributeList:read()) - device:send(attribute_list_read) + device:send(clusters.PowerSource.attributes.AttributeList:read(device)) else device:try_update_metadata({profile = profile_name}) end - device:set_field(BUTTON_DEVICE_PROFILED, true) end local function build_child_switch_profiles(driver, device, main_endpoint) @@ -683,13 +652,15 @@ local function handle_light_switch_with_onOff_server_clusters(device, main_endpo end local function initialize_buttons_and_switches(driver, device, main_endpoint) + local profile_found = false local button_eps = device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH}) if tbl_contains(STATIC_BUTTON_PROFILE_SUPPORTED, #button_eps) then build_button_profile(device, main_endpoint, #button_eps) -- All button endpoints found will be added as additional components in the profile containing the main_endpoint. - -- The resulting endpoint to component map is saved in the COMPONENT_TO_ENDPOINT_MAP_BUTTON field + -- The resulting endpoint to component map is saved in the COMPONENT_TO_ENDPOINT_MAP field build_button_component_map(device, main_endpoint, button_eps) configure_buttons(device) + profile_found = true end -- Without support for bindings, only clusters that are implemented as server are counted. This count is handled @@ -701,9 +672,9 @@ local function initialize_buttons_and_switches(driver, device, main_endpoint) -- Note: since their device type isn't supported, these devices join as a matter-thing. if num_switch_server_eps > 0 and detect_matter_thing(device) then handle_light_switch_with_onOff_server_clusters(device, main_endpoint) + profile_found = true end - - device:set_field(SWITCH_INITIALIZED, true, {persist = true}) + return profile_found end local function detect_bridge(device) @@ -721,20 +692,13 @@ local function device_init(driver, device) if device.network_type ~= device_lib.NETWORK_TYPE_MATTER then return end - + check_field_name_updates(device) device:set_component_to_endpoint_fn(component_to_endpoint) device:set_endpoint_to_component_fn(endpoint_to_component) - - local main_endpoint = find_default_endpoint(device) - if not device:get_field(COMPONENT_TO_ENDPOINT_MAP) and -- this field is only set for old MCD devices. See comments in the field def. - not device:get_field(SWITCH_INITIALIZED) and - not detect_bridge(device) then - -- initialize the main device card with buttons if applicable, and create child devices as needed for multi-switch devices. - initialize_buttons_and_switches(driver, device, main_endpoint) - end if device:get_field(IS_PARENT_CHILD_DEVICE) then device:set_find_child(find_child) end + local main_endpoint = find_default_endpoint(device) -- ensure subscription to all endpoint attributes- including those mapped to child devices for _, ep in ipairs(device.endpoints) do if ep.endpoint_id ~= main_endpoint then @@ -756,6 +720,50 @@ local function device_init(driver, device) device:subscribe() end +local function do_configure(driver, device) + if detect_bridge(device) then + return + end + local main_endpoint = find_default_endpoint(device) + -- initialize the main device card with buttons if applicable, and create child devices as needed for multi-switch devices. + local profile_found = initialize_buttons_and_switches(driver, device, main_endpoint) + if device:get_field(IS_PARENT_CHILD_DEVICE) then + device:set_find_child(find_child) + end + if profile_found then + return + end + + local fan_eps = device:get_endpoints(clusters.FanControl.ID) + local level_eps = device:get_endpoints(clusters.LevelControl.ID) + local energy_eps = embedded_cluster_utils.get_endpoints(device, clusters.ElectricalEnergyMeasurement.ID) + local power_eps = embedded_cluster_utils.get_endpoints(device, clusters.ElectricalPowerMeasurement.ID) + local valve_eps = embedded_cluster_utils.get_endpoints(device, clusters.ValveConfigurationAndControl.ID) + local profile_name = nil + local level_support = "" + if #level_eps > 0 then + level_support = "-level" + end + if #energy_eps > 0 and #power_eps > 0 then + profile_name = "plug" .. level_support .. "-power-energy-powerConsumption" + elseif #energy_eps > 0 then + profile_name = "plug" .. level_support .. "-energy-powerConsumption" + elseif #power_eps > 0 then + profile_name = "plug" .. level_support .. "-power" + elseif #valve_eps > 0 then + profile_name = "water-valve" + if #embedded_cluster_utils.get_endpoints(device, clusters.ValveConfigurationAndControl.ID, + {feature_bitmap = clusters.ValveConfigurationAndControl.types.Feature.LEVEL}) > 0 then + profile_name = profile_name .. "-level" + end + elseif #fan_eps > 0 then + profile_name = "light-color-level-fan" + end + if profile_name then + device:try_update_metadata({ profile = profile_name }) + end +end + local function device_removed(driver, device) log.info("device removed") delete_import_poll_schedule(device) diff --git a/drivers/SmartThings/matter-switch/src/test/test_aqara_climate_sensor_w100.lua b/drivers/SmartThings/matter-switch/src/test/test_aqara_climate_sensor_w100.lua index 270bc6febb..830a9b99f8 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_aqara_climate_sensor_w100.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_aqara_climate_sensor_w100.lua @@ -133,10 +133,6 @@ local function test_init() clusters.Switch.server.events.MultiPressComplete, } - local read_attribute_list = clusters.PowerSource.attributes.AttributeList:read() - test.socket.matter:__expect_send({aqara_mock_device.id, read_attribute_list}) - test.socket.matter:__queue_receive({aqara_mock_device.id, clusters.PowerSource.attributes.AttributeList:build_test_report_data(aqara_mock_device, 6, {uint32(0x0C)})}) - local subscribe_request = cluster_subscribe_list[1]:subscribe(aqara_mock_device) for i, cluster in ipairs(cluster_subscribe_list) do if i > 1 then @@ -144,16 +140,17 @@ local function test_init() end end - configure_buttons() test.socket.matter:__expect_send({aqara_mock_device.id, subscribe_request}) + test.socket.device_lifecycle:__queue_receive({ aqara_mock_device.id, "doConfigure" }) + local read_attribute_list = clusters.PowerSource.attributes.AttributeList:read() + test.socket.matter:__expect_send({aqara_mock_device.id, read_attribute_list}) + configure_buttons() + aqara_mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) test.mock_device.add_test_device(aqara_mock_device) test.set_rpc_version(5) test.socket.device_lifecycle:__queue_receive({ aqara_mock_device.id, "added" }) test.socket.matter:__expect_send({aqara_mock_device.id, subscribe_request}) - test.mock_devices_api._expected_device_updates[aqara_mock_device.device_id] = "00000000-1111-2222-3333-000000000001" - test.mock_devices_api._expected_device_updates[1] = {device_id = "00000000-1111-2222-3333-000000000001"} - test.mock_devices_api._expected_device_updates[1].metadata = {deviceId="00000000-1111-2222-3333-000000000001", profileReference="3-button-battery-temperature-humidity"} local device_info_copy = utils.deep_copy(aqara_mock_device.raw_st_data) device_info_copy.profile.id = "3-button-battery-temperature-humidity" @@ -165,9 +162,15 @@ end test.set_test_init_function(test_init) +local function update_profile() + test.socket.matter:__queue_receive({aqara_mock_device.id, clusters.PowerSource.attributes.AttributeList:build_test_report_data(aqara_mock_device, 6, {uint32(0x0C)})}) + aqara_mock_device:expect_metadata_update({ profile = "3-button-battery-temperature-humidity" }) +end + test.register_coroutine_test( "Temperature reports should generate correct messages", function () + update_profile() test.socket.matter:__queue_receive( { aqara_mock_device.id, @@ -183,6 +186,7 @@ test.register_coroutine_test( test.register_coroutine_test( "Min and max temperature attributes set capability constraint", function () + update_profile() test.socket.matter:__queue_receive( { aqara_mock_device.id, @@ -204,6 +208,7 @@ test.register_coroutine_test( test.register_coroutine_test( "Relative humidity reports should generate correct messages", function () + update_profile() test.socket.matter:__queue_receive( { aqara_mock_device.id, @@ -228,6 +233,7 @@ test.register_coroutine_test( test.register_coroutine_test( "Battery percent reports should generate correct messages", function () + update_profile() test.socket.matter:__queue_receive( { aqara_mock_device.id, @@ -243,6 +249,7 @@ test.register_coroutine_test( test.register_coroutine_test( "Handle single press sequence for a long hold on long-release-capable button", -- only a long press event should generate a held event function () + update_profile() test.timer.__create_and_queue_test_time_advance_timer(2, "oneshot") test.socket.matter:__queue_receive( { @@ -264,6 +271,7 @@ test.register_coroutine_test( test.register_coroutine_test( "Handle single press sequence for a long hold on multi button", -- pushes should only be generated from multiPressComplete events function () + update_profile() test.timer.__create_and_queue_test_time_advance_timer(2, "oneshot") test.socket.matter:__queue_receive( { @@ -285,6 +293,7 @@ test.register_coroutine_test( test.register_coroutine_test( "Handle single press sequence for a multi press on multi button", function() + update_profile() test.socket.matter:__queue_receive( { aqara_mock_device.id, @@ -322,6 +331,7 @@ test.register_coroutine_test( test.register_coroutine_test( "Handle long press sequence for a long hold on long-release-capable button", -- only a long press event should generate a held event function () + update_profile() test.socket.matter:__queue_receive( { aqara_mock_device.id, @@ -347,6 +357,7 @@ test.register_coroutine_test( test.register_coroutine_test( "Handle long press sequence for a long hold on multi button", function () + update_profile() test.socket.matter:__queue_receive( { aqara_mock_device.id, @@ -372,6 +383,7 @@ test.register_coroutine_test( test.register_coroutine_test( "Handle double press", function() + update_profile() test.socket.matter:__queue_receive( { aqara_mock_device.id, @@ -387,6 +399,7 @@ test.register_coroutine_test( test.register_coroutine_test( "Receiving a max press attribute of 2 should emit correct event", function() + update_profile() test.socket.matter:__queue_receive( { aqara_mock_device.id, @@ -402,6 +415,7 @@ test.register_coroutine_test( test.register_coroutine_test( "Handle single press sequence for emulated hold on short-release-only button", function () + update_profile() test.timer.__create_and_queue_test_time_advance_timer(2, "oneshot") test.socket.matter:__queue_receive( { @@ -420,46 +434,44 @@ test.register_coroutine_test( end ) -test.register_message_test( - "Receiving a max press attribute of 3 should emit correct event", { - { - channel = "matter", - direction = "receive", - message = { +test.register_coroutine_test( + "Receiving a max press attribute of 3 should emit correct event", + function () + update_profile() + test.socket.matter:__queue_receive( + { aqara_mock_device.id, clusters.Switch.attributes.MultiPressMax:build_test_report_data( aqara_mock_device, 5, 3 ) - }, - }, - { - channel = "capability", - direction = "send", - message = aqara_mock_device:generate_test_message("button3", - capabilities.button.supportedButtonValues({"pushed", "double", "held", "pushed_3x"}, {visibility = {displayed = false}})) - }, - } + } + ) + test.socket.capability:__expect_send( + aqara_mock_device:generate_test_message( + "button3", capabilities.button.supportedButtonValues({"pushed", "double", "held", "pushed_3x"}, {visibility = {displayed = false}}) + ) + ) + end ) -test.register_message_test( - "Receiving a max press attribute of greater than 6 should only emit up to pushed_6x", { - { - channel = "matter", - direction = "receive", - message = { +test.register_coroutine_test( + "Receiving a max press attribute of 3 should emit correct event", + function () + update_profile() + test.socket.matter:__queue_receive( + { aqara_mock_device.id, clusters.Switch.attributes.MultiPressMax:build_test_report_data( aqara_mock_device, 3, 7 ) - }, - }, - { - channel = "capability", - direction = "send", - message = aqara_mock_device:generate_test_message("button1", - capabilities.button.supportedButtonValues({"pushed", "double", "held", "pushed_3x", "pushed_4x", "pushed_5x", "pushed_6x"}, {visibility = {displayed = false}})) - }, - } + } + ) + test.socket.capability:__expect_send( + aqara_mock_device:generate_test_message( + "button1", capabilities.button.supportedButtonValues({"pushed", "double", "held", "pushed_3x", "pushed_4x", "pushed_5x", "pushed_6x"}, {visibility = {displayed = false}}) + ) + ) + end ) test.run_registered_tests() diff --git a/drivers/SmartThings/matter-switch/src/test/test_aqara_light_switch_h2.lua b/drivers/SmartThings/matter-switch/src/test/test_aqara_light_switch_h2.lua index 3ed95aa15f..369689e181 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_aqara_light_switch_h2.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_aqara_light_switch_h2.lua @@ -177,6 +177,11 @@ local function test_init() end end test.socket.matter:__expect_send({aqara_mock_device.id, subscribe_request}) + test.socket.device_lifecycle:__queue_receive({ aqara_mock_device.id, "doConfigure" }) + test.mock_devices_api._expected_device_updates[aqara_mock_device.device_id] = "00000000-1111-2222-3333-000000000001" + test.mock_devices_api._expected_device_updates[1] = {device_id = "00000000-1111-2222-3333-000000000001"} + test.mock_devices_api._expected_device_updates[1].metadata = {deviceId="00000000-1111-2222-3333-000000000001", profileReference="4-button"} + aqara_mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) test.mock_device.add_test_device(aqara_mock_device) -- to test powerConsumptionReport test.timer.__create_and_queue_test_time_advance_timer(60 * 15, "interval", "create_poll_report_schedule") @@ -204,9 +209,6 @@ local function test_init() test.socket.device_lifecycle:__queue_receive({ aqara_mock_device.id, "added" }) configure_buttons() test.socket.matter:__expect_send({aqara_mock_device.id, subscribe_request}) - test.mock_devices_api._expected_device_updates[aqara_mock_device.device_id] = "00000000-1111-2222-3333-000000000001" - test.mock_devices_api._expected_device_updates[1] = {device_id = "00000000-1111-2222-3333-000000000001"} - test.mock_devices_api._expected_device_updates[1].metadata = {deviceId="00000000-1111-2222-3333-000000000001", profileReference="4-button"} aqara_mock_device:set_field(DEFERRED_CONFIGURE, true, opts) local device_info_copy = utils.deep_copy(aqara_mock_device.raw_st_data) diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_button.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_button.lua index ae6f0017b5..f34f432ec7 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_button.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_button.lua @@ -62,11 +62,13 @@ local function test_init() for i, clus in ipairs(CLUSTER_SUBSCRIBE_LIST) do if i > 1 then subscribe_request:merge(clus:subscribe(mock_device)) end end + test.socket.matter:__expect_send({mock_device.id, subscribe_request}) + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "doConfigure" }) + mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + test.mock_device.add_test_device(mock_device) local read_attribute_list = clusters.PowerSource.attributes.AttributeList:read() test.socket.matter:__expect_send({mock_device.id, read_attribute_list}) configure_buttons() - test.socket.matter:__expect_send({mock_device.id, subscribe_request}) - test.mock_device.add_test_device(mock_device) test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" }) test.socket.matter:__expect_send({mock_device.id, subscribe_request}) local device_info_copy = utils.deep_copy(mock_device.raw_st_data) diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button.lua index d74eaf04a9..624a3ab205 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button.lua @@ -121,11 +121,13 @@ local function test_init() for i, clus in ipairs(CLUSTER_SUBSCRIBE_LIST) do if i > 1 then subscribe_request:merge(clus:subscribe(mock_device)) end end + test.socket.matter:__expect_send({mock_device.id, subscribe_request}) + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "doConfigure" }) + mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + test.mock_device.add_test_device(mock_device) local read_attribute_list = clusters.PowerSource.attributes.AttributeList:read() test.socket.matter:__expect_send({mock_device.id, read_attribute_list}) configure_buttons() - test.socket.matter:__expect_send({mock_device.id, subscribe_request}) - test.mock_device.add_test_device(mock_device) test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" }) test.socket.matter:__expect_send({mock_device.id, subscribe_request}) local device_info_copy = utils.deep_copy(mock_device.raw_st_data) 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 dde176de98..962ac6c167 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 @@ -198,6 +198,15 @@ local function test_init() if i > 1 then subscribe_request:merge(clus:subscribe(mock_device)) end end test.socket.matter:__expect_send({mock_device.id, subscribe_request}) + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "doConfigure" }) + mock_device:expect_metadata_update({ profile = "light-level-3-button" }) + mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + local device_info_copy = utils.deep_copy(mock_device.raw_st_data) + device_info_copy.profile.id = "3-button" + local device_info_json = dkjson.encode(device_info_copy) + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "infoChanged", device_info_json }) + test.socket.matter:__expect_send({mock_device.id, subscribe_request}) + configure_buttons() test.mock_device.add_test_device(mock_device) test.mock_device.add_test_device(mock_child) mock_device:expect_device_create({ @@ -210,13 +219,6 @@ local function test_init() test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" }) configure_buttons() test.socket.matter:__expect_send({mock_device.id, subscribe_request}) - mock_device:expect_metadata_update({ profile = "light-level-3-button" }) - local device_info_copy = utils.deep_copy(mock_device.raw_st_data) - device_info_copy.profile.id = "3-button" - local device_info_json = dkjson.encode(device_info_copy) - test.socket.device_lifecycle:__queue_receive({ mock_device.id, "infoChanged", device_info_json }) - test.socket.matter:__expect_send({mock_device.id, subscribe_request}) - configure_buttons() end local function test_init_mcd_unsupported_switch_device_type() @@ -233,7 +235,10 @@ local function test_init_mcd_unsupported_switch_device_type() subscribe_request:merge(cluster:subscribe(mock_device_mcd_unsupported_switch_device_type)) end end + test.socket.matter:__expect_send({mock_device_mcd_unsupported_switch_device_type.id, subscribe_request}) + test.socket.device_lifecycle:__queue_receive({ mock_device_mcd_unsupported_switch_device_type.id, "doConfigure" }) mock_device_mcd_unsupported_switch_device_type:expect_metadata_update({ profile = "2-button" }) + mock_device_mcd_unsupported_switch_device_type:expect_metadata_update({ provisioning_state = "PROVISIONED" }) mock_device_mcd_unsupported_switch_device_type:expect_device_create({ type = "EDGE_CHILD", label = "Matter Switch 1", @@ -242,7 +247,6 @@ local function test_init_mcd_unsupported_switch_device_type() parent_assigned_child_key = string.format("%d", 7) }) test.mock_device.add_test_device(mock_device_mcd_unsupported_switch_device_type) - test.socket.matter:__expect_send({mock_device_mcd_unsupported_switch_device_type.id, subscribe_request}) end test.set_test_init_function(test_init) 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 4d8325d2fa..6debff2163 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 @@ -365,8 +365,12 @@ local mock_device_parent_child_unsupported_device_type = test.mock_device.build_ local function test_init_parent_child_switch_types() local subscribe_request = clusters.OnOff.attributes.OnOff:subscribe(mock_device_parent_child_switch_types) test.socket.matter:__expect_send({mock_device_parent_child_switch_types.id, subscribe_request}) - test.mock_device.add_test_device(mock_device_parent_child_switch_types) + + test.socket.device_lifecycle:__queue_receive({ mock_device_parent_child_switch_types.id, "doConfigure" }) mock_device_parent_child_switch_types:expect_metadata_update({ profile = "switch-level" }) + mock_device_parent_child_switch_types:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + + test.mock_device.add_test_device(mock_device_parent_child_switch_types) mock_device_parent_child_switch_types:expect_device_create({ type = "EDGE_CHILD", @@ -379,7 +383,9 @@ end local function test_init_onoff() test.mock_device.add_test_device(mock_device_onoff) + test.socket.device_lifecycle:__queue_receive({ mock_device_onoff.id, "doConfigure" }) mock_device_onoff:expect_metadata_update({ profile = "switch-binary" }) + mock_device_onoff:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end local function test_init_onoff_client() @@ -389,18 +395,24 @@ end local function test_init_parent_client_child_server() local subscribe_request = clusters.OnOff.attributes.OnOff:subscribe(mock_device_parent_client_child_server) test.socket.matter:__expect_send({mock_device_parent_client_child_server.id, subscribe_request}) - test.mock_device.add_test_device(mock_device_parent_client_child_server) + test.socket.device_lifecycle:__queue_receive({ mock_device_parent_client_child_server.id, "doConfigure" }) mock_device_parent_client_child_server:expect_metadata_update({ profile = "switch-binary" }) + mock_device_parent_client_child_server:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + test.mock_device.add_test_device(mock_device_parent_client_child_server) 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" }) mock_device_dimmer:expect_metadata_update({ profile = "switch-level" }) + mock_device_dimmer:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end local function test_init_color_dimmer() test.mock_device.add_test_device(mock_device_color_dimmer) + test.socket.device_lifecycle:__queue_receive({ mock_device_color_dimmer.id, "doConfigure" }) mock_device_color_dimmer:expect_metadata_update({ profile = "switch-color-level" }) + mock_device_color_dimmer:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end local function test_init_mounted_on_off_control() @@ -414,6 +426,8 @@ local function test_init_mounted_on_off_control() end end 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" }) + mock_device_mounted_on_off_control:expect_metadata_update({ provisioning_state = "PROVISIONED" }) test.mock_device.add_test_device(mock_device_mounted_on_off_control) end @@ -428,6 +442,8 @@ local function test_init_mounted_dimmable_load_control() end end 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" }) + mock_device_mounted_dimmable_load_control:expect_metadata_update({ provisioning_state = "PROVISIONED" }) test.mock_device.add_test_device(mock_device_mounted_dimmable_load_control) end @@ -460,6 +476,9 @@ local function test_init_parent_child_different_types() end 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" }) + mock_device_parent_child_different_types:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + test.mock_device.add_test_device(mock_device_parent_child_different_types) mock_device_parent_child_different_types:expect_device_create({ @@ -472,8 +491,10 @@ local function test_init_parent_child_different_types() end local function test_init_parent_child_unsupported_device_type() - test.mock_device.add_test_device(mock_device_parent_child_unsupported_device_type) + 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" }) + mock_device_parent_child_unsupported_device_type:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + test.mock_device.add_test_device(mock_device_parent_child_unsupported_device_type) mock_device_parent_child_unsupported_device_type:expect_device_create({ type = "EDGE_CHILD", 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 065b364998..ec403a0a6d 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 @@ -180,6 +180,9 @@ local function test_init() end test.socket.matter:__expect_send({mock_device.id, subscribe_request}) + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "doConfigure" }) + mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + test.mock_device.add_test_device(mock_device) for _, child in pairs(mock_children) do test.mock_device.add_test_device(child) @@ -243,6 +246,9 @@ local function test_init_parent_child_endpoints_non_sequential() end test.socket.matter:__expect_send({mock_device_parent_child_endpoints_non_sequential.id, subscribe_request}) + 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({ provisioning_state = "PROVISIONED" }) + 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) diff --git a/drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_plugs.lua b/drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_plugs.lua index 5b2e080713..9152d947d0 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_plugs.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_plugs.lua @@ -138,6 +138,9 @@ local function test_init() local subscribe_request = cluster_subscribe_list[1]:subscribe(mock_device) test.socket.matter:__expect_send({mock_device.id, subscribe_request}) + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "doConfigure" }) + mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + test.mock_device.add_test_device(mock_device) for _, child in pairs(mock_children) do test.mock_device.add_test_device(child) @@ -172,6 +175,7 @@ for i, endpoint in ipairs(mock_device_child_profile_override.endpoints) do mock_children_child_profile_override[endpoint.endpoint_id] = test.mock_device.build_test_child_device(child_data) end end + local function test_init_child_profile_override() local cluster_subscribe_list = { clusters.OnOff.attributes.OnOff, @@ -179,6 +183,9 @@ local function test_init_child_profile_override() local subscribe_request = cluster_subscribe_list[1]:subscribe(mock_device_child_profile_override) test.socket.matter:__expect_send({mock_device_child_profile_override.id, subscribe_request}) + test.socket.device_lifecycle:__queue_receive({ mock_device_child_profile_override.id, "doConfigure" }) + mock_device_child_profile_override:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + test.mock_device.add_test_device(mock_device_child_profile_override) for _, child in pairs(mock_children_child_profile_override) do test.mock_device.add_test_device(child)