Skip to content

Commit

Permalink
Merge pull request #1397 from SmartThingsCommunity/main
Browse files Browse the repository at this point in the history
Rolling main up to beta
  • Loading branch information
ctowns authored May 29, 2024
2 parents cd86169 + d926e86 commit 556a341
Show file tree
Hide file tree
Showing 3 changed files with 333 additions and 10 deletions.
27 changes: 26 additions & 1 deletion drivers/SmartThings/matter-switch/fingerprints.yml
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,22 @@ matterManufacturer:
vendorId: 0x1339
productId: 0x006F
deviceProfileName: plug-binary

#Legrand
- id: "4129/3"
deviceLabel: Smart Lights Smart Plug
vendorId: 0x1021
productId: 0x0003
deviceProfileName: plug-binary
- id: "4129/4"
deviceLabel: Smart Lights Outdoor Plug
vendorId: 0x1021
productId: 0x0004
deviceProfileName: plug-binary
- id: "4129/7"
deviceLabel: Radiant Smart Receptacle
vendorId: 0x1021
productId: 0x0007
deviceProfileName: plug-binary
#Lifx
- id: "5155/169"
deviceLabel: LIFX Color (A21)
Expand Down Expand Up @@ -203,6 +218,16 @@ matterManufacturer:
vendorId: 0x115A
productId: 0x711
deviceProfileName: light-color-level-2700K-6500K
- id: "4442/72"
deviceLabel: Essentials Indoor Lights
vendorId: 0x115A
productId: 0x0048
deviceProfileName: light-color-level-2700K-6500K
- id: "4442/73"
deviceLabel: Essentials Outdoor Lights
vendorId: 0x115A
productId: 0x0049
deviceProfileName: light-color-level-2700K-6500K
#SONOFF
- id: "SONOFF MINIR4M"
deviceLabel: Smart Plug-in Unit
Expand Down
39 changes: 30 additions & 9 deletions drivers/SmartThings/matter-switch/src/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,19 @@ local COLOR_TEMP_LIGHT_DEVICE_TYPE_ID = 0x010C
local EXTENDED_COLOR_LIGHT_DEVICE_TYPE_ID = 0x010D
local ON_OFF_PLUG_DEVICE_TYPE_ID = 0x010A
local DIMMABLE_PLUG_DEVICE_TYPE_ID = 0x010B
local ON_OFF_SWITCH_ID = 0x0103
local ON_OFF_DIMMER_SWITCH_ID = 0x0104
local ON_OFF_COLOR_DIMMER_SWITCH_ID = 0x0105
local device_type_profile_map = {
[ON_OFF_LIGHT_DEVICE_TYPE_ID] = "light-binary",
[DIMMABLE_LIGHT_DEVICE_TYPE_ID] = "light-level",
[COLOR_TEMP_LIGHT_DEVICE_TYPE_ID] = "light-level-colorTemperature",
[EXTENDED_COLOR_LIGHT_DEVICE_TYPE_ID] = "light-color-level",
[ON_OFF_PLUG_DEVICE_TYPE_ID] = "plug-binary",
[DIMMABLE_PLUG_DEVICE_TYPE_ID] = "plug-level"
[DIMMABLE_PLUG_DEVICE_TYPE_ID] = "plug-level",
[ON_OFF_SWITCH_ID] = "switch-binary",
[ON_OFF_DIMMER_SWITCH_ID] = "switch-level",
[ON_OFF_COLOR_DIMMER_SWITCH_ID] = "switch-color-level",
}
local detect_matter_thing

Expand Down Expand Up @@ -124,7 +130,6 @@ end
local function initialize_switch(driver, device)
local switch_eps = device:get_endpoints(clusters.OnOff.ID)
table.sort(switch_eps)

-- Since we do not support bindings at the moment, we only want to count On/Off
-- clusters that have been implemented as server. This can be removed when we have
-- support for bindings.
Expand Down Expand Up @@ -158,15 +163,31 @@ local function initialize_switch(driver, device)
end

device:set_field(SWITCH_INITIALIZED, true)
-- The case where num_server_eps > 0 is a workaround for devices that have the On/Off
-- The case where num_server_eps > 0 is a workaround for devices that have a
-- Light Switch device type but implement the On Off cluster as server (which is against the spec
-- for this device type). By default, we do not support On/Off Light Switch because by spec these
-- devices need bindings to work correctly (On/Off cluster is client in this case), so this device type
-- does not have a generic fingerprint and will join as a matter-thing. However, we have
-- seen some devices claim to be On/Off Light Switch device type and still implement On/Off server, so this
-- is a workaround for those devices.
-- for this device type). By default, we do not support Light Switch device types because by spec these
-- devices need bindings to work correctly (On/Off cluster is client in this case), so these device types
-- do not have a generic fingerprint and will join as a matter-thing. However, we have seen some devices
-- claim to be Light Switch device types and still implement their clusters as server, so this is a
-- workaround for those devices.
if num_server_eps > 0 and detect_matter_thing(device) == true then
device:try_update_metadata({profile = "switch-binary"})
local id = 0
for _, ep in ipairs(device.endpoints) do
-- main_endpoint only supports server cluster by definition of get_endpoints()
if main_endpoint == ep.endpoint_id then
for _, dt in ipairs(ep.device_types) do
-- no device type that is not in the switch subset should be considered.
if (ON_OFF_SWITCH_ID <= dt.device_type_id and dt.device_type_id <= ON_OFF_COLOR_DIMMER_SWITCH_ID) then
id = math.max(id, dt.device_type_id)
end
end
break
end
end

if device_type_profile_map[id] ~= nil then
device:try_update_metadata({profile = device_type_profile_map[id]})
end
end
end

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
local test = require "integration_test"
local t_utils = require "integration_test.utils"

local clusters = require "st.matter.clusters"

local mock_device_onoff = test.mock_device.build_test_matter_device({
profile = t_utils.get_profile_definition("matter-thing.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 = 1,
clusters = {
{cluster_id = clusters.OnOff.ID, cluster_type = "SERVER", cluster_revision = 1, feature_map = 0},
},
device_types = {
{device_type_id = 0x0103, device_type_revision = 1} -- On/Off Light Switch
}
}
}
})

local mock_device_onoff_client = test.mock_device.build_test_matter_device({
profile = t_utils.get_profile_definition("matter-thing.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 = 1,
clusters = {
{cluster_id = clusters.OnOff.ID, cluster_type = "CLIENT", cluster_revision = 1, feature_map = 0},
},
device_types = {
{device_type_id = 0x0103, device_type_revision = 1} -- On/Off Light Switch
}
}
}
})

local mock_device_dimmer = test.mock_device.build_test_matter_device({
profile = t_utils.get_profile_definition("matter-thing.yml"),
manufacturer_info = {
vendor_id = 0x0000,
product_id = 0x0000,
},
endpoints = {
{
endpoint_id = 5,
clusters = {
{cluster_id = clusters.Basic.ID, cluster_type = "SERVER"},
},
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},
{cluster_id = clusters.LevelControl.ID, cluster_type = "SERVER", feature_map = 2}
},
device_types = {
{device_type_id = 0x0104, device_type_revision = 1} -- Dimmer Switch
}
}
}
})

local mock_device_color_dimmer = test.mock_device.build_test_matter_device({
profile = t_utils.get_profile_definition("matter-thing.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 = 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.ColorControl.ID, cluster_type = "CLIENT", feature_map = 31},

},
device_types = {
{device_type_id = 0x0105, device_type_revision = 1} -- Color Dimmer Switch
}
}
}
})

local mock_device_parent_client_child_server = test.mock_device.build_test_matter_device({
profile = t_utils.get_profile_definition("matter-thing.yml"),
manufacturer_info = {
vendor_id = 0x0000,
product_id = 0x0000,
},
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 = 7,
clusters = {
{cluster_id = clusters.OnOff.ID, cluster_type = "SERVER", cluster_revision = 1, feature_map = 0},
},
device_types = {
{device_type_id = 0x0103, device_type_revision = 1} -- OnOff Switch
}
},
{
endpoint_id = 10,
clusters = {
{cluster_id = clusters.OnOff.ID, cluster_type = "CLIENT", cluster_revision = 1, feature_map = 0},
},
device_types = {
{device_type_id = 0x0103, device_type_revision = 1} -- OnOff Switch
}
},
}
})

local mock_device_parent_child_switch_types = test.mock_device.build_test_matter_device({
label = "Matter Switch",
profile = t_utils.get_profile_definition("matter-thing.yml"),
manufacturer_info = {
vendor_id = 0x0000,
product_id = 0x0000,
},
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 = 7,
clusters = {
{cluster_id = clusters.OnOff.ID, cluster_type = "SERVER", cluster_revision = 1, feature_map = 0},
{cluster_id = clusters.LevelControl.ID, cluster_type = "SERVER", feature_map = 2}
},
device_types = {
{device_type_id = 0x0104, device_type_revision = 1} -- Dimmer Switch
}
},
{
endpoint_id = 10,
clusters = {
{cluster_id = clusters.OnOff.ID, cluster_type = "SERVER", cluster_revision = 1, feature_map = 0},
},
device_types = {
{device_type_id = 0x0103, device_type_revision = 1} -- OnOff Switch
}
},
}
})

local function test_init_parent_child_switch_types()
test.mock_device.add_test_device(mock_device_parent_child_switch_types)
mock_device_parent_child_switch_types:expect_metadata_update({ profile = "switch-level" })

mock_device_parent_child_switch_types:expect_device_create({
type = "EDGE_CHILD",
label = "Matter Switch 2",
profile = "switch-binary",
parent_device_id = mock_device_parent_child_switch_types.id,
parent_assigned_child_key = string.format("%d", 10)
})
end

local function test_init_onoff()
test.mock_device.add_test_device(mock_device_onoff)
mock_device_onoff:expect_metadata_update({ profile = "switch-binary" })
end

local function test_init_onoff_client()
test.mock_device.add_test_device(mock_device_onoff_client)
end

local function test_init_parent_client_child_server()
test.mock_device.add_test_device(mock_device_parent_client_child_server)
mock_device_parent_client_child_server:expect_metadata_update({ profile = "switch-binary" })
end

local function test_init_dimmer()
test.mock_device.add_test_device(mock_device_dimmer)
mock_device_dimmer:expect_metadata_update({ profile = "switch-level" })
end

local function test_init_color_dimmer()
test.mock_device.add_test_device(mock_device_color_dimmer)
mock_device_color_dimmer:expect_metadata_update({ profile = "switch-color-level" })
end

test.register_coroutine_test(
"Test profile change on init for onoff parent cluster as server",
function()
end,
{ test_init = test_init_onoff }
)

test.register_coroutine_test(
"Test profile change on init for dimmer parent cluster as server",
function()
end,
{ test_init = test_init_dimmer }
)

test.register_coroutine_test(
"Test profile change on init for color dimmer parent cluster as server",
function()
end,
{ test_init = test_init_color_dimmer }
)

test.register_coroutine_test(
"Test profile change on init for onoff parent cluster as client",
function()
end,
{ test_init = test_init_onoff_client }
)

test.register_coroutine_test(
"Test profile change on init for onoff parent cluster as client and onoff child as server",
function()
end,
{ test_init = test_init_parent_client_child_server }
)

test.register_coroutine_test(
"Test profile change on init for onoff device when parent and child are both server",
function()
end,
{ test_init = test_init_parent_child_switch_types }
)

test.run_registered_tests()

0 comments on commit 556a341

Please sign in to comment.