mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Add Beaufort to wind_speed (#105795)
* Add Beaufort to wind_speed * Add Bft to UnitOfSpeed * Update tests with Bft * Remove check for unit * Fix test_deprecated_constants * Test depricated constant Beaufort * Fix test_unit_system.py for Beaufort * Remove _DEPRECATED_SPEED_FEET_BEAUFORT * Remove maxsize from lru_cache * Update test_deprecated_constants * Update comment * Add missing docstring * Apply suggestions from code review --------- Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
parent
f3eb292c2d
commit
385b29bdf5
@ -344,6 +344,7 @@ class SensorDeviceClass(StrEnum):
|
||||
- SI /metric: `mm/d`, `mm/h`, `m/s`, `km/h`
|
||||
- USCS / imperial: `in/d`, `in/h`, `ft/s`, `mph`
|
||||
- Nautical: `kn`
|
||||
- Beaufort: `Beaufort`
|
||||
"""
|
||||
|
||||
SULPHUR_DIOXIDE = "sulphur_dioxide"
|
||||
@ -431,6 +432,7 @@ class SensorDeviceClass(StrEnum):
|
||||
- SI /metric: `m/s`, `km/h`
|
||||
- USCS / imperial: `ft/s`, `mph`
|
||||
- Nautical: `kn`
|
||||
- Beaufort: `Beaufort`
|
||||
"""
|
||||
|
||||
|
||||
|
@ -1214,6 +1214,7 @@ CONCENTRATION_PARTS_PER_BILLION: Final = "ppb"
|
||||
class UnitOfSpeed(StrEnum):
|
||||
"""Speed units."""
|
||||
|
||||
BEAUFORT = "Beaufort"
|
||||
FEET_PER_SECOND = "ft/s"
|
||||
METERS_PER_SECOND = "m/s"
|
||||
KILOMETERS_PER_HOUR = "km/h"
|
||||
|
@ -334,6 +334,7 @@ class SpeedConverter(BaseUnitConverter):
|
||||
UnitOfSpeed.KNOTS: _HRS_TO_SECS / _NAUTICAL_MILE_TO_M,
|
||||
UnitOfSpeed.METERS_PER_SECOND: 1,
|
||||
UnitOfSpeed.MILES_PER_HOUR: _HRS_TO_SECS / _MILE_TO_M,
|
||||
UnitOfSpeed.BEAUFORT: 1,
|
||||
}
|
||||
VALID_UNITS = {
|
||||
UnitOfVolumetricFlux.INCHES_PER_DAY,
|
||||
@ -345,8 +346,73 @@ class SpeedConverter(BaseUnitConverter):
|
||||
UnitOfSpeed.KNOTS,
|
||||
UnitOfSpeed.METERS_PER_SECOND,
|
||||
UnitOfSpeed.MILES_PER_HOUR,
|
||||
UnitOfSpeed.BEAUFORT,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
@lru_cache
|
||||
def converter_factory(
|
||||
cls, from_unit: str | None, to_unit: str | None
|
||||
) -> Callable[[float], float]:
|
||||
"""Return a function to convert a speed from one unit to another."""
|
||||
if from_unit == to_unit:
|
||||
# Return a function that does nothing. This is not
|
||||
# in _converter_factory because we do not want to wrap
|
||||
# it with the None check in converter_factory_allow_none.
|
||||
return lambda value: value
|
||||
|
||||
return cls._converter_factory(from_unit, to_unit)
|
||||
|
||||
@classmethod
|
||||
@lru_cache
|
||||
def converter_factory_allow_none(
|
||||
cls, from_unit: str | None, to_unit: str | None
|
||||
) -> Callable[[float | None], float | None]:
|
||||
"""Return a function to convert a speed from one unit to another which allows None."""
|
||||
if from_unit == to_unit:
|
||||
# Return a function that does nothing. This is not
|
||||
# in _converter_factory because we do not want to wrap
|
||||
# it with the None check in this case.
|
||||
return lambda value: value
|
||||
|
||||
convert = cls._converter_factory(from_unit, to_unit)
|
||||
return lambda value: None if value is None else convert(value)
|
||||
|
||||
@classmethod
|
||||
def _converter_factory(
|
||||
cls, from_unit: str | None, to_unit: str | None
|
||||
) -> Callable[[float], float]:
|
||||
"""Convert a speed from one unit to another, eg. 14m/s will return 7Bft."""
|
||||
# We cannot use the implementation from BaseUnitConverter here because the
|
||||
# Beaufort scale is not a constant value to divide or multiply with.
|
||||
if (
|
||||
from_unit not in SpeedConverter.VALID_UNITS
|
||||
or to_unit not in SpeedConverter.VALID_UNITS
|
||||
):
|
||||
raise HomeAssistantError(
|
||||
UNIT_NOT_RECOGNIZED_TEMPLATE.format(to_unit, cls.UNIT_CLASS)
|
||||
)
|
||||
|
||||
if from_unit == UnitOfSpeed.BEAUFORT:
|
||||
to_ratio = cls._UNIT_CONVERSION[to_unit]
|
||||
return lambda val: cls._beaufort_to_ms(val) * to_ratio
|
||||
if to_unit == UnitOfSpeed.BEAUFORT:
|
||||
from_ratio = cls._UNIT_CONVERSION[from_unit]
|
||||
return lambda val: cls._ms_to_beaufort(val / from_ratio)
|
||||
|
||||
from_ratio, to_ratio = cls._get_from_to_ratio(from_unit, to_unit)
|
||||
return lambda val: (val / from_ratio) * to_ratio
|
||||
|
||||
@classmethod
|
||||
def _ms_to_beaufort(cls, ms: float) -> float:
|
||||
"""Convert a speed in m/s to Beaufort."""
|
||||
return float(round(((ms / 0.836) ** 2) ** (1 / 3)))
|
||||
|
||||
@classmethod
|
||||
def _beaufort_to_ms(cls, beaufort: float) -> float:
|
||||
"""Convert a speed in Beaufort to m/s."""
|
||||
return float(0.836 * beaufort ** (3 / 2))
|
||||
|
||||
|
||||
class TemperatureConverter(BaseUnitConverter):
|
||||
"""Utility to convert temperature values."""
|
||||
|
@ -30,7 +30,18 @@ async def test_device_class_units(
|
||||
msg = await client.receive_json()
|
||||
assert msg["success"]
|
||||
assert msg["result"] == {
|
||||
"units": ["ft/s", "in/d", "in/h", "km/h", "kn", "m/s", "mm/d", "mm/h", "mph"]
|
||||
"units": [
|
||||
"Beaufort",
|
||||
"ft/s",
|
||||
"in/d",
|
||||
"in/h",
|
||||
"km/h",
|
||||
"kn",
|
||||
"m/s",
|
||||
"mm/d",
|
||||
"mm/h",
|
||||
"mph",
|
||||
]
|
||||
}
|
||||
|
||||
# Device class with units which include `None`
|
||||
|
@ -131,7 +131,16 @@ def test_all() -> None:
|
||||
],
|
||||
"PRECIPITATION_",
|
||||
)
|
||||
+ _create_tuples(const.UnitOfSpeed, "SPEED_")
|
||||
+ _create_tuples(
|
||||
[
|
||||
const.UnitOfSpeed.FEET_PER_SECOND,
|
||||
const.UnitOfSpeed.METERS_PER_SECOND,
|
||||
const.UnitOfSpeed.KILOMETERS_PER_HOUR,
|
||||
const.UnitOfSpeed.KNOTS,
|
||||
const.UnitOfSpeed.MILES_PER_HOUR,
|
||||
],
|
||||
"SPEED_",
|
||||
)
|
||||
+ _create_tuples(
|
||||
[
|
||||
const.UnitOfVolumetricFlux.MILLIMETERS_PER_DAY,
|
||||
|
@ -413,6 +413,8 @@ _CONVERTED_VALUE: dict[
|
||||
(5, UnitOfSpeed.KNOTS, 2.57222, UnitOfSpeed.METERS_PER_SECOND),
|
||||
# 5 ft/s * 0.3048 m/ft = 1.524 m/s
|
||||
(5, UnitOfSpeed.FEET_PER_SECOND, 1.524, UnitOfSpeed.METERS_PER_SECOND),
|
||||
# float(round(((20.7 m/s / 0.836) ** 2) ** (1 / 3))) = 8.0Bft
|
||||
(20.7, UnitOfSpeed.METERS_PER_SECOND, 8.0, UnitOfSpeed.BEAUFORT),
|
||||
],
|
||||
TemperatureConverter: [
|
||||
(100, UnitOfTemperature.CELSIUS, 212, UnitOfTemperature.FAHRENHEIT),
|
||||
|
@ -515,6 +515,7 @@ UNCONVERTED_UNITS_METRIC_SYSTEM = {
|
||||
UnitOfPressure.PA,
|
||||
),
|
||||
SensorDeviceClass.SPEED: (
|
||||
UnitOfSpeed.BEAUFORT,
|
||||
UnitOfSpeed.KILOMETERS_PER_HOUR,
|
||||
UnitOfSpeed.KNOTS,
|
||||
UnitOfSpeed.METERS_PER_SECOND,
|
||||
@ -723,6 +724,7 @@ UNCONVERTED_UNITS_US_SYSTEM = {
|
||||
),
|
||||
SensorDeviceClass.PRESSURE: (UnitOfPressure.INHG, UnitOfPressure.PSI),
|
||||
SensorDeviceClass.SPEED: (
|
||||
UnitOfSpeed.BEAUFORT,
|
||||
UnitOfSpeed.FEET_PER_SECOND,
|
||||
UnitOfSpeed.KNOTS,
|
||||
UnitOfSpeed.MILES_PER_HOUR,
|
||||
|
Loading…
x
Reference in New Issue
Block a user