mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 04:07:08 +00:00
Cache sensor precision calculation (#140019)
This commit is contained in:
parent
02e9002466
commit
e2c050ed40
@ -675,22 +675,13 @@ class SensorEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
||||
):
|
||||
# Deduce the precision by finding the decimal point, if any
|
||||
value_s = str(value)
|
||||
precision = (
|
||||
len(value_s) - value_s.index(".") - 1 if "." in value_s else 0
|
||||
)
|
||||
|
||||
# Scale the precision when converting to a larger unit
|
||||
# For example 1.1 Wh should be rendered as 0.0011 kWh, not 0.0 kWh
|
||||
ratio_log = max(
|
||||
0,
|
||||
log10(
|
||||
converter.get_unit_ratio(
|
||||
precision = (
|
||||
len(value_s) - value_s.index(".") - 1 if "." in value_s else 0
|
||||
) + converter.get_unit_floored_log_ratio(
|
||||
native_unit_of_measurement, unit_of_measurement
|
||||
)
|
||||
),
|
||||
)
|
||||
precision = precision + floor(ratio_log)
|
||||
|
||||
value = f"{converted_numerical_value:z.{precision}f}"
|
||||
else:
|
||||
value = converted_numerical_value
|
||||
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from functools import lru_cache
|
||||
from math import floor, log10
|
||||
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
@ -144,6 +145,15 @@ class BaseUnitConverter:
|
||||
from_ratio, to_ratio = cls._get_from_to_ratio(from_unit, to_unit)
|
||||
return from_ratio / to_ratio
|
||||
|
||||
@classmethod
|
||||
@lru_cache
|
||||
def get_unit_floored_log_ratio(
|
||||
cls, from_unit: str | None, to_unit: str | None
|
||||
) -> float:
|
||||
"""Get floored base10 log ratio between units of measurement."""
|
||||
from_ratio, to_ratio = cls._get_from_to_ratio(from_unit, to_unit)
|
||||
return floor(max(0, log10(from_ratio / to_ratio)))
|
||||
|
||||
@classmethod
|
||||
@lru_cache
|
||||
def _are_unit_inverses(cls, from_unit: str | None, to_unit: str | None) -> bool:
|
||||
|
@ -902,8 +902,8 @@ def test_convert_nonnumeric_value(
|
||||
("converter", "from_unit", "to_unit", "expected"),
|
||||
[
|
||||
# Process all items in _GET_UNIT_RATIO
|
||||
(converter, item[0], item[1], item[2])
|
||||
for converter, item in _GET_UNIT_RATIO.items()
|
||||
(converter, from_unit, to_unit, expected)
|
||||
for converter, (from_unit, to_unit, expected) in _GET_UNIT_RATIO.items()
|
||||
],
|
||||
)
|
||||
def test_get_unit_ratio(
|
||||
@ -915,13 +915,34 @@ def test_get_unit_ratio(
|
||||
assert converter.get_unit_ratio(to_unit, from_unit) == pytest.approx(1 / ratio)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("converter", "from_unit", "to_unit", "expected"),
|
||||
[
|
||||
# Process all items in _GET_UNIT_RATIO
|
||||
(converter, from_unit, to_unit, expected)
|
||||
for converter, (from_unit, to_unit, expected) in _GET_UNIT_RATIO.items()
|
||||
],
|
||||
)
|
||||
def get_unit_floored_log_ratio(
|
||||
converter: type[BaseUnitConverter], from_unit: str, to_unit: str, expected: float
|
||||
) -> None:
|
||||
"""Test floored log unit ratio.
|
||||
|
||||
Should not use pytest.approx since we are checking these
|
||||
values are exact.
|
||||
"""
|
||||
ratio = converter.get_unit_floored_log_ratio(from_unit, to_unit)
|
||||
assert ratio == expected
|
||||
assert converter.get_unit_floored_log_ratio(to_unit, from_unit) == 1 / ratio
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("converter", "value", "from_unit", "expected", "to_unit"),
|
||||
[
|
||||
# Process all items in _CONVERTED_VALUE
|
||||
(converter, list_item[0], list_item[1], list_item[2], list_item[3])
|
||||
(converter, value, from_unit, expected, to_unit)
|
||||
for converter, item in _CONVERTED_VALUE.items()
|
||||
for list_item in item
|
||||
for value, from_unit, expected, to_unit in item
|
||||
],
|
||||
)
|
||||
def test_unit_conversion(
|
||||
|
Loading…
x
Reference in New Issue
Block a user