Skip to content

Commit 130c39d

Browse files
Add method of inserting to front of capability list based on device type
1 parent 33be062 commit 130c39d

File tree

3 files changed

+51
-40
lines changed

3 files changed

+51
-40
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,13 @@ local function supports_modular_profile(device)
322322
if not modular_profiles_supported then
323323
device:set_field(SUPPORTS_MODULAR_PROFILE, false)
324324
return false
325-
elseif device:get_field(SUPPORTS_MODULAR_PROFILE) then -- if we've already determined the device supports modular profiles, then there is no need to check the device category again
325+
elseif device:get_field(SUPPORTS_MODULAR_PROFILE) then
326+
-- If we've already determined the device supports modular profiles, then there is
327+
-- no need to check the device category again
326328
return true
327329
end
328330
local main_endpoint = common_utils.find_default_endpoint(device)
331+
-- Lights are not currently supported by modular profiles because modular profiles do not currently work with lighting groups
329332
modular_profiles_supported = common_utils.get_device_category(device, main_endpoint) ~= common_utils.device_categories.LIGHT
330333
device:set_field(SUPPORTS_MODULAR_PROFILE, modular_profiles_supported)
331334
return modular_profiles_supported

drivers/SmartThings/matter-switch/src/modular-profiles-utils.lua

Lines changed: 46 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,11 @@ local modular_profiles_utils = {}
2121

2222
modular_profiles_utils.SUPPORTED_COMPONENT_CAPABILITIES = "__supported_component_capabilities"
2323

24-
2524
local profile_name_and_mandatory_capability_per_device_category = {
26-
[common_utils.device_categories.BUTTON] = { profile_name = "button-modular", mandatory_capability = capabilities.button.ID },
27-
[common_utils.device_categories.LIGHT] = { profile_name = "light-modular", mandatory_capability = capabilities.switch.ID },
28-
[common_utils.device_categories.PLUG] = { profile_name = "plug-modular", mandatory_capability = capabilities.switch.ID },
29-
[common_utils.device_categories.SWITCH] = { profile_name = "switch-modular", mandatory_capability = capabilities.valve.ID },
25+
[common_utils.device_categories.BUTTON] = { profile_name = "button-modular", mandatory_capability = capabilities.button.ID },
26+
[common_utils.device_categories.LIGHT] = { profile_name = "light-modular", mandatory_capability = capabilities.switch.ID },
27+
[common_utils.device_categories.PLUG] = { profile_name = "plug-modular", mandatory_capability = capabilities.switch.ID },
28+
[common_utils.device_categories.SWITCH] = { profile_name = "switch-modular", mandatory_capability = capabilities.valve.ID },
3029
[common_utils.device_categories.WATER_VALVE] = { profile_name = "water-valve-modular", mandatory_capability = capabilities.switch.ID }
3130
}
3231

@@ -61,7 +60,7 @@ local function add_button_capabilities(device, category, main_endpoint, main_com
6160
-- button-modular profile uses 'main', 'button2', button3', ... as component names.
6261
-- Other profiles use 'main', 'button', 'button2', etc
6362
if component_num == 1 and category == common_utils.device_categories.BUTTON then
64-
table.insert(main_component_capabilities, capabilities.button.ID)
63+
table.insert(main_component_capabilities, 1, capabilities.button.ID)
6564
if battery_attr_support then
6665
add_battery_capability(main_component_capabilities, battery_attr_support)
6766
end
@@ -85,10 +84,10 @@ end
8584
local function handle_light_switch_with_onOff_server_clusters(device, main_endpoint, component_capabilities)
8685
local device_type_id = 0
8786
for _, ep in ipairs(device.endpoints) do
88-
-- main_endpoint only supports server cluster by definition of get_endpoints()
87+
-- The main endpoint only supports server cluster by definition of get_endpoints()
8988
if main_endpoint == ep.endpoint_id then
9089
for _, dt in ipairs(ep.device_types) do
91-
-- no device type that is not in the switch subset should be considered.
90+
-- No device type that is not in the switch subset should be considered
9291
if (common_utils.ON_OFF_SWITCH_ID <= dt.device_type_id and dt.device_type_id <= common_utils.ON_OFF_COLOR_DIMMER_SWITCH_ID) then
9392
device_type_id = math.max(device_type_id, dt.device_type_id)
9493
end
@@ -124,15 +123,23 @@ local function handle_light_switch_with_onOff_server_clusters(device, main_endpo
124123
end
125124
end
126125

126+
local function optionally_insert_to_position(insert_to_position, component_capabilities, capability_id, position)
127+
if insert_to_position then
128+
table.insert(component_capabilities, position, capability_id)
129+
else
130+
table.insert(component_capabilities, capability_id)
131+
end
132+
end
133+
127134
local function match_modular_profile(driver, device, battery_attr_support)
128135
local main_endpoint = common_utils.find_default_endpoint(device)
136+
local switch_eps = device:get_endpoints(clusters.OnOff.ID)
137+
local level_eps = device:get_endpoints(clusters.LevelControl.ID)
129138
local color_hs_eps = device:get_endpoints(clusters.ColorControl.ID, {feature_bitmap = clusters.ColorControl.types.Feature.HS})
130139
local color_xy_eps = device:get_endpoints(clusters.ColorControl.ID, {feature_bitmap = clusters.ColorControl.types.Feature.XY})
131140
local color_temp_eps = device:get_endpoints(clusters.ColorControl.ID, {feature_bitmap = clusters.ColorControl.types.Feature.CT})
132-
local level_eps = device:get_endpoints(clusters.LevelControl.ID)
133141
local power_eps = device:get_endpoints(clusters.ElectricalPowerMeasurement.ID)
134142
local energy_eps = device:get_endpoints(clusters.ElectricalEnergyMeasurement.ID)
135-
local switch_eps = device:get_endpoints(clusters.OnOff.ID)
136143
local fan_eps = device:get_endpoints(clusters.FanControl.ID)
137144
local humidity_eps = device:get_endpoints(clusters.RelativeHumidityMeasurement.ID)
138145
local temperature_eps = device:get_endpoints(clusters.TemperatureMeasurement.ID)
@@ -146,10 +153,28 @@ local function match_modular_profile(driver, device, battery_attr_support)
146153

147154
local MAIN_COMPONENT_IDX, CAPABILITIES_LIST_IDX = 1, 2
148155

149-
add_button_capabilities(device, category, main_endpoint, main_component_capabilities, extra_component_capabilities, battery_attr_support)
156+
if #switch_eps > 0 then
157+
-- If the device is a Button or Water Valve, add the switch capability since it is not a mandatory
158+
-- capability for these device types
159+
if category == common_utils.device_categories.BUTTON or category == common_utils.device_categories.WATER_VALVE then
160+
table.insert(main_component_capabilities, capabilities.switch.ID)
161+
end
162+
-- Without support for bindings, only clusters that are implemented as server are counted. This count is handled
163+
-- while building switch child profiles
164+
local num_switch_server_eps = common_utils.build_child_switch_profiles(driver, device, main_endpoint)
165+
-- Ensure that the proper capabilities are included for Light Switch device types that implement the OnOff
166+
-- cluster as 'server'
167+
if num_switch_server_eps > 0 and common_utils.detect_matter_thing(device) then
168+
handle_light_switch_with_onOff_server_clusters(device, main_endpoint, main_component_capabilities)
169+
end
170+
end
150171

151172
-- Only add capabilities related to lights if the corresponding cluster is
152173
-- implemented on the main endpoint. Otherwise, it will be added as a child device.
174+
if common_utils.tbl_contains(level_eps, main_endpoint) then
175+
table.insert(main_component_capabilities, capabilities.switchLevel.ID)
176+
end
177+
153178
if common_utils.tbl_contains(color_hs_eps, main_endpoint) or common_utils.tbl_contains(color_xy_eps, main_endpoint) then
154179
table.insert(main_component_capabilities, capabilities.colorControl.ID)
155180
end
@@ -158,10 +183,6 @@ local function match_modular_profile(driver, device, battery_attr_support)
158183
table.insert(main_component_capabilities, capabilities.colorTemperature.ID)
159184
end
160185

161-
if common_utils.tbl_contains(level_eps, main_endpoint) then
162-
table.insert(main_component_capabilities, capabilities.switchLevel.ID)
163-
end
164-
165186
if #power_eps > 0 then
166187
table.insert(main_component_capabilities, capabilities.powerMeter.ID)
167188
end
@@ -171,27 +192,6 @@ local function match_modular_profile(driver, device, battery_attr_support)
171192
table.insert(main_component_capabilities, capabilities.powerConsumptionReport.ID)
172193
end
173194

174-
if #switch_eps > 0 then
175-
-- If the device is a Button or Water Valve, add the switch capability since
176-
-- it is not a mandatory capability for these device types.
177-
if category == common_utils.device_categories.BUTTON or category == common_utils.device_categories.WATER_VALVE then
178-
table.insert(main_component_capabilities, capabilities.switch.ID)
179-
end
180-
-- Without support for bindings, only clusters that are implemented as server are counted. This count is handled
181-
-- while building switch child profiles
182-
local num_switch_server_eps = common_utils.build_child_switch_profiles(driver, device, main_endpoint)
183-
-- Ensure that the proper capabilities are included for Light Switch device types that implement the OnOff
184-
-- cluster as 'server'
185-
if num_switch_server_eps > 0 and common_utils.detect_matter_thing(device) then
186-
handle_light_switch_with_onOff_server_clusters(device, main_endpoint, main_component_capabilities)
187-
end
188-
end
189-
190-
if #fan_eps > 0 then
191-
table.insert(main_component_capabilities, capabilities.fanMode.ID)
192-
table.insert(main_component_capabilities, capabilities.fanSpeedPercent.ID)
193-
end
194-
195195
if #humidity_eps > 0 then
196196
table.insert(main_component_capabilities, capabilities.relativeHumidityMeasurement.ID)
197197
end
@@ -200,14 +200,22 @@ local function match_modular_profile(driver, device, battery_attr_support)
200200
table.insert(main_component_capabilities, capabilities.temperatureMeasurement.ID)
201201
end
202202

203+
if #fan_eps > 0 then
204+
table.insert(main_component_capabilities, capabilities.fanMode.ID)
205+
table.insert(main_component_capabilities, capabilities.fanSpeedPercent.ID)
206+
end
207+
203208
if #valve_eps > 0 then
204-
table.insert(main_component_capabilities, capabilities.valve.ID)
209+
local is_a_valve = category == common_utils.device_categories.WATER_VALVE
210+
optionally_insert_to_position(is_a_valve, main_component_capabilities, capabilities.valve.ID, 1)
205211
if #device:get_endpoints(clusters.ValveConfigurationAndControl.ID,
206212
{feature_bitmap = clusters.ValveConfigurationAndControl.types.Feature.LEVEL}) > 0 then
207-
table.insert(main_component_capabilities, capabilities.level.ID)
213+
optionally_insert_to_position(is_a_valve, main_component_capabilities, capabilities.level.ID, 2)
208214
end
209215
end
210216

217+
add_button_capabilities(device, category, main_endpoint, main_component_capabilities, extra_component_capabilities, battery_attr_support)
218+
211219
table.insert(optional_supported_component_capabilities, {"main", main_component_capabilities})
212220
for _, component_capability in ipairs(extra_component_capabilities) do
213221
table.insert(optional_supported_component_capabilities, component_capability)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ local function test_init()
8282
test.mock_device.add_test_device(mock_device)
8383
test.socket.device_lifecycle:__queue_receive({ mock_device.id, "doConfigure" })
8484
local optional_component_capabilities = {
85-
{ "main", { "colorControl", "colorTemperature", "switchLevel", "switch", "valve", "level" } }
85+
{ "main", { "valve", "level", "switch", "switchLevel", "colorControl", "colorTemperature" } }
8686
}
8787
if version.api >= 14 then
8888
mock_device:expect_metadata_update({ profile = "water-valve-modular", optional_component_capabilities = optional_component_capabilities })

0 commit comments

Comments
 (0)