diff --git a/drivers/SmartThings/matter-switch/profiles/plug-2-button.yml b/drivers/SmartThings/matter-switch/profiles/plug-2-button.yml new file mode 100644 index 0000000000..c9a514a5cc --- /dev/null +++ b/drivers/SmartThings/matter-switch/profiles/plug-2-button.yml @@ -0,0 +1,24 @@ +name: plug-2-button +components: + - id: main + capabilities: + - id: switch + version: 1 + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: SmartPlug + - id: button + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button2 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController diff --git a/drivers/SmartThings/matter-switch/profiles/plug-3-button.yml b/drivers/SmartThings/matter-switch/profiles/plug-3-button.yml new file mode 100644 index 0000000000..952f6d06d3 --- /dev/null +++ b/drivers/SmartThings/matter-switch/profiles/plug-3-button.yml @@ -0,0 +1,30 @@ +name: plug-3-button +components: + - id: main + capabilities: + - id: switch + version: 1 + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: SmartPlug + - id: button + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button2 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button3 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController diff --git a/drivers/SmartThings/matter-switch/profiles/plug-4-button.yml b/drivers/SmartThings/matter-switch/profiles/plug-4-button.yml new file mode 100644 index 0000000000..afac64c9b4 --- /dev/null +++ b/drivers/SmartThings/matter-switch/profiles/plug-4-button.yml @@ -0,0 +1,36 @@ +name: plug-4-button +components: + - id: main + capabilities: + - id: switch + version: 1 + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: SmartPlug + - id: button + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button2 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button3 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button4 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController diff --git a/drivers/SmartThings/matter-switch/profiles/plug-5-button.yml b/drivers/SmartThings/matter-switch/profiles/plug-5-button.yml new file mode 100644 index 0000000000..dfe0d4cf05 --- /dev/null +++ b/drivers/SmartThings/matter-switch/profiles/plug-5-button.yml @@ -0,0 +1,42 @@ +name: plug-5-button +components: + - id: main + capabilities: + - id: switch + version: 1 + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: SmartPlug + - id: button + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button2 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button3 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button4 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button5 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController diff --git a/drivers/SmartThings/matter-switch/profiles/plug-6-button.yml b/drivers/SmartThings/matter-switch/profiles/plug-6-button.yml new file mode 100644 index 0000000000..ef8fe07d96 --- /dev/null +++ b/drivers/SmartThings/matter-switch/profiles/plug-6-button.yml @@ -0,0 +1,48 @@ +name: plug-6-button +components: + - id: main + capabilities: + - id: switch + version: 1 + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: SmartPlug + - id: button + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button2 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button3 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button4 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button5 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button6 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController diff --git a/drivers/SmartThings/matter-switch/profiles/plug-7-button.yml b/drivers/SmartThings/matter-switch/profiles/plug-7-button.yml new file mode 100644 index 0000000000..957fcb1aab --- /dev/null +++ b/drivers/SmartThings/matter-switch/profiles/plug-7-button.yml @@ -0,0 +1,54 @@ +name: plug-7-button +components: + - id: main + capabilities: + - id: switch + version: 1 + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: SmartPlug + - id: button + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button2 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button3 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button4 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button5 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button6 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button7 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController diff --git a/drivers/SmartThings/matter-switch/profiles/plug-8-button.yml b/drivers/SmartThings/matter-switch/profiles/plug-8-button.yml new file mode 100644 index 0000000000..1ae3e541b8 --- /dev/null +++ b/drivers/SmartThings/matter-switch/profiles/plug-8-button.yml @@ -0,0 +1,60 @@ +name: plug-8-button +components: + - id: main + capabilities: + - id: switch + version: 1 + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: SmartPlug + - id: button + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button2 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button3 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button4 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button5 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button6 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button7 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button8 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController diff --git a/drivers/SmartThings/matter-switch/src/init.lua b/drivers/SmartThings/matter-switch/src/init.lua index 3fab77fa3a..268650d54f 100644 --- a/drivers/SmartThings/matter-switch/src/init.lua +++ b/drivers/SmartThings/matter-switch/src/init.lua @@ -346,16 +346,20 @@ end --- whether the device type for an endpoint is currently supported by a profile for --- combination button/switch devices. local function is_supported_combination_button_switch_device_type(device, endpoint_id) - for _, ep in ipairs(device.endpoints) do - if ep.endpoint_id == endpoint_id then - for _, dt in ipairs(ep.device_types) do - if dt.device_type_id == DIMMABLE_LIGHT_DEVICE_TYPE_ID then - return true + 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}) + if #switch_eps > 0 and #button_eps > 0 then + for _, ep in ipairs(device.endpoints) do + if ep.endpoint_id == endpoint_id then + for _, dt in ipairs(ep.device_types) do + if dt.device_type_id == DIMMABLE_LIGHT_DEVICE_TYPE_ID or dt.device_type_id == ON_OFF_PLUG_DEVICE_TYPE_ID then + return true, dt.device_type_id + end end end end end - return false + return false, nil end local function get_first_non_zero_endpoint(endpoints) @@ -393,7 +397,8 @@ local function find_default_endpoint(device) -- default endpoint. if #switch_eps > 0 and #button_eps > 0 then local main_endpoint = get_first_non_zero_endpoint(switch_eps) - if is_supported_combination_button_switch_device_type(device, main_endpoint) then + local is_supported_device_type, _ = is_supported_combination_button_switch_device_type(device, main_endpoint) + if is_supported_device_type then return main_endpoint else device.log.warn("The main switch endpoint does not contain a supported device type for a component configuration with buttons") @@ -571,11 +576,17 @@ local function initialize_switch(driver, device) device:set_field(COMPONENT_TO_ENDPOINT_MAP_BUTTON, component_map, {persist = true}) end - if #button_eps > 0 and is_supported_combination_button_switch_device_type(device, main_endpoint) then + local is_supported_button_switch_device, device_type_id = is_supported_combination_button_switch_device_type(device, main_endpoint) + if is_supported_button_switch_device then + if device_type_id == DIMMABLE_LIGHT_DEVICE_TYPE_ID then + profile_name = "light-level" + else + profile_name = "plug" + end if #button_eps == 1 then - profile_name = "light-level-button" + profile_name = profile_name .. "-button" else - profile_name = "light-level" .. string.format("-%d-button", #button_eps) + profile_name = profile_name .. string.format("-%d-button", #button_eps) end device:try_update_metadata({profile = profile_name}) device:set_field(DEFERRED_CONFIGURE, true) 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 a5f2420557..70de16a682 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 @@ -153,6 +153,48 @@ local mock_device_mcd_unsupported_switch_device_type = test.mock_device.build_te } }) +local mock_device_plug_button = test.mock_device.build_test_matter_device({ + label = "Matter Switch", + profile = t_utils.get_profile_definition("plug-button.yml"), + manufacturer_info = { + vendor_id = 0x137F, + product_id = 0x027B, + }, + endpoints = { + { + endpoint_id = 0, + clusters = { + {cluster_id = clusters.Basic.ID, cluster_type = "SERVER", cluster_revision = 1, feature_map = 0}, + }, + device_types = { + {device_type_id = 0x0016, device_type_revision = 1} -- RootNode + } + }, + { + endpoint_id = 1, + clusters = { + {cluster_id = clusters.OnOff.ID, cluster_type = "SERVER", cluster_revision = 1, feature_map = 0}, + }, + device_types = { + {device_type_id = 0x010A, device_type_revision = 1} -- OnOff Plug + } + }, + { + endpoint_id = 2, + clusters = { + { + cluster_id = clusters.Switch.ID, + feature_map = clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH | clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH_RELEASE, + cluster_type = "SERVER" + }, + }, + device_types = { + {device_type_id = 0x000F, device_type_revision = 1} -- Generic Switch + } + } + } +}) + local child_profile = t_utils.get_profile_definition("light-color-level.yml") local child_data = { profile = child_profile, @@ -243,6 +285,34 @@ local function test_init_mcd_unsupported_switch_device_type() }) end +local function test_init_plug_button() + test.socket.matter:__set_channel_ordering("relaxed") + local cluster_subscribe_list = { + clusters.OnOff.attributes.OnOff, + clusters.Switch.server.events.InitialPress, + clusters.Switch.server.events.LongPress, + clusters.Switch.server.events.ShortRelease, + clusters.Switch.server.events.MultiPressComplete, + } + local subscribe_request = cluster_subscribe_list[1]:subscribe(mock_device_plug_button) + for i, clus in ipairs(cluster_subscribe_list) do + if i > 1 then subscribe_request:merge(clus:subscribe(mock_device_plug_button)) end + end + test.socket.matter:__expect_send({mock_device_plug_button.id, subscribe_request}) + test.mock_device.add_test_device(mock_device_plug_button) + test.socket.device_lifecycle:__queue_receive({ mock_device_plug_button.id, "added" }) + mock_device_plug_button:expect_metadata_update({ profile = "plug-button" }) + local device_info_copy = utils.deep_copy(mock_device_plug_button.raw_st_data) + device_info_copy.profile.id = "button" + local device_info_json = dkjson.encode(device_info_copy) + test.socket.device_lifecycle:__queue_receive({ mock_device_plug_button.id, "infoChanged", device_info_json }) + test.socket.matter:__expect_send({mock_device_plug_button.id, subscribe_request}) + test.socket.matter:__expect_send({mock_device_plug_button.id, subscribe_request}) + + test.socket.capability:__expect_send(mock_device_plug_button:generate_test_message("button", capabilities.button.supportedButtonValues({"pushed", "held"}, {visibility = {displayed = false}}))) + test.socket.capability:__expect_send(mock_device_plug_button:generate_test_message("button", button_attr.pushed({state_change = false}))) +end + test.set_test_init_function(test_init) test.register_message_test( @@ -410,5 +480,12 @@ test.register_coroutine_test( { test_init = test_init_mcd_unsupported_switch_device_type } ) +test.register_coroutine_test( + "Test initialization for plug/button device", + function() + end, + { test_init = test_init_plug_button } +) + -- run the tests test.run_registered_tests()