-
Notifications
You must be signed in to change notification settings - Fork 484
Matter Switch move button and switch initialization to doConfigure #2041
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
base: main
Are you sure you want to change the base?
Conversation
Invitation URL: |
Test Results 66 files 422 suites 0s ⏱️ Results for commit 7b5daf1. ♻️ This comment has been updated with latest results. |
Minimum allowed coverage is Generated by 🐒 cobertura-action against 7b5daf1 |
951333e
to
d2843e6
Compare
I found this line: -- The resulting endpoint to component map is saved in the COMPONENT_TO_ENDPOINT_MAP_BUTTON field |
@@ -472,6 +467,17 @@ local function endpoint_to_component(device, ep) | |||
return "main" | |||
end | |||
|
|||
local function check_field_name_updates(device) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a very critical function. It definitely looks fine to me, but it may be best to make this functionality as explicit as possible. I think being able to reason about this very clearly is important.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think there is any risk that the command to copy the old field to the new field could fail, and then the next line would set the old field to nil? I kind of doubt that it could happen but I suppose it's possible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose maybe that could happen? but a driver crash wouldn't cause that, so like lua itself and the lua runtime would have to fail. That's not something we're really capable of worrying about I don't think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, you're probably right.
if device:get_field(IS_PARENT_CHILD_DEVICE) then | ||
device:set_find_child(find_child) | ||
end | ||
if device:get_field(BUTTON_DEVICE_PROFILED) then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since we've moved this logic, I don't think we need the check to include a field anymore since we're not worried about race conditions? We could have the initialize_buttons_and_switches
function return whether or not a profile was found mapped to. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah good point, and I like that idea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After trying this out, it felt a bit messy trying to get the profile name from try_build_button_component_map
back to doConfigure
. It feels easier to just use the field, but now since we only need it a single time we can set it to nil after using it. Do you agree with this approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's what I'm imagining.
In the do_configure handling:
local profile_found = initialize_buttons_and_switches(driver, device, main_endpoint)
if profile_found then
return
end
Then, in initialize_buttons_and_switches
, we could do something like:
local function initialize_buttons_and_switches(driver, device, main_endpoint)
...
if #button_eps > 0 then
build_button_profile(device, main_endpoint, #button_eps)
configure_buttons(device)
return true
end
...
if num_switch_server_eps > 0 and detect_matter_thing(device) then
handle_light_switch_with_onOff_server_clusters(device, main_endpoint, num_switch_server_eps)
return true
end
the button path is actually identical per the current logic, and I added another check for the num_switch_server_eps > 0
case that I think was missed before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah okay, that approach makes sense to me now. I implemented this in the latest commit!
-- initialize the main device card with buttons if applicable, and create child devices as needed for multi-switch devices. | ||
initialize_buttons_and_switches(driver, device, main_endpoint) | ||
if device:get_field(IS_PARENT_CHILD_DEVICE) then | ||
device:set_find_child(find_child) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
device:set_find_child(find_child)
will still need to be set on init as it does not persist and should be called each time the driver restarts.
As a good test case for these changes, we should test various device types and ensure that they continue to work after a driver restart. Onboarding a parent-child device and then confirming that the child devices continue to work as expected after a driver restart would be a good test case!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, that's a great call out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated this in the latest commit
-- driver after it was merged into the matter-switch driver. Note that devices | ||
-- containing both button endpoints and switch endpoints will use this field | ||
-- rather than COMPONENT_TO_ENDPOINT_MAP. | ||
local COMPONENT_TO_ENDPOINT_MAP_BUTTON = "__component_to_endpoint_map_button" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What as the original intent behind using a different field specifically for the button MCD devices? Was it because of the check in init
that essentially bypassed MCD devices? That sounds right to me but I just want to make sure there wasn't another intent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that's right. We didn't want to mess with the original field because there are probably still old switch MCD devices out there that we didn't want to re-configure as parent-child. But if the init logic is in doConfigure then we wouldn't need to worry about that.
@@ -760,6 +722,47 @@ local function device_init(driver, device) | |||
device:subscribe() | |||
end | |||
|
|||
local function do_configure(driver, device) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason to put this in doConfigure
instead of added
? I think that we have effectively treated these functions as nearly interchangable "one-time configuration" functions, but it may be worth setting a precedent with this change since this is our biggest and most used driver. Any thoughts on which lifecycle event we should use for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some calls in device_init
that are required to run before initialize_buttons_and_switches
(device:set_component_to_endpoint_fn(component_to_endpoint)
for example), so I think doConfigure
is the best place for this code since it will run after device_init
(while added
precedes device_init
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Further, since doConfigure
is tied to whether or not the provisioning state has been changed to provisioned while added
is also related to a driver change, doConfigure
is the more appropriate place for a "true" one time handling like device profiling.
if not detect_bridge(device) then | ||
local main_endpoint = find_default_endpoint(device) | ||
-- initialize the main device card with buttons if applicable, and create child devices as needed for multi-switch devices. | ||
initialize_buttons_and_switches(driver, device, main_endpoint) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also since doConfigure
could be called multiple times, we want to make sure functions like this can be run multiple times without issue in the same lifecycle. I don't suspect any issue from what I see but just wanted to call it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be no issue but I do see your concern. However, from my understanding doConfigure
would only be called multiple times if the device is not set to the provisioned state, and it that case it seems that it would be a good idea to re-run these init functions.
@@ -286,8 +286,6 @@ local HELD_THRESHOLD = 1 | |||
-- this is the number of buttons for which we have a static profile already made | |||
local STATIC_BUTTON_PROFILE_SUPPORTED = {1, 2, 3, 4, 5, 6, 7, 8} | |||
|
|||
local BUTTON_DEVICE_PROFILED = "__button_device_profiled" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should also set this field to nil since we have that handy function to remove these en masse
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This field was not persisted so we should be good there 👍
Good catch! Fixed in latest commit |
92942cb
to
2879761
Compare
This change moves the initialization logic for buttons and switches to doConfigure. This keeps all of the profile selection logic all within doConfigure and allows the removal of logic gates from device_init that were there to ensure init code only ran one time. Also added is a new function that runs at init that can rename or delete persisted fields on the device.
2879761
to
7b5daf1
Compare
Type of Change
Checklist
Description of Change
This change moves the initialization logic for buttons and switches to
do_configure
. This consolidates all of the profile selection logic to be within doConfigure and allows the removal of logic gates fromdevice_init
that were there to ensure init code only ran one time.Also added is a new function that runs at init that can rename or delete persisted fields on the device. The original
__component_to_endpoint_map
field can now be utilized by buttons and other devices becauseinitialize_buttons_and_switches
is ensured to only run one time, meaning that old MCD switch devices will not be affected. Also, the__switch_intialized
field can now be deleted from devices.Summary of Completed Tests
Tested with various matter buttons and lights to ensure no change in behavior.