-
Notifications
You must be signed in to change notification settings - Fork 737
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
Add support for Tuya DPs mapped to multiple cluster attributes #3643
base: dev
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## dev #3643 +/- ##
==========================================
+ Coverage 90.91% 90.93% +0.01%
==========================================
Files 325 325
Lines 10567 10575 +8
==========================================
+ Hits 9607 9616 +9
+ Misses 960 959 -1 ☔ View full report in Codecov by Sentry. |
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.
Just went through the existing DP mapping code and noticed this was merged at some point: #1989
The example at the bottom is interesting. It seems like we already support mapping one datapoint to multiple attributes if they're on the same cluster.
I generally prefer this implementation though, as it's more explicit/clear than the older one. In a follow-up PR, we can probably convert old quirks and remove the old parsing code, unless we find that a bunch of custom quirks use it..
Overall, I think this is fine. We should see if we can optimize how often _dp_to_attributes
is generated though. It might be enough to just do that once in the cluster __init__
.
def tuya_dp_multi( | ||
self, | ||
dp_id: int, | ||
attribute_mapping: list[DPToAttributeMapping], | ||
dp_handler: str = "_dp_2_attr_update", | ||
) -> QuirkBuilder: # fmt: skip | ||
"""Add Tuya DP Converter that maps to multiple attributes.""" | ||
self.tuya_dp_to_attribute.update({dp_id: attribute_mapping}) | ||
self.tuya_data_point_handlers.update({dp_id: dp_handler}) | ||
return self |
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, is there any benefit to also having this method instead of just calling tuya_dp
twice for the same endpoint?
If so, we may want to add a test for this, though I'd need to check if tuya_dp
is tested explicitly (or just by one of the other Tuya methods).
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.
Part of the reason was that calling tuya_dp
multiple times would allow passing a different dp_handler
, which will not work properly. It would still handle multiple DPToAttributeMapping
, but just overwrite the dp_handler
.
Having a separate method prevents that and makes it clearer to who uses it. I can drop it if you think it would be better that way.
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.
Oh, I just noticed that I missed the tests when opening this PR from the original one: https://github.com/zigpy/zha-device-handlers/pull/3644/files#diff-d01eb6338c5bfa4635fb433e6a8fc5b9cf3de58e784218f8930c5ccaedd927f5
🤦♂️
Copied them to this PR now.
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.
Ok, one more thing regarding this. Can we either block subsequent calls to tuya_dp
if the dp_id
is already in tuya_dp_to_attribute
or just have it update the existing list of DPToAttributeMapping
per id?
For the latter, both tuya_dp_multi
and subsequent calls to tuya_dp
would work as expected 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.
Added that in a new PR #3827 since it required changing 2 quirks that were invalid.
# mark mapped to attribute as valid if existing and if on a LocalDataCluster | ||
attr = cluster.attributes_by_name.get(dp_map.attribute_name) | ||
if attr and isinstance(cluster, LocalDataCluster): | ||
# _VALID_ATTRIBUTES is only a class variable, but as want to modify it | ||
# per instance here, we need to create an instance variable first | ||
if "_VALID_ATTRIBUTES" not in cluster.__dict__: | ||
cluster._VALID_ATTRIBUTES = set() | ||
cluster._VALID_ATTRIBUTES.add(attr.id) |
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.
Well, this code also never expected a tuple, so the "old multi DP code".
Needs updating in a future PR if we keep that code around.
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.
Personally I would prefer to drop the tuple from DPToAttributeMapping
. Even if a few custom quirks break, I think it is worth it to have the code a bit clean. Except if there are a lot of custom quirks using it.
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.
Ok, we probably should remove it soon then.
I guess we could also convert the old tuple-style to the new _dp_to_attributes
format with the list in __init__
if we really wanted to. Then, we wouldn't need to care about handling it again in _dp_2_attr_update
or for the "mark attributes as valid". I think that could be nice. Otherwise, we can just remove it soon.
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 am fine with both removing or converting it to _dp_to_attributes
. Personally, I prefer to remove it just to keep the code simpler and easier to maintain.
But let me know which approach you prefer and I'll do that. Is it fine if we leave that to a follow-up PR? This one is not breaking it anyway.
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, that's fine.
I was under the impression that this is already supported in v1 quirks, see the DPToAttributeMapping class:
Below is an example that I used previously that calls a function in the TuyaPowerPhase class to extract voltage, current and power:
This would look like this in a v2 quirk:
Before seeing this PR I as about to raise my own (linked #3811) to amend the v2 tuya builder methods Are we overcomplicating things here? |
@jeverley TheJulianJES pointed that out too here: #3643 (review) I have missed that when I opened this. Still, this PR makes it a bit more explicit, and allows having a single DP mapped to different clusters, which is not possible with the old DPToAttributeMapping tuple approach. Also, not all code is currently properly handling the tuple. See #3643 (comment) The plan is to check if we can drop the old tuple after this is merge (and migrate any quirks using it). |
Proposed change
Some Tuya devices expose multiple atributes (like current+voltage+power) in a single DP. This PR adds support for easilly mapping those, including Builder support.
Additional information
Checklist
pre-commit
checks pass / the code has been formatted using Black