Skip to content

Commit ec112fe

Browse files
committed
update vendor overrides
1 parent af87419 commit ec112fe

File tree

7 files changed

+55
-163
lines changed

7 files changed

+55
-163
lines changed

drivers/SmartThings/matter-switch/src/generic_handlers/attribute_handlers.lua

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,8 +361,7 @@ function AttributeHandlers.power_source_attribute_list_handler(driver, device, i
361361
profile_name = string.format("%d-", #button_eps) .. profile_name
362362
end
363363

364-
if device.manufacturer_info.vendor_id == fields.AQARA_MANUFACTURER_ID and
365-
device.manufacturer_info.product_id == fields.AQARA_CLIMATE_SENSOR_W100_ID then
364+
if switch_utils.get_product_override_field(device, "is_climate_sensor_w100") then
366365
profile_name = profile_name .. "-temperature-humidity"
367366
end
368367
device:try_update_metadata({ profile = profile_name })

drivers/SmartThings/matter-switch/src/test/test_matter_bridge.lua

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,18 @@ end
8888
test.register_coroutine_test(
8989
"Profile should not change for devices with aggregator device type (bridges)",
9090
function()
91+
local subscribe_request = cluster_subscribe_list[1]:subscribe(mock_bridge)
92+
for i, cluster in ipairs(cluster_subscribe_list) do
93+
if i > 1 then
94+
subscribe_request:merge(cluster:subscribe(mock_bridge))
95+
end
96+
end
97+
test.socket.device_lifecycle:__queue_receive({ mock_bridge.id, "added" })
98+
test.socket.matter:__expect_send({mock_bridge.id, subscribe_request})
99+
test.socket.device_lifecycle:__queue_receive({ mock_bridge.id, "init" })
100+
test.socket.matter:__expect_send({mock_bridge.id, subscribe_request})
101+
test.socket.device_lifecycle:__queue_receive({ mock_bridge.id, "doConfigure" })
102+
mock_bridge:expect_metadata_update({ provisioning_state = "PROVISIONED" })
91103
end,
92104
{ test_init = test_init_mock_bridge }
93105
)

drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_lights.lua

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,11 +274,10 @@ local function test_init_parent_child_endpoints_non_sequential()
274274
parent_assigned_child_key = string.format("%d", child2_ep_non_sequential)
275275
})
276276

277-
-- switch-binary will be selected as an overridden child device profile
278277
mock_device_parent_child_endpoints_non_sequential:expect_device_create({
279278
type = "EDGE_CHILD",
280279
label = "Matter Switch 3",
281-
profile = "switch-binary",
280+
profile = "plug-binary",
282281
parent_device_id = mock_device_parent_child_endpoints_non_sequential.id,
283282
parent_assigned_child_key = string.format("%d", child3_ep_non_sequential)
284283
})

drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_plugs.lua

Lines changed: 0 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ local clusters = require "st.matter.clusters"
2020
test.disable_startup_messages()
2121

2222
local child_profile = t_utils.get_profile_definition("plug-binary.yml")
23-
local child_profile_override = t_utils.get_profile_definition("switch-binary.yml")
2423
local parent_ep = 10
2524
local child1_ep = 20
2625
local child2_ep = 30
@@ -72,53 +71,6 @@ local mock_device = test.mock_device.build_test_matter_device({
7271
}
7372
})
7473

75-
local mock_device_child_profile_override = test.mock_device.build_test_matter_device({
76-
label = "Matter Switch",
77-
profile = t_utils.get_profile_definition("switch-binary.yml"),
78-
manufacturer_info = {
79-
vendor_id = 0x1321,
80-
product_id = 0x000D,
81-
},
82-
endpoints = {
83-
{
84-
endpoint_id = 0,
85-
clusters = {
86-
{cluster_id = clusters.Basic.ID, cluster_type = "SERVER"},
87-
},
88-
device_types = {
89-
{device_type_id = 0x0016, device_type_revision = 1} -- RootNode
90-
}
91-
},
92-
{
93-
endpoint_id = parent_ep,
94-
clusters = {
95-
{cluster_id = clusters.OnOff.ID, cluster_type = "SERVER"},
96-
},
97-
device_types = {
98-
{device_type_id = 0x010A, device_type_revision = 2} -- On/Off Plug
99-
}
100-
},
101-
{
102-
endpoint_id = child1_ep,
103-
clusters = {
104-
{cluster_id = clusters.OnOff.ID, cluster_type = "SERVER"},
105-
},
106-
device_types = {
107-
{device_type_id = 0x010A, device_type_revision = 2} -- On/Off Plug
108-
}
109-
},
110-
{
111-
endpoint_id = child2_ep,
112-
clusters = {
113-
{cluster_id = clusters.OnOff.ID, cluster_type = "SERVER"},
114-
},
115-
device_types = {
116-
{device_type_id = 0x010A, device_type_revision = 2} -- On/Off Plug
117-
}
118-
},
119-
}
120-
})
121-
12274
local mock_children = {}
12375
for i, endpoint in ipairs(mock_device.endpoints) do
12476
if endpoint.endpoint_id ~= parent_ep and endpoint.endpoint_id ~= 0 then
@@ -169,56 +121,6 @@ local function test_init()
169121
})
170122
end
171123

172-
local mock_children_child_profile_override = {}
173-
for i, endpoint in ipairs(mock_device_child_profile_override.endpoints) do
174-
if endpoint.endpoint_id ~= parent_ep and endpoint.endpoint_id ~= 0 then
175-
local child_data = {
176-
profile = child_profile_override,
177-
device_network_id = string.format("%s:%d", mock_device_child_profile_override.id, endpoint.endpoint_id),
178-
parent_device_id = mock_device_child_profile_override.id,
179-
parent_assigned_child_key = string.format("%d", endpoint.endpoint_id)
180-
}
181-
mock_children_child_profile_override[endpoint.endpoint_id] = test.mock_device.build_test_child_device(child_data)
182-
end
183-
end
184-
185-
local function test_init_child_profile_override()
186-
test.mock_device.add_test_device(mock_device_child_profile_override)
187-
local cluster_subscribe_list = {
188-
clusters.OnOff.attributes.OnOff,
189-
}
190-
local subscribe_request = cluster_subscribe_list[1]:subscribe(mock_device_child_profile_override)
191-
192-
test.socket.device_lifecycle:__queue_receive({ mock_device_child_profile_override.id, "added" })
193-
test.socket.matter:__expect_send({mock_device_child_profile_override.id, subscribe_request})
194-
195-
test.socket.device_lifecycle:__queue_receive({ mock_device_child_profile_override.id, "init" })
196-
test.socket.matter:__expect_send({mock_device_child_profile_override.id, subscribe_request})
197-
198-
test.socket.device_lifecycle:__queue_receive({ mock_device_child_profile_override.id, "doConfigure" })
199-
mock_device_child_profile_override:expect_metadata_update({ provisioning_state = "PROVISIONED" })
200-
201-
for _, child in pairs(mock_children_child_profile_override) do
202-
test.mock_device.add_test_device(child)
203-
end
204-
205-
mock_device:expect_device_create({
206-
type = "EDGE_CHILD",
207-
label = "Matter Switch 2",
208-
profile = "switch-binary",
209-
parent_device_id = mock_device_child_profile_override.id,
210-
parent_assigned_child_key = string.format("%d", child1_ep)
211-
})
212-
213-
mock_device:expect_device_create({
214-
type = "EDGE_CHILD",
215-
label = "Matter Switch 3",
216-
profile = "switch-binary",
217-
parent_device_id = mock_device_child_profile_override.id,
218-
parent_assigned_child_key = string.format("%d", child2_ep)
219-
})
220-
end
221-
222124
test.set_test_init_function(test_init)
223125

224126
test.register_message_test(
@@ -383,10 +285,4 @@ test.register_coroutine_test(
383285
end
384286
)
385287

386-
test.register_coroutine_test(
387-
"Child device profiles should be overriden for specific devices", function()
388-
end,
389-
{ test_init = test_init_child_profile_override }
390-
)
391-
392288
test.run_registered_tests()

drivers/SmartThings/matter-switch/src/utils/device_configuration.lua

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,9 @@ function SwitchDeviceConfiguration.assign_child_profile(device, child_ep)
5050
end
5151
end
5252

53-
-- Check if device has an overridden child profile that differs from the profile that would match
54-
-- the child's device type for the following two cases:
55-
-- 1. To add Electrical Sensor only to the first EDGE_CHILD (light-power-energy-powerConsumption)
56-
-- for the Aqara Light Switch H2. The profile of the second EDGE_CHILD for this device is
57-
-- determined in the "for" loop above (e.g., light-binary)
58-
-- 2. The selected profile for the child device matches the initial profile defined in
59-
-- child_device_profile_overrides
60-
for id, vendor in pairs(fields.child_device_profile_overrides_per_vendor_id) do
61-
for _, fingerprint in ipairs(vendor) do
62-
if device.manufacturer_info.product_id == fingerprint.product_id and
63-
((device.manufacturer_info.vendor_id == fields.AQARA_MANUFACTURER_ID and child_ep == 1) or profile == fingerprint.initial_profile) then
64-
return fingerprint.target_profile
65-
end
66-
end
53+
-- workaround: Aqara Light Switch H2: add Electrical Sensor profile only to the first EDGE_CHILD
54+
if child_ep == 1 then
55+
profile = switch_utils.get_product_override_field(device, "target_profile") or profile
6756
end
6857

6958
-- default to "switch-binary" if no profile is found

drivers/SmartThings/matter-switch/src/utils/switch_fields.lua

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -106,19 +106,16 @@ SwitchFields.HUE_SAT_COLOR_MODE = clusters.ColorControl.types.ColorMode.CURRENT_
106106
SwitchFields.X_Y_COLOR_MODE = clusters.ColorControl.types.ColorMode.CURRENTX_AND_CURRENTY
107107

108108

109-
SwitchFields.child_device_profile_overrides_per_vendor_id = {
110-
[0x1321] = {
111-
{ product_id = 0x000C, target_profile = "switch-binary", initial_profile = "plug-binary" },
112-
{ product_id = 0x000D, target_profile = "switch-binary", initial_profile = "plug-binary" },
113-
},
114-
[0x115F] = {
115-
{ product_id = 0x1003, target_profile = "light-power-energy-powerConsumption" }, -- 2 Buttons(Generic Switch), 1 Channel(On/Off Light)
116-
{ product_id = 0x1004, target_profile = "light-power-energy-powerConsumption" }, -- 2 Buttons(Generic Switch), 2 Channels(On/Off Light)
117-
{ product_id = 0x1005, target_profile = "light-power-energy-powerConsumption" }, -- 4 Buttons(Generic Switch), 3 Channels(On/Off Light)
118-
{ product_id = 0x1006, target_profile = "light-level-power-energy-powerConsumption" }, -- 3 Buttons(Generic Switch), 1 Channels(Dimmable Light)
119-
{ product_id = 0x1008, target_profile = "light-power-energy-powerConsumption" }, -- 2 Buttons(Generic Switch), 1 Channel(On/Off Light)
120-
{ product_id = 0x1009, target_profile = "light-power-energy-powerConsumption" }, -- 4 Buttons(Generic Switch), 2 Channels(On/Off Light)
121-
{ product_id = 0x100A, target_profile = "light-level-power-energy-powerConsumption" }, -- 1 Buttons(Generic Switch), 1 Channels(Dimmable Light)
109+
SwitchFields.vendor_overrides = {
110+
[0x115F] = { -- AQARA_MANUFACTURER_ID
111+
[0x1003] = { target_profile = "light-power-energy-powerConsumption" }, -- 2 Buttons(Generic Switch), 1 Channel(On/Off Light)
112+
[0x1004] = { target_profile = "light-power-energy-powerConsumption" }, -- 2 Buttons(Generic Switch), 2 Channels(On/Off Light)
113+
[0x1005] = { target_profile = "light-power-energy-powerConsumption" }, -- 4 Buttons(Generic Switch), 3 Channels(On/Off Light)
114+
[0x1008] = { target_profile = "light-power-energy-powerConsumption" }, -- 2 Buttons(Generic Switch), 1 Channel(On/Off Light)
115+
[0x1009] = { target_profile = "light-power-energy-powerConsumption" }, -- 4 Buttons(Generic Switch), 2 Channels(On/Off Light)
116+
[0x1006] = { ignore_combo_switch_button = true, target_profile = "light-level-power-energy-powerConsumption" }, -- 3 Buttons(Generic Switch), 1 Channels(Dimmable Light)
117+
[0x100A] = { ignore_combo_switch_button = true, target_profile = "light-level-power-energy-powerConsumption" }, -- 1 Buttons(Generic Switch), 1 Channels(Dimmable Light)
118+
[0x2004] = { is_climate_sensor_w100 = true }, -- Climate Sensor W100, requires unique profile
122119
}
123120
}
124121

@@ -150,9 +147,6 @@ SwitchFields.TEMP_BOUND_RECEIVED = "__temp_bound_received"
150147
SwitchFields.TEMP_MIN = "__temp_min"
151148
SwitchFields.TEMP_MAX = "__temp_max"
152149

153-
SwitchFields.AQARA_MANUFACTURER_ID = 0x115F
154-
SwitchFields.AQARA_CLIMATE_SENSOR_W100_ID = 0x2004
155-
156150
SwitchFields.TRANSITION_TIME = 0 --1/10ths of a second
157151
-- When sent with a command, these options mask and override bitmaps cause the command
158152
-- to take effect when the switch/light is off.

drivers/SmartThings/matter-switch/src/utils/switch_utils.lua

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ function utils.mired_to_kelvin(value, minOrMax)
6363
end
6464
end
6565

66+
function utils.get_product_override_field(device, override_key)
67+
if fields.vendor_overrides[device.manufacturer_info.vendor_id]
68+
and fields.vendor_overrides[device.manufacturer_info.vendor_id][device.manufacturer_info.product_id]
69+
then
70+
return fields.vendor_overrides[device.manufacturer_info.vendor_id][device.manufacturer_info.product_id][override_key]
71+
end
72+
end
73+
6674
function utils.check_field_name_updates(device)
6775
for _, field in ipairs(fields.updated_fields) do
6876
if device:get_field(field.current_field_name) then
@@ -78,29 +86,18 @@ end
7886
--- whether the device type for an endpoint is currently supported by a profile for
7987
--- combination button/switch devices.
8088
function utils.device_type_supports_button_switch_combination(device, endpoint_id)
81-
for _, ep in ipairs(device.endpoints) do
82-
if ep.endpoint_id == endpoint_id then
83-
for _, dt in ipairs(ep.device_types) do
84-
if dt.device_type_id == fields.DIMMABLE_LIGHT_DEVICE_TYPE_ID then
85-
for _, fingerprint in ipairs(fields.child_device_profile_overrides_per_vendor_id[0x115F]) do
86-
if device.manufacturer_info.product_id == fingerprint.product_id then
87-
return false -- For Aqara Dimmer Switch with Button.
88-
end
89-
end
90-
return true
91-
end
92-
end
93-
end
89+
if utils.get_product_override_field(device, "ignore_combo_switch_button") then
90+
return false
9491
end
95-
return false
92+
local dimmable_eps = utils.get_endpoints_by_device_type(device, fields.DIMMABLE_LIGHT_DEVICE_TYPE_ID)
93+
return utils.tbl_contains(dimmable_eps, endpoint_id)
9694
end
9795

9896
--- find_default_endpoint is a helper function to handle situations where
9997
--- device does not have endpoint ids in sequential order from 1
10098
function utils.find_default_endpoint(device)
101-
if device.manufacturer_info.vendor_id == fields.AQARA_MANUFACTURER_ID and
102-
device.manufacturer_info.product_id == fields.AQARA_CLIMATE_SENSOR_W100_ID then
103-
-- In case of Aqara Climate Sensor W100, in order to sequentially set the button name to button 1, 2, 3
99+
-- Buttons should not be set on the main component for the Aqara Climate Sensor W100,
100+
if utils.get_product_override_field(device, "is_climate_sensor_w100") then
104101
return device.MATTER_DEFAULT_ENDPOINT
105102
end
106103

@@ -171,6 +168,19 @@ function utils.matter_handler(driver, device, response_block)
171168
device.log.info(string.format("Fallback handler for %s", response_block))
172169
end
173170

171+
-- get a list of endpoints for a specified device type.
172+
function utils.get_endpoints_by_device_type(device, device_type_id)
173+
local dt_eps = {}
174+
for _, ep in ipairs(device.endpoints) do
175+
for _, dt in ipairs(ep.device_types) do
176+
if dt.device_type_id == device_type_id then
177+
table.insert(dt_eps, ep.endpoint_id)
178+
end
179+
end
180+
end
181+
return dt_eps
182+
end
183+
174184
--helper function to create list of multi press values
175185
function utils.create_multi_press_values_list(size, supportsHeld)
176186
local list = {"pushed", "double"}
@@ -183,14 +193,7 @@ function utils.create_multi_press_values_list(size, supportsHeld)
183193
end
184194

185195
function utils.detect_bridge(device)
186-
for _, ep in ipairs(device.endpoints) do
187-
for _, dt in ipairs(ep.device_types) do
188-
if dt.device_type_id == fields.AGGREGATOR_DEVICE_TYPE_ID then
189-
return true
190-
end
191-
end
192-
end
193-
return false
196+
return #utils.get_endpoints_by_device_type(device, fields.AGGREGATOR_DEVICE_TYPE_ID) > 0
194197
end
195198

196199
function utils.detect_matter_thing(device)

0 commit comments

Comments
 (0)