mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 13:47:35 +00:00
Enable unit conversion for DATA_RATE (#84698)
This commit is contained in:
parent
c354868270
commit
46e02ebaff
@ -86,6 +86,7 @@ from homeassistant.helpers.typing import ConfigType, StateType
|
|||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
from homeassistant.util.unit_conversion import (
|
from homeassistant.util.unit_conversion import (
|
||||||
BaseUnitConverter,
|
BaseUnitConverter,
|
||||||
|
DataRateConverter,
|
||||||
DistanceConverter,
|
DistanceConverter,
|
||||||
MassConverter,
|
MassConverter,
|
||||||
PressureConverter,
|
PressureConverter,
|
||||||
@ -466,6 +467,7 @@ STATE_CLASSES: Final[list[str]] = [cls.value for cls in SensorStateClass]
|
|||||||
# Note: this needs to be aligned with frontend: OVERRIDE_SENSOR_UNITS in
|
# Note: this needs to be aligned with frontend: OVERRIDE_SENSOR_UNITS in
|
||||||
# `entity-registry-settings.ts`
|
# `entity-registry-settings.ts`
|
||||||
UNIT_CONVERTERS: dict[SensorDeviceClass | str | None, type[BaseUnitConverter]] = {
|
UNIT_CONVERTERS: dict[SensorDeviceClass | str | None, type[BaseUnitConverter]] = {
|
||||||
|
SensorDeviceClass.DATA_RATE: DataRateConverter,
|
||||||
SensorDeviceClass.DISTANCE: DistanceConverter,
|
SensorDeviceClass.DISTANCE: DistanceConverter,
|
||||||
SensorDeviceClass.GAS: VolumeConverter,
|
SensorDeviceClass.GAS: VolumeConverter,
|
||||||
SensorDeviceClass.PRECIPITATION: DistanceConverter,
|
SensorDeviceClass.PRECIPITATION: DistanceConverter,
|
||||||
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
UNIT_NOT_RECOGNIZED_TEMPLATE,
|
UNIT_NOT_RECOGNIZED_TEMPLATE,
|
||||||
|
UnitOfDataRate,
|
||||||
UnitOfEnergy,
|
UnitOfEnergy,
|
||||||
UnitOfLength,
|
UnitOfLength,
|
||||||
UnitOfMass,
|
UnitOfMass,
|
||||||
@ -86,6 +87,28 @@ class BaseUnitConverter:
|
|||||||
return cls._UNIT_CONVERSION[from_unit] / cls._UNIT_CONVERSION[to_unit]
|
return cls._UNIT_CONVERSION[from_unit] / cls._UNIT_CONVERSION[to_unit]
|
||||||
|
|
||||||
|
|
||||||
|
class DataRateConverter(BaseUnitConverter):
|
||||||
|
"""Utility to convert data rate values."""
|
||||||
|
|
||||||
|
UNIT_CLASS = "data_rate"
|
||||||
|
NORMALIZED_UNIT = UnitOfDataRate.BITS_PER_SECOND
|
||||||
|
# Units in terms of bits
|
||||||
|
_UNIT_CONVERSION: dict[str, float] = {
|
||||||
|
UnitOfDataRate.BITS_PER_SECOND: 1,
|
||||||
|
UnitOfDataRate.KILOBITS_PER_SECOND: 1 / 1e3,
|
||||||
|
UnitOfDataRate.MEGABITS_PER_SECOND: 1 / 1e6,
|
||||||
|
UnitOfDataRate.GIGABITS_PER_SECOND: 1 / 1e9,
|
||||||
|
UnitOfDataRate.BYTES_PER_SECOND: 1 / 8,
|
||||||
|
UnitOfDataRate.KILOBYTES_PER_SECOND: 1 / 8e3,
|
||||||
|
UnitOfDataRate.MEGABYTES_PER_SECOND: 1 / 8e6,
|
||||||
|
UnitOfDataRate.GIGABYTES_PER_SECOND: 1 / 8e9,
|
||||||
|
UnitOfDataRate.KIBIBYTES_PER_SECOND: 1 / 2**13,
|
||||||
|
UnitOfDataRate.MEBIBYTES_PER_SECOND: 1 / 2**23,
|
||||||
|
UnitOfDataRate.GIBIBYTES_PER_SECOND: 1 / 2**33,
|
||||||
|
}
|
||||||
|
VALID_UNITS = set(UnitOfDataRate)
|
||||||
|
|
||||||
|
|
||||||
class DistanceConverter(BaseUnitConverter):
|
class DistanceConverter(BaseUnitConverter):
|
||||||
"""Utility to convert distance values."""
|
"""Utility to convert distance values."""
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
UnitOfDataRate,
|
||||||
UnitOfEnergy,
|
UnitOfEnergy,
|
||||||
UnitOfLength,
|
UnitOfLength,
|
||||||
UnitOfMass,
|
UnitOfMass,
|
||||||
@ -15,6 +16,7 @@ from homeassistant.const import (
|
|||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.util.unit_conversion import (
|
from homeassistant.util.unit_conversion import (
|
||||||
BaseUnitConverter,
|
BaseUnitConverter,
|
||||||
|
DataRateConverter,
|
||||||
DistanceConverter,
|
DistanceConverter,
|
||||||
EnergyConverter,
|
EnergyConverter,
|
||||||
MassConverter,
|
MassConverter,
|
||||||
@ -31,6 +33,7 @@ INVALID_SYMBOL = "bob"
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"converter,valid_unit",
|
"converter,valid_unit",
|
||||||
[
|
[
|
||||||
|
(DataRateConverter, UnitOfDataRate.GIBIBYTES_PER_SECOND),
|
||||||
(DistanceConverter, UnitOfLength.KILOMETERS),
|
(DistanceConverter, UnitOfLength.KILOMETERS),
|
||||||
(DistanceConverter, UnitOfLength.METERS),
|
(DistanceConverter, UnitOfLength.METERS),
|
||||||
(DistanceConverter, UnitOfLength.CENTIMETERS),
|
(DistanceConverter, UnitOfLength.CENTIMETERS),
|
||||||
@ -85,6 +88,7 @@ def test_convert_same_unit(converter: type[BaseUnitConverter], valid_unit: str)
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"converter,valid_unit",
|
"converter,valid_unit",
|
||||||
[
|
[
|
||||||
|
(DataRateConverter, UnitOfDataRate.GIBIBYTES_PER_SECOND),
|
||||||
(DistanceConverter, UnitOfLength.KILOMETERS),
|
(DistanceConverter, UnitOfLength.KILOMETERS),
|
||||||
(EnergyConverter, UnitOfEnergy.KILO_WATT_HOUR),
|
(EnergyConverter, UnitOfEnergy.KILO_WATT_HOUR),
|
||||||
(MassConverter, UnitOfMass.GRAMS),
|
(MassConverter, UnitOfMass.GRAMS),
|
||||||
@ -111,6 +115,11 @@ def test_convert_invalid_unit(
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"converter,from_unit,to_unit",
|
"converter,from_unit,to_unit",
|
||||||
[
|
[
|
||||||
|
(
|
||||||
|
DataRateConverter,
|
||||||
|
UnitOfDataRate.BYTES_PER_SECOND,
|
||||||
|
UnitOfDataRate.BITS_PER_SECOND,
|
||||||
|
),
|
||||||
(DistanceConverter, UnitOfLength.KILOMETERS, UnitOfLength.METERS),
|
(DistanceConverter, UnitOfLength.KILOMETERS, UnitOfLength.METERS),
|
||||||
(EnergyConverter, UnitOfEnergy.WATT_HOUR, UnitOfEnergy.KILO_WATT_HOUR),
|
(EnergyConverter, UnitOfEnergy.WATT_HOUR, UnitOfEnergy.KILO_WATT_HOUR),
|
||||||
(MassConverter, UnitOfMass.GRAMS, UnitOfMass.KILOGRAMS),
|
(MassConverter, UnitOfMass.GRAMS, UnitOfMass.KILOGRAMS),
|
||||||
@ -132,6 +141,12 @@ def test_convert_nonnumeric_value(
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"converter,from_unit,to_unit,expected",
|
"converter,from_unit,to_unit,expected",
|
||||||
[
|
[
|
||||||
|
(
|
||||||
|
DataRateConverter,
|
||||||
|
UnitOfDataRate.BITS_PER_SECOND,
|
||||||
|
UnitOfDataRate.BYTES_PER_SECOND,
|
||||||
|
8,
|
||||||
|
),
|
||||||
(DistanceConverter, UnitOfLength.KILOMETERS, UnitOfLength.METERS, 1 / 1000),
|
(DistanceConverter, UnitOfLength.KILOMETERS, UnitOfLength.METERS, 1 / 1000),
|
||||||
(EnergyConverter, UnitOfEnergy.WATT_HOUR, UnitOfEnergy.KILO_WATT_HOUR, 1000),
|
(EnergyConverter, UnitOfEnergy.WATT_HOUR, UnitOfEnergy.KILO_WATT_HOUR, 1000),
|
||||||
(PowerConverter, UnitOfPower.WATT, UnitOfPower.KILO_WATT, 1000),
|
(PowerConverter, UnitOfPower.WATT, UnitOfPower.KILO_WATT, 1000),
|
||||||
@ -168,6 +183,48 @@ def test_get_unit_ratio(
|
|||||||
assert converter.get_unit_ratio(from_unit, to_unit) == expected
|
assert converter.get_unit_ratio(from_unit, to_unit) == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"value,from_unit,expected,to_unit",
|
||||||
|
[
|
||||||
|
(8e3, UnitOfDataRate.BITS_PER_SECOND, 8, UnitOfDataRate.KILOBITS_PER_SECOND),
|
||||||
|
(8e6, UnitOfDataRate.BITS_PER_SECOND, 8, UnitOfDataRate.MEGABITS_PER_SECOND),
|
||||||
|
(8e9, UnitOfDataRate.BITS_PER_SECOND, 8, UnitOfDataRate.GIGABITS_PER_SECOND),
|
||||||
|
(8, UnitOfDataRate.BITS_PER_SECOND, 1, UnitOfDataRate.BYTES_PER_SECOND),
|
||||||
|
(8e3, UnitOfDataRate.BITS_PER_SECOND, 1, UnitOfDataRate.KILOBYTES_PER_SECOND),
|
||||||
|
(8e6, UnitOfDataRate.BITS_PER_SECOND, 1, UnitOfDataRate.MEGABYTES_PER_SECOND),
|
||||||
|
(8e9, UnitOfDataRate.BITS_PER_SECOND, 1, UnitOfDataRate.GIGABYTES_PER_SECOND),
|
||||||
|
(
|
||||||
|
8 * 2**10,
|
||||||
|
UnitOfDataRate.BITS_PER_SECOND,
|
||||||
|
1,
|
||||||
|
UnitOfDataRate.KIBIBYTES_PER_SECOND,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
8 * 2**20,
|
||||||
|
UnitOfDataRate.BITS_PER_SECOND,
|
||||||
|
1,
|
||||||
|
UnitOfDataRate.MEBIBYTES_PER_SECOND,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
8 * 2**30,
|
||||||
|
UnitOfDataRate.BITS_PER_SECOND,
|
||||||
|
1,
|
||||||
|
UnitOfDataRate.GIBIBYTES_PER_SECOND,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_data_rate_convert(
|
||||||
|
value: float,
|
||||||
|
from_unit: str,
|
||||||
|
expected: float,
|
||||||
|
to_unit: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test conversion to other units."""
|
||||||
|
assert DataRateConverter.convert(value, from_unit, to_unit) == pytest.approx(
|
||||||
|
expected
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"value,from_unit,expected,to_unit",
|
"value,from_unit,expected,to_unit",
|
||||||
[
|
[
|
||||||
|
Loading…
x
Reference in New Issue
Block a user