-
Notifications
You must be signed in to change notification settings - Fork 54
Fix not claiming cluster handler for some quirks v2 entities #548
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
37390cf
0ebbce8
f98323d
1a7d243
19c9279
a9f8141
fc53e7a
4911051
bcf7b37
6c12760
51682e9
dfa5653
3d46322
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 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -232,6 +232,10 @@ def discover_quirks_v2_entities(self, device: Device) -> Iterator[PlatformEntity | |||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert cluster_handler | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # flags to determine if we need to claim/bind the cluster handler | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| attribute_initialization_found: bool = False | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reporting_found: bool = False | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for entity_metadata in entity_metadata_list: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| platform = Platform(entity_metadata.entity_platform.value) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| metadata_type = type(entity_metadata) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -254,6 +258,7 @@ def discover_quirks_v2_entities(self, device: Device) -> Iterator[PlatformEntity | |||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # process the entity metadata for ZCL_INIT_ATTRS and REPORT_CONFIG | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if attr_name := getattr(entity_metadata, "attribute_name", None): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # TODO: ignore "attribute write buttons"? currently, we claim ch | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # if the entity has a reporting config, add it to the cluster handler | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if rep_conf := getattr(entity_metadata, "reporting_config", None): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # if attr is already in REPORT_CONFIG, remove it first | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -268,8 +273,8 @@ def discover_quirks_v2_entities(self, device: Device) -> Iterator[PlatformEntity | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| cluster_handler.REPORT_CONFIG += ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AttrReportConfig(attr=attr_name, config=astuple(rep_conf)), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # claim the cluster handler, so ZHA configures and binds it | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endpoint.claim_cluster_handlers([cluster_handler]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # mark cluster handler for claiming and binding later | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reporting_found = True | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # not in REPORT_CONFIG, add to ZCL_INIT_ATTRS if it not already in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| elif attr_name not in cluster_handler.ZCL_INIT_ATTRS: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -283,6 +288,8 @@ def discover_quirks_v2_entities(self, device: Device) -> Iterator[PlatformEntity | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| cluster_handler.ZCL_INIT_ATTRS[attr_name] = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| entity_metadata.attribute_initialized_from_cache | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # mark cluster handler for claiming later, but not binding | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| attribute_initialization_found = True | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yield entity_class( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cluster_handlers=[cluster_handler], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -299,6 +306,19 @@ def discover_quirks_v2_entities(self, device: Device) -> Iterator[PlatformEntity | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| [cluster_handler.name], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # if the cluster handler is unclaimed, claim it and set BIND accordingly, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
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. I wonder: should we move this to happen before 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. We can't really do that in a nice way, since we need to iterate over all quirks v2 entity metadata for a specific cluster handler before we can make the final decision on whether we can set This is all still done "pre initialization", since they're just added to Lines 939 to 950 in b172549
Nothing in entity.on_add() can also ever rely on the cluster handler being claimed or not.The actual cluster handler initialization is done way later, where it then matters if a cluster handler is claimed or not. I think it's fine to keep it like this tbh.
Lines 956 to 969 in b172549
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # so ZHA configures the cluster handler: reporting + reads attributes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (attribute_initialization_found or reporting_found) and ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cluster_handler not in endpoint.claimed_cluster_handlers.values() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
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. Is there any way for the cluster handler to already be claimed?
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. The cluster handler can already be claimed by entities from This is also checked by the tests. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endpoint.claim_cluster_handlers([cluster_handler]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # BIND is True by default, so only set to False if no reporting found. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # We can safely do this, since quirks v2 entities are initialized last, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # so if the cluster handler wasn't claimed by EndpointProbe so far, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # only v2 entities need it. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not reporting_found: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cluster_handler.BIND = False | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @ignore_exceptions_during_iteration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def discover_coordinator_device_entities( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self, device: 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.
Another nitpick, feel free to ignore if it's too much trouble. Is there any way to test using JSON diagnostics from a real device? I'd like to phase out use of
create_mock_zigpy_deviceand other synthetic testing setups in favor of using real devices.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.
Hmm, I explicitly used
create_mock_zigpy_device, as that's what the similar tests intest_sensorused and especially here, we really want to make sure that we get this exact device with that exact cluster setup.I feel like we always run into a bit of a risk with using JSON diagnostics in tests, as it's not clear how endpoints and clusters are layed out by just looking at the tests. You have to look at the (huge) JSON file. It's also harder to get a device exactly in the way you want it, without adding unnecessary endpoints/clusters/quirk interference.
Some parts of the device/diagnostics can change over time as well (i.e. ZHA or quirk doing something different, firmware update, ...), when we may not want that for all tests where the diagnostics are used in.
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 can address this in the future IMO. The new/modified tests are all based on one very similar (existing) test. If so, we should change all of them then.
Maybe we can have some JSON diagnostics files in a separate folder that aren't real devices (and cannot be "modified" if we add new diagnostics). That way we could avoid
create_mock_zigpy_device.We could add a comment in the tests then to explain what the diagnostics/tests devices do.
I do think that manually modifying JSON files isn't as easy as using
create_mock_zigpy_device. For these tests,create_mock_zigpy_deviceis kind of ideal.