mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 17:57:11 +00:00
Adjust suggested_display_precision according to unit conversion (#87614)
This commit is contained in:
parent
ea29cdfe83
commit
8f2a764a43
@ -8,7 +8,7 @@ from dataclasses import dataclass
|
|||||||
from datetime import date, datetime, timedelta, timezone
|
from datetime import date, datetime, timedelta, timezone
|
||||||
from decimal import Decimal, InvalidOperation as DecimalInvalidOperation
|
from decimal import Decimal, InvalidOperation as DecimalInvalidOperation
|
||||||
import logging
|
import logging
|
||||||
from math import floor, log10
|
from math import ceil, floor, log10
|
||||||
import re
|
import re
|
||||||
from typing import Any, Final, cast, final
|
from typing import Any, Final, cast, final
|
||||||
|
|
||||||
@ -679,11 +679,40 @@ class SensorEntity(Entity):
|
|||||||
"""Update suggested display precision stored in registry."""
|
"""Update suggested display precision stored in registry."""
|
||||||
assert self.registry_entry
|
assert self.registry_entry
|
||||||
|
|
||||||
|
device_class = self.device_class
|
||||||
display_precision = self.suggested_display_precision
|
display_precision = self.suggested_display_precision
|
||||||
|
default_unit_of_measurement = (
|
||||||
|
self.suggested_unit_of_measurement or self.native_unit_of_measurement
|
||||||
|
)
|
||||||
|
unit_of_measurement = self.unit_of_measurement
|
||||||
|
|
||||||
if (
|
if (
|
||||||
sensor_options := self.registry_entry.options.get(DOMAIN, {})
|
display_precision is not None
|
||||||
) and sensor_options.get("suggested_display_precision") == display_precision:
|
and default_unit_of_measurement != unit_of_measurement
|
||||||
|
and device_class in UNIT_CONVERTERS
|
||||||
|
):
|
||||||
|
converter = UNIT_CONVERTERS[device_class]
|
||||||
|
|
||||||
|
# Scale the precision when converting to a larger or smaller unit
|
||||||
|
# For example 1.1 Wh should be rendered as 0.0011 kWh, not 0.0 kWh
|
||||||
|
ratio_log = log10(
|
||||||
|
converter.get_unit_ratio(
|
||||||
|
default_unit_of_measurement, unit_of_measurement
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ratio_log = floor(ratio_log) if ratio_log > 0 else ceil(ratio_log)
|
||||||
|
display_precision = max(0, display_precision + ratio_log)
|
||||||
|
|
||||||
|
if display_precision is None and (
|
||||||
|
DOMAIN not in self.registry_entry.options
|
||||||
|
or "suggested_display_precision" not in self.registry_entry.options
|
||||||
|
):
|
||||||
|
return
|
||||||
|
sensor_options = self.registry_entry.options.get(DOMAIN, {})
|
||||||
|
if (
|
||||||
|
"suggested_display_precision" in sensor_options
|
||||||
|
and sensor_options["suggested_display_precision"] == display_precision
|
||||||
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
registry = er.async_get(self.hass)
|
registry = er.async_get(self.hass)
|
||||||
@ -716,6 +745,7 @@ class SensorEntity(Entity):
|
|||||||
def async_registry_entry_updated(self) -> None:
|
def async_registry_entry_updated(self) -> None:
|
||||||
"""Run when the entity registry entry has been updated."""
|
"""Run when the entity registry entry has been updated."""
|
||||||
self._async_read_entity_options()
|
self._async_read_entity_options()
|
||||||
|
self._update_suggested_precision()
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _async_read_entity_options(self) -> None:
|
def _async_read_entity_options(self) -> None:
|
||||||
|
@ -1143,27 +1143,46 @@ async def test_unit_conversion_priority_suggested_unit_change(
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"native_unit, suggested_precision, native_value, device_class",
|
"unit_system, native_unit, integration_suggested_precision,"
|
||||||
|
"options_suggested_precision, native_value, device_class, extra_options",
|
||||||
[
|
[
|
||||||
# Distance
|
# Distance
|
||||||
(
|
(
|
||||||
|
METRIC_SYSTEM,
|
||||||
UnitOfLength.KILOMETERS,
|
UnitOfLength.KILOMETERS,
|
||||||
4,
|
4,
|
||||||
|
4,
|
||||||
1000,
|
1000,
|
||||||
SensorDeviceClass.DISTANCE,
|
SensorDeviceClass.DISTANCE,
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
# Air pressure
|
||||||
|
(
|
||||||
|
US_CUSTOMARY_SYSTEM,
|
||||||
|
UnitOfPressure.HPA,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1000,
|
||||||
|
SensorDeviceClass.ATMOSPHERIC_PRESSURE,
|
||||||
|
{"sensor.private": {"suggested_unit_of_measurement": "inHg"}},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_suggested_precision_option(
|
async def test_suggested_precision_option(
|
||||||
hass,
|
hass,
|
||||||
enable_custom_integrations,
|
enable_custom_integrations,
|
||||||
|
unit_system,
|
||||||
native_unit,
|
native_unit,
|
||||||
suggested_precision,
|
integration_suggested_precision,
|
||||||
|
options_suggested_precision,
|
||||||
native_value,
|
native_value,
|
||||||
device_class,
|
device_class,
|
||||||
|
extra_options,
|
||||||
):
|
):
|
||||||
"""Test suggested precision is stored in the registry."""
|
"""Test suggested precision is stored in the registry."""
|
||||||
|
|
||||||
|
hass.config.units = unit_system
|
||||||
|
|
||||||
entity_registry = er.async_get(hass)
|
entity_registry = er.async_get(hass)
|
||||||
platform = getattr(hass.components, "test.sensor")
|
platform = getattr(hass.components, "test.sensor")
|
||||||
platform.init(empty=True)
|
platform.init(empty=True)
|
||||||
@ -1173,7 +1192,7 @@ async def test_suggested_precision_option(
|
|||||||
device_class=device_class,
|
device_class=device_class,
|
||||||
native_unit_of_measurement=native_unit,
|
native_unit_of_measurement=native_unit,
|
||||||
native_value=str(native_value),
|
native_value=str(native_value),
|
||||||
suggested_display_precision=suggested_precision,
|
suggested_display_precision=integration_suggested_precision,
|
||||||
unique_id="very_unique",
|
unique_id="very_unique",
|
||||||
)
|
)
|
||||||
entity0 = platform.ENTITIES["0"]
|
entity0 = platform.ENTITIES["0"]
|
||||||
@ -1183,34 +1202,58 @@ async def test_suggested_precision_option(
|
|||||||
|
|
||||||
# Assert the suggested precision is stored in the registry
|
# Assert the suggested precision is stored in the registry
|
||||||
entry = entity_registry.async_get(entity0.entity_id)
|
entry = entity_registry.async_get(entity0.entity_id)
|
||||||
assert entry.options == {
|
assert entry.options == extra_options | {
|
||||||
"sensor": {"suggested_display_precision": suggested_precision}
|
"sensor": {"suggested_display_precision": options_suggested_precision}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"native_unit, old_precision, new_precision, native_value, device_class",
|
"unit_system, native_unit, suggested_unit, old_precision, new_precision,"
|
||||||
|
"opt_precision, native_value, device_class, extra_options",
|
||||||
[
|
[
|
||||||
|
# Distance
|
||||||
(
|
(
|
||||||
|
METRIC_SYSTEM,
|
||||||
|
UnitOfLength.KILOMETERS,
|
||||||
UnitOfLength.KILOMETERS,
|
UnitOfLength.KILOMETERS,
|
||||||
4,
|
4,
|
||||||
1,
|
1,
|
||||||
|
1,
|
||||||
1000,
|
1000,
|
||||||
SensorDeviceClass.DISTANCE,
|
SensorDeviceClass.DISTANCE,
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
# Air pressure
|
||||||
|
(
|
||||||
|
US_CUSTOMARY_SYSTEM,
|
||||||
|
UnitOfPressure.HPA,
|
||||||
|
UnitOfPressure.INHG,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
1000,
|
||||||
|
SensorDeviceClass.ATMOSPHERIC_PRESSURE,
|
||||||
|
{"sensor.private": {"suggested_unit_of_measurement": "inHg"}},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_suggested_precision_option_update(
|
async def test_suggested_precision_option_update(
|
||||||
hass,
|
hass,
|
||||||
enable_custom_integrations,
|
enable_custom_integrations,
|
||||||
|
unit_system,
|
||||||
native_unit,
|
native_unit,
|
||||||
|
suggested_unit,
|
||||||
old_precision,
|
old_precision,
|
||||||
new_precision,
|
new_precision,
|
||||||
|
opt_precision,
|
||||||
native_value,
|
native_value,
|
||||||
device_class,
|
device_class,
|
||||||
|
extra_options,
|
||||||
):
|
):
|
||||||
"""Test suggested precision stored in the registry is updated."""
|
"""Test suggested precision stored in the registry is updated."""
|
||||||
|
|
||||||
|
hass.config.units = unit_system
|
||||||
|
|
||||||
entity_registry = er.async_get(hass)
|
entity_registry = er.async_get(hass)
|
||||||
platform = getattr(hass.components, "test.sensor")
|
platform = getattr(hass.components, "test.sensor")
|
||||||
platform.init(empty=True)
|
platform.init(empty=True)
|
||||||
@ -1228,7 +1271,7 @@ async def test_suggested_precision_option_update(
|
|||||||
entry.entity_id,
|
entry.entity_id,
|
||||||
"sensor.private",
|
"sensor.private",
|
||||||
{
|
{
|
||||||
"suggested_unit_of_measurement": native_unit,
|
"suggested_unit_of_measurement": suggested_unit,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1249,10 +1292,10 @@ async def test_suggested_precision_option_update(
|
|||||||
entry = entity_registry.async_get(entity0.entity_id)
|
entry = entity_registry.async_get(entity0.entity_id)
|
||||||
assert entry.options == {
|
assert entry.options == {
|
||||||
"sensor": {
|
"sensor": {
|
||||||
"suggested_display_precision": new_precision,
|
"suggested_display_precision": opt_precision,
|
||||||
},
|
},
|
||||||
"sensor.private": {
|
"sensor.private": {
|
||||||
"suggested_unit_of_measurement": native_unit,
|
"suggested_unit_of_measurement": suggested_unit,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user