8000 Add AnalogInput sensor, use description attribute for fallback_name by prairiesnpr · Pull Request #197 · zigpy/zha · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add AnalogInput sensor, use description attribute for fallback_name #197

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

Merged
merged 50 commits into from
May 2, 2025

Conversation

prairiesnpr
Copy link
Contributor
@prairiesnpr prairiesnpr commented Sep 7, 2024

This ensures that the description attribute (0x001C), if present, is used for the fallback_name and sets the translation_key to None. The entity id and name will use the fallback_name and align with the devices value. This is mostly useful for devices using general clusters, if not set, the current functionality is maintained.

Due to testing requirements, this now also updates the cluster handlers for AnalogInput, MultistateInput, and BinaryInput.

Closes: #160

image

image

Multistate still requires zigpy/zigpy#1456 to be fully implemented, since the LVLists aren't serialized, we create a default value for now.
image

AnalogOutput is putting the description in the name twice.
image

This is due to this logic in core, should we add similar logic to core for the rest of the Entities and remove it from ZHA, keep the logic in ZHA, or have it mixed?

https://github.com/home-assistant/core/blob/f1e4229b23ef7837bb4e46877f55d6533f8d4607/homeassistant/components/zha/number.py#L52C9-L52C58

Copy link
codecov bot commented Sep 7, 2024

Codecov Report

Attention: Patch coverage is 98.07229% with 8 lines in your changes missing coverage. Please review.

Project coverage is 96.88%. Comparing base (4afffe1) to head (1639dd1).
Report is 1 commits behind head on dev.

Files with missing lines Patch % Lines
zha/zigbee/cluster_handlers/general.py 82.92% 7 Missing ⚠️
zha/application/platforms/sensor/helpers.py 91.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              dev     #197      +/-   ##
==========================================
+ Coverage   96.82%   96.88%   +0.05%     
==========================================
  Files          61       63       +2     
  Lines        9997    10404     +407     
==========================================
+ Hits         9680    10080     +400     
- Misses        317      324       +7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@puddly
Copy link
Contributor
puddly commented Sep 7, 2024

I wonder: would it be feasible to instead set the translation key to the ZCL description? This could allow the description to be localized.

@prairiesnpr
Copy link
Contributor Author
prairiesnpr commented Sep 7, 2024

I wonder: would it be feasible to instead set the translation key to the ZCL description? This could allow the description to be localized.

That was the approach I started with, unfortunately, when the translation key wasn't found, it would return None for the name and id. I understood it should then fallback, but that's not the result I observed in testing.

@prairiesnpr prairiesnpr marked this pull request as draft September 7, 2024 20:08
@prairiesnpr prairiesnpr marked this pull request as ready for review September 7, 2024 23:44
@prairiesnpr prairiesnpr changed the title Use description attribute for fallback_name Add AnalogInput, MultistateInput, use description attribute for fallback_name Sep 9, 2024
super().__init__(unique_id, cluster_handlers, endpoint, device, **kwargs)
engineering_units = self._cluster_handler.engineering_units
self._attr_native_unit_of_measurement = UNITS.get(engineering_units)
self._attr_state_class = SensorStateClass.MEASUREMENT
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this always be measurement? I can see a situation where total or total increasing makes sense, but I don't see a good way to choose based on the attributes we have available.

Copy link
Contributor
@TheJulianJES TheJulianJES left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some restrictions on what we can provide as a translation_key to Home Assistant. AFAIK, we are not allowed to provide translation keys blindly, so not directly from the description attribute, for example.

We'd need to map all known description attribute values to translation keys (and fall-back to a default or untranslated name otherwise).

So, I'm wondering if it would make sense to split this PR into two: one with the translation key changes and one with the added AnalogInput and MultistateInput sensors.

@prairiesnpr
Copy link
Contributor Author

There are some restrictions on what we can provide as a translation_key to Home Assistant. AFAIK, we are not allowed to provide translation keys blindly, so not directly from the description attribute, for example.

We'd need to map all known description attribute values to translation keys (and fall-back to a default or untranslated name otherwise).

So, I'm wondering if it would make sense to split this PR into two: one with the translation key changes and one with the added AnalogInput and MultistateInput sensors.

We aren't modifying the translation_key here, if a description attribute is provided, we set the key to None and then provide a fallback_name, that way we can use arbitrary values without having a matching translation_key. This follows the same logic currently used for custom quirks https://github.com/home-assistant/core/blob/f1e4229b23ef7837bb4e46877f55d6533f8d4607/homeassistant/components/zha/entity.py#L46

As far as splitting the PR, it was originally planned to have multiple PRs, one for the fallback_name functionality and then additional PRs for each cluster. I ran into issues with writing tests there, since we really needed them to both be present to get the required coverage. That said, I'm not opposed to splitting it, if we have a plan on how best to proceed.

@prairiesnpr
Copy link
Contributor Author

This will need a zigpy release before tests will pass.

@prairiesnpr prairiesnpr force-pushed the use_description_attr branch from 8fd863b to bd34bfd Compare October 4, 2024 12:14
@puddly puddly force-pushed the use_description_attr branch from 5a8c916 to 3b21131 Compare April 26, 2025 01:07
@puddly
Copy link
Contributor
puddly commented Apr 26, 2025

I've pushed a whole host of changes to this branch, apologies! There were a few bugs that needed fixing in ZHA (and thus some tweaks to Core):

  • Enum entities now implement _attr_options, which enumerate the possible entries. This is added to the info dict for the entity and will need to be exposed to HA Core.
  • The description attribute is required for both types of entities to be auto-created. This is unfortunate but something that we need to do until ZHA discovery is hammered into better shape.
  • All of the BACnet units have been re-mapped.

@P-R-O-C-H-Y Give this branch a try.

For analog input:

  1. description attribute must exist.
  2. engineering_units or application_type (preferred) must be implemented.

For multistate input:

  1. description attribute must exist.
  2. The state_text array must exist OR number_of_states. I'm debating whether or not to allow number_of_states and just require state_text.

The only implementation detail I'm still unsure of is state_text: the ZCL states:

The PresentValue, interpreted as an integer, serves as an index into the array.

In the ZCL, arrays are bizarrely both 0- and 1-indexed: the zero-th element is the size of the array, and the first element is the first element is the first. I think this means that present_value == 1 is the first element of the state_text array, so it's one-indexed? I would need a certified device to confirm and I unfortunately don't have one at the moment.

@puddly puddly moved this to Backlog in ZHA Apr 28, 2025
@puddly puddly added this to ZHA Apr 28, 2025
@puddly puddly moved this from Backlog to In progress in ZHA Apr 28, 2025
@P-R-O-C-H-Y
Copy link
Contributor

@puddly I am having some issues with Analog Input. It is showing up now, but the Description and Application type is not used.
I did send more info to you on Discord.

@puddly
Copy link
Contributor
puddly commented Apr 29, 2025

@P-R-O-C-H-Y This should be fixed by zigpy/zigpy#1593. With the device diagnostics you provided, the device is correctly shown:

       {
         "info_object": {
+          "fallback_name": "Power Consumption (Watts)",
           "unique_id": "ab:cd:ef:12:39:a2:73:55-1-12-analog_input",
           "migrate_unique_ids": [],
           "platform": "sensor",
           "class_name": "AnalogInputSensor",
           "translation_key": null,
           "device_class": "power",
           "state_class": "measurement",
           "entity_category": null,
           "entity_registry_enabled_default": true,
           "enabled": true,
           "primary": false,
           "cluster_handlers": [
             {
               "class_name": "AnalogInputClusterHandler",
               "generic_id": "cluster_handler_0x000c",
               "endpoint_id": 1,
               "cluster": {
                 "id": 12,
                 "name": "AnalogInput",
                 "type": "server"
               },
               "id": "1:0x000c",
               "unique_id": "ab:cd:ef:12:39:a2:73:55:1:0x000c",
               "status": "INITIALIZED",
               "value_attribute": "present_value"
             }
           ],
           "device_ieee": [ 85, 115, 162, 57, 18, 239, 205, 171],
           "endpoint_id": 1,
           "available": true,
           "group_id": null,
           "attribute": "present_value",
           "suggested_display_precision": null,
           "divisor": 1,
           "multiplier": 1,
+          "unit": "W",
           "options": null
         },
         "state": {
           "class_name": "AnalogInputSensor",
           "available": true,
+          "state": 280.0
         }

The unit is correctly identified as well. If you implement the resolution attribute, suggested_display_precision will be computed too.

@P-R-O-C-H-Y
Copy link
Contributor

@puddly Can you give a hint about the resolution attribute? Setting its value to 0.001 does not affect the suggested_display_precision. Is something not working or am I setting wrong values?

@puddly
Copy link
Contributor
puddly commented May 1, 2025

I've removed the MultiStateInput entity creation for now, unfortunately. We need to re-add these entities once zigpy's database issue with arrays has been resolved. This will unblock AnalogInput entities.

@puddly puddly merged commit 37778b0 into zigpy:dev May 2, 2025
9 checks passed
@github-project-automation github-project-automation bot moved this from In progress to Done in ZHA May 2, 2025
@TheJulianJES TheJulianJES changed the title Add AnalogInput, MultistateInput, use description attribute for fallback_name Add AnalogInput sensor, use description attribute for fallback_name May 2, 2025
Copy link
Contributor
@TheJulianJES TheJulianJES left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two small possible improvements with the description attribute check:

@@ -99,6 +95,14 @@ def on_add(self) -> None:
self.handle_cluster_handler_attribute_updated,
)
)
if (
hasattr(self._analog_output_cluster_handler, "description")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hasattr check shouldn't be needed, as the description property will always be present on the AnalogOutputClusterHandler that's guaranteed here since #442 in (now called) AnalogOutputNumber.
So, only the None check below is needed.

Comment on lines +205 to +210
if (
hasattr(self._cluster_handler, "description")
and self._cluster_handler.description is not None
):
self._attr_translation_key = None
self._attr_fallback_name: str = self._cluster_handler.description
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having this in the base Sensor class feels a bit weird. The description attribute will only be available on the AnalogInputClusterHandler used for AnalogInputSensor.
So, shouldn't we just move this part there (and remove the hasattr check as well)?

Comment on lines 1876 to 1885
"info_object": {
"fallback_name": null,
"fallback_name": "fading_time",
"unique_id": "ab:cd:ef:12:94:85:f7:5f-2-13",
"migrate_unique_ids": [],
"platform": "number",
"class_name": "Number",
"translation_key": "number",
"translation_key": null,
"device_class": null,
"state_class": null,
"entity_category": null,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More of a note: These entities shouldn't be present anymore.

We've replaced these AnalogOutput config entities for a lot of Tuya sensors with proper quirks v2 entities.
However, they'll still be in the zigpy attribute cache, until the device is re-paired.

I thought that the quirks v1 signature/replacement shouldn't persist to the database, but I remember we've had that issue at one point, so the quirked signature might be stuck in the database, or these were saved when the v1 quirks were still present and the regeneration of diagnostics just looked at the quirked signature and not the original signature?

We might wanna add a .removes(AnalogInput.cluster_id, endpoint_id=xx) to a whole lot of Tuya quirks for the various fake config entities that were added in the past...
Assuming these entities are still "provided" (but non-functional) for real users.

@P-R-O-C-H-Y
Copy link
Contributor

@puddly @TheJulianJES Can we take a look again into this and add MultiState Input/Output? Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request entities Issue or PR about (custom) entities
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Query and use device values when creating entities
5 participants
0