Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rolling main up to beta #1397

Merged
merged 5 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()
Loading