Skip to content

Set a suggested display precision of one decimal for humidity sensors - #915

Draft
zigpy-review-bot wants to merge 2 commits into
devfrom
zigpy-bot/humidity-suggested-display-precision
Draft

zigpy-review-bot wants to merge 2 commits into
devfrom
zigpy-bot/humidity-suggested-display-precision

Conversation

@zigpy-review-bot

Copy link
Copy Markdown
Collaborator

Proposed change

ZHA's humidity-type sensors report measured_value / 100, so their state carries two decimals (e.g. 72.39), and they set no suggested_display_precision. Home Assistant has no default display precision for the humidity (or moisture) device class either, so the frontend falls back to showing as many decimals as the state happens to have: 72,39 %. That is what is still open in home-assistant/core#145584.

This sets _attr_suggested_display_precision = 1 on the four sensors that divide a ZCL percent value by 100:

entity cluster device class
Humidity RelativeHumidity (0x0405) humidity
SmartThingsHumidity SmartThings manufacturer-specific (0xFC45) humidity
LeafWetness LeafWetness (0x0407) humidity
SoilMoisture SoilMoisture (0x0408) moisture

AnalogInputSensor can also end up with the humidity device class (application type Relative_Humidity_Percent), but it is left alone: it has no /100 scaling and already derives its precision from the cluster's resolution attribute.

Only the display default changes. The state is still the unrounded value, a Display precision the user picked for an entity still wins, and Home Assistant recomputes the stored suggestion whenever the entity is added, so existing installs pick this up without a migration. The HA integration already forwards the library's value (homeassistant/components/zha/sensor.py copies suggested_display_precision from the entity state when it is not None), so no change is needed there beyond the usual ZHA bump. Core's ZHA tests only assert the humidity state ("10.0"), not a precision or registry options, so the bump should not need test changes either.

Related: home-assistant/core#145584

Background

Core not defining a default for the percent-based device classes is the actual gap, and a fix there would cover every integration at once. Until that exists, each integration has to set it itself. If Core adds one later, these attributes become redundant but harmless, since an integration-supplied precision takes priority over the table.

Why one decimal (open for discussion, hence draft)

  • It restores what ZHA displayed before Replace decimals with suggested_display_precision + remove rounding #408. Back then the state itself was rounded, so history and statistics had one decimal too; that part is intentionally not restored.
  • It matches the default Core applies to temperature, so a temperature/humidity sensor reads consistently.
  • deCONZ, the other Zigbee integration in Core, uses 1 for the same measured_value / 100, and so does Shelly.

This is a display choice, not something the spec dictates: ZCL R8 §4.7.2.1.1 defines MeasuredValue as 100 × the water content in percent, with a maximum resolution of 0.01 %, for all three standard clusters.

The alternative is 0 (whole percent). Typical sensors are specified at ±2 to 3 % RH, so there is an argument for it, but it would show less than ZHA ever did.

What other Core integrations do

An AST scan of homeassistant/components on Core dev (a1e35b34f0a) for sensor entity definitions using SensorDeviceClass.HUMIDITY finds 225 statically declared definitions in 134 integrations. It counts entity descriptions and _attr_device_class class attributes; selectors, trigger/condition specs and integrations that pick the device class at runtime or from a lookup table (Tuya's DP tables, KNX, Tasmota, …) are not counted, and a precision assigned at runtime shows up as "not set" (nibe_heatpump and tplink do that).

suggested_display_precision definitions integrations
not set 202 119
1 15 10 (airly, airthings_ble, ambient_network, deconz, epion, imou, microbees, nam, point, shelly)
2 5 2 (altruist, lacrosse_view)
0 3 3 (airthings, weatherflow, weatherflow_cloud)

"Not set" does not always mean two decimals on screen, because many of those integrations deliver a whole or pre-rounded number. The ones closest to ZHA:

integration humidity precision notes
deCONZ 1 same Zigbee value, humidity / 100
Shelly 1 all three humidity sensor descriptions
ESPHome per entity taken from the device's accuracy_decimals
Matter not set MeasuredValue / 100, so it has the same two decimals as ZHA today; the Matter sensor platform sets a precision on many other sensors, but not on its standard TemperatureSensor and HumiditySensor descriptions
Z-Wave JS not set no suggested_display_precision on any sensor; the state has whatever precision the device reports
MQTT (Zigbee2MQTT) not set Zigbee2MQTT's discovery payload carries no precision for humidity and it rounds the value itself, to two decimals by default (humidity_precision)

Quirks

  • Nothing needs to change in zha-quirks for humidity. On its dev (d6fcec59), none of the 50 .sensor() and 66 .tuya_sensor() calls defines a humidity- or moisture-class sensor. Tuya quirks expose humidity through .tuya_humidity() (10 uses) and .tuya_soil_moisture() (4 uses), which map the datapoint onto the standard RelativeHumidity / SoilMoisture clusters, so those devices get ZHA's Humidity / SoilMoisture entities and are covered here. The same goes for v1 quirks that replace these clusters, and for the Third Reality soil sensor, which only changes the device class of ZHA's Humidity entity to moisture.
  • Separate finding, not addressed here: QuirkBuilder.sensor() has a suggested_display_precision parameter (default 1, from Implement suggested display precision for sensors zigpy#1586) that is stored on ZCLSensorMetadata but never applied. _platform_kwargs() in zhaquirks/builder/discovery.py does not forward it and Sensor.__init__ has no such parameter; Sensor._init_from_quirks_metadata(), which did this job before Migrate quirks out of zigpy and provide direct entity access #762, did not read it either. So a quirk-defined sensor currently always ends up with None, whatever the quirk passes (no quirk passes it today). Wiring it up needs a change in both repos, and the builder default would have to become None first: otherwise every quirk sensor would get one decimal at once, and Home Assistant raises for a sensor that has a suggested precision but a non-numeric value.

Testing

  • async_test_humidity now also checks that a report of 4853 gives a state of 48.53 (not rounded) with suggested_display_precision == 1, and test_sensor runs it for SoilMoisture and LeafWetness as well as Humidity.
  • Regenerated tests/data/devices with python -m tools.regenerate_diagnostics: 79 snapshots change, each by exactly one line ("suggested_display_precision": null to 1) — 70 Humidity, 8 SoilMoisture, 1 SmartThingsHumidity. No device in the corpus has a LeafWetness entity, so that one is covered by the unit test only.

@codecov

codecov Bot commented Sep 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.22%. Comparing base (fc5b094) to head (8bd3bc0).

Additional details and impacted files
@@           Coverage Diff           @@
##              dev     #915   +/-   ##
=======================================
  Coverage   97.22%   97.22%           
=======================================
  Files          61       61           
  Lines       10657    10661    +4     
=======================================
+ Hits        10361    10365    +4     
  Misses        296      296           

☔ View full report in Codecov by Harness.
📢 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

puddly commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

Wouldn't it be more sensible to contribute this to Core? Was humidity deliberately omitted?

@TheJulianJES

Copy link
Copy Markdown
Contributor

Yes, the bot got stuck and didn't comment that part yet 😅

@TheJulianJES

Copy link
Copy Markdown
Contributor

@zigpy-review-bot Find session that was about this PR and home-assistant/core#145584. It already started preparing HA Core branch, continue my instructions from there.

@zigpy-review-bot

Copy link
Copy Markdown
Collaborator Author

Core-side version of this is on a branch: https://github.com/TheJulianJES/core/tree/zigpy-bot/humidity-default-display-precision (diff against Core dev: home-assistant/core@dev...TheJulianJES:core:zigpy-bot/humidity-default-display-precision). Not opened as a PR.

It adds SensorDeviceClass.HUMIDITY and SensorDeviceClass.MOISTURE to UNITS_PRECISION in homeassistant/components/sensor/const.py with one decimal, plus the matching rows in test_default_precision. Both device classes only allow %, so there is no unit conversion involved. Everything else in the diff is snapshot churn: 190 humidity and 4 moisture sensors across 47 integrations now get suggested_display_precision: 1 stored in the entity registry. Integrations that already set their own precision (deCONZ, Shelly, Airthings, …) are unchanged, because an integration-supplied value always wins over the table.

Was humidity deliberately left out? I found no sign of it. home-assistant/core#145013, which introduced the table, describes it as a default precision "for each of Sensor's device classes" and says nothing about humidity in its description or review. Yet more than 20 other numeric device classes are also missing from the table, including battery, CO2, illuminance and the PM classes. That reads like gaps in coverage rather than a decision about humidity.

Is it the better fix? For the root cause, yes: one table entry covers every integration, including Matter, which has the same two decimals for the same MeasuredValue / 100 reason, and the 202 of 225 humidity sensor definitions an AST scan of Core could classify that set no precision. As with temperature, the default only reaches entities with a unique ID, since the value is stored in the entity registry. The cost is that integrations that report whole-number humidity would show 59.0 % instead of 59 %, the same trade-off Core already made for temperature. Of the 146 humidity entities in Core's own snapshots that have a numeric state and no precision, 48 are whole numbers. Whether the default should be 1 or 0 is Core's call. If Core takes it, this PR becomes redundant but harmless; until then it is the faster way to fix ZHA.

Verification
  • Branch commit TheJulianJES/core@79c7094d8e5 on top of home-assistant/core@6cd7e61bad5.
  • tests/components/sensor, the tests of all 60 integrations with humidity or moisture sensor snapshots (re-run without --snapshot-update after regenerating), and config, esphome, mqtt, powerwall, rapt_ble and zwave_js (non-snapshot tests that assert display precision): all pass except the tplink camera and esphome ffmpeg-proxy tests, which need an ffmpeg binary this environment doesn't have.
  • pre-commit (ruff, mypy, pylint, hassfest, …) passes.
  • The commit is authored by the bot account; it needs to be re-authored before it can go upstream as a Core PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants