-
Notifications
You must be signed in to change notification settings - Fork 522
Matter Switch: Support fan/light devices as parent/child #2653
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
Changes from all commits
9be3723
350c4bf
ac7517e
29ffe1e
5b9fccf
aff7f90
06fd08e
a33c57b
d291eb7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| name: fan-modular | ||
| components: | ||
| - id: main | ||
| capabilities: | ||
| - id: fanMode | ||
| version: 1 | ||
| optional: true | ||
| - id: fanSpeedPercent | ||
| version: 1 | ||
| optional: true | ||
| - id: firmwareUpdate | ||
| version: 1 | ||
| - id: refresh | ||
| version: 1 | ||
| categories: | ||
| - name: Fan | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,8 +16,64 @@ if version.api < 11 then | |
| end | ||
|
|
||
| local DeviceConfiguration = {} | ||
| local ChildConfiguration = {} | ||
| local SwitchDeviceConfiguration = {} | ||
| local ButtonDeviceConfiguration = {} | ||
| local FanDeviceConfiguration = {} | ||
|
|
||
| function ChildConfiguration.create_child_devices(driver, device, server_cluster_ep_ids, default_endpoint_id, assign_profile_fn) | ||
| if #server_cluster_ep_ids == 1 and server_cluster_ep_ids[1] == default_endpoint_id then -- no children will be created | ||
| return | ||
| end | ||
|
|
||
| table.sort(server_cluster_ep_ids) | ||
| for device_num, ep_id in ipairs(server_cluster_ep_ids) do | ||
| if ep_id ~= default_endpoint_id then -- don't create a child device that maps to the main endpoint | ||
| local label_and_name = string.format("%s %d", device.label, device_num) | ||
| local child_profile, _ = assign_profile_fn(device, ep_id, true) | ||
| local existing_child_device = device:get_field(fields.IS_PARENT_CHILD_DEVICE) and switch_utils.find_child(device, ep_id) | ||
| if not existing_child_device then | ||
| driver:try_create_device({ | ||
| type = "EDGE_CHILD", | ||
| label = label_and_name, | ||
| profile = child_profile, | ||
| parent_device_id = device.id, | ||
| parent_assigned_child_key = string.format("%d", ep_id), | ||
| vendor_provided_label = label_and_name | ||
| }) | ||
| else | ||
| existing_child_device:try_update_metadata({ | ||
| profile = child_profile | ||
| }) | ||
| end | ||
| end | ||
| end | ||
|
|
||
| -- Persist so that the find_child function is always set on each driver init. | ||
| device:set_field(fields.IS_PARENT_CHILD_DEVICE, true, {persist = true}) | ||
| device:set_find_child(switch_utils.find_child) | ||
| end | ||
|
|
||
| function FanDeviceConfiguration.assign_profile_for_fan_ep(device, server_fan_ep_id) | ||
| local ep_info = switch_utils.get_endpoint_info(device, server_fan_ep_id) | ||
| local fan_cluster_info = switch_utils.find_cluster_on_ep(ep_info, clusters.FanControl.ID) | ||
| local optional_supported_component_capabilities = {} | ||
| local main_component_capabilities = {} | ||
|
|
||
| if clusters.FanControl.are_features_supported(clusters.FanControl.types.Feature.MULTI_SPEED, fan_cluster_info.feature_map) then | ||
| table.insert(main_component_capabilities, capabilities.fanSpeedPercent.ID) | ||
| -- only fanMode can trigger AUTO, so a multi-speed fan still requires this capability if it supports AUTO | ||
| if clusters.FanControl.are_features_supported(clusters.FanControl.types.Feature.AUTO, fan_cluster_info.feature_map) then | ||
| table.insert(main_component_capabilities, capabilities.fanMode.ID) | ||
| end | ||
| else -- MULTI_SPEED is not supported | ||
| table.insert(main_component_capabilities, capabilities.fanMode.ID) | ||
| end | ||
|
|
||
| table.insert(optional_supported_component_capabilities, {"main", main_component_capabilities}) | ||
| return "fan-modular", optional_supported_component_capabilities | ||
| end | ||
|
|
||
|
|
||
| function SwitchDeviceConfiguration.assign_profile_for_onoff_ep(device, server_onoff_ep_id, is_child_device) | ||
| local ep_info = switch_utils.get_endpoint_info(device, server_onoff_ep_id) | ||
|
|
@@ -176,6 +232,7 @@ function DeviceConfiguration.match_profile(driver, device) | |
| if profiling_data_still_required(device) then return end | ||
|
|
||
| local default_endpoint_id = switch_utils.find_default_endpoint(device) | ||
| local optional_component_capabilities | ||
| local updated_profile | ||
|
|
||
| if #embedded_cluster_utils.get_endpoints(device, clusters.ValveConfigurationAndControl.ID) > 0 then | ||
|
|
@@ -188,15 +245,13 @@ function DeviceConfiguration.match_profile(driver, device) | |
|
|
||
| local server_onoff_ep_ids = device:get_endpoints(clusters.OnOff.ID) -- get_endpoints defaults to return EPs supporting SERVER or BOTH | ||
| if #server_onoff_ep_ids > 0 then | ||
| SwitchDeviceConfiguration.create_or_update_child_devices(driver, device, server_onoff_ep_ids, default_endpoint_id) | ||
| ChildConfiguration.create_child_devices(driver, device, server_onoff_ep_ids, default_endpoint_id, SwitchDeviceConfiguration.assign_profile_for_onoff_ep) | ||
| end | ||
|
|
||
| if switch_utils.tbl_contains(server_onoff_ep_ids, default_endpoint_id) then | ||
| updated_profile = SwitchDeviceConfiguration.assign_profile_for_onoff_ep(device, default_endpoint_id) | ||
| local generic_profile = function(s) return string.find(updated_profile or "", s, 1, true) end | ||
| if generic_profile("light-color-level") and #device:get_endpoints(clusters.FanControl.ID) > 0 then | ||
| updated_profile = "light-color-level-fan" | ||
| elseif generic_profile("light-level") and #device:get_endpoints(clusters.OccupancySensing.ID) > 0 then | ||
| if generic_profile("light-level") and #device:get_endpoints(clusters.OccupancySensing.ID) > 0 then | ||
| updated_profile = "light-level-motion" | ||
| elseif generic_profile("plug-binary") or generic_profile("plug-level") then | ||
| if switch_utils.check_switch_category_vendor_overrides(device) then | ||
|
|
@@ -209,6 +264,12 @@ function DeviceConfiguration.match_profile(driver, device) | |
| end | ||
| end | ||
|
|
||
| local fan_device_type_ep_ids = switch_utils.get_endpoints_by_device_type(device, fields.DEVICE_TYPE_ID.FAN) | ||
| if #fan_device_type_ep_ids > 0 then | ||
| updated_profile, optional_component_capabilities = FanDeviceConfiguration.assign_profile_for_fan_ep(device, default_endpoint_id) | ||
| device:set_field(fields.MODULAR_PROFILE_UPDATED, true) | ||
| end | ||
|
Comment on lines
+267
to
+271
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For now this is perfectly fine, but it might be worth discussing alternate approaches for the default endpoint logic at some point. Because at this point we already know the default endpoint contains a fan device type so it seems like we shouldn't need the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agreed |
||
|
|
||
| -- initialize the main device card with buttons if applicable | ||
| local momemtary_switch_ep_ids = device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH}) | ||
| if switch_utils.tbl_contains(fields.STATIC_BUTTON_PROFILE_SUPPORTED, #momemtary_switch_ep_ids) then | ||
|
|
@@ -219,7 +280,7 @@ function DeviceConfiguration.match_profile(driver, device) | |
| return | ||
| end | ||
|
|
||
| device:try_update_metadata({ profile = updated_profile }) | ||
| device:try_update_metadata({ profile = updated_profile, optional_component_capabilities = optional_component_capabilities }) | ||
| end | ||
|
|
||
| return { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.