Add WS command weather/convertible_units (#85681)

This commit is contained in:
Erik Montnemery 2023-02-28 11:35:47 +01:00 committed by GitHub
parent 4e66554298
commit b6f66b3568
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 157 additions and 65 deletions

View File

@ -1,7 +1,6 @@
"""Weather component that handles meteorological data for your location.""" """Weather component that handles meteorological data for your location."""
from __future__ import annotations from __future__ import annotations
from collections.abc import Callable
from contextlib import suppress from contextlib import suppress
from dataclasses import dataclass from dataclasses import dataclass
from datetime import timedelta from datetime import timedelta
@ -16,8 +15,6 @@ from homeassistant.const import (
PRECISION_HALVES, PRECISION_HALVES,
PRECISION_TENTHS, PRECISION_TENTHS,
PRECISION_WHOLE, PRECISION_WHOLE,
UnitOfLength,
UnitOfPrecipitationDepth,
UnitOfPressure, UnitOfPressure,
UnitOfSpeed, UnitOfSpeed,
UnitOfTemperature, UnitOfTemperature,
@ -30,14 +27,27 @@ from homeassistant.helpers.config_validation import ( # noqa: F401
from homeassistant.helpers.entity import Entity, EntityDescription from homeassistant.helpers.entity import Entity, EntityDescription
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from homeassistant.util.unit_conversion import (
DistanceConverter,
PressureConverter,
SpeedConverter,
TemperatureConverter,
)
from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
from .const import (
ATTR_WEATHER_HUMIDITY,
ATTR_WEATHER_OZONE,
ATTR_WEATHER_PRECIPITATION_UNIT,
ATTR_WEATHER_PRESSURE,
ATTR_WEATHER_PRESSURE_UNIT,
ATTR_WEATHER_TEMPERATURE,
ATTR_WEATHER_TEMPERATURE_UNIT,
ATTR_WEATHER_VISIBILITY,
ATTR_WEATHER_VISIBILITY_UNIT,
ATTR_WEATHER_WIND_BEARING,
ATTR_WEATHER_WIND_SPEED,
ATTR_WEATHER_WIND_SPEED_UNIT,
DOMAIN,
UNIT_CONVERSIONS,
VALID_UNITS,
)
from .websocket_api import async_setup as async_setup_ws_api
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
ATTR_CONDITION_CLASS = "condition_class" ATTR_CONDITION_CLASS = "condition_class"
@ -71,20 +81,6 @@ ATTR_FORECAST_TIME: Final = "datetime"
ATTR_FORECAST_WIND_BEARING: Final = "wind_bearing" ATTR_FORECAST_WIND_BEARING: Final = "wind_bearing"
ATTR_FORECAST_NATIVE_WIND_SPEED: Final = "native_wind_speed" ATTR_FORECAST_NATIVE_WIND_SPEED: Final = "native_wind_speed"
ATTR_FORECAST_WIND_SPEED: Final = "wind_speed" ATTR_FORECAST_WIND_SPEED: Final = "wind_speed"
ATTR_WEATHER_HUMIDITY = "humidity"
ATTR_WEATHER_OZONE = "ozone"
ATTR_WEATHER_PRESSURE = "pressure"
ATTR_WEATHER_PRESSURE_UNIT = "pressure_unit"
ATTR_WEATHER_TEMPERATURE = "temperature"
ATTR_WEATHER_TEMPERATURE_UNIT = "temperature_unit"
ATTR_WEATHER_VISIBILITY = "visibility"
ATTR_WEATHER_VISIBILITY_UNIT = "visibility_unit"
ATTR_WEATHER_WIND_BEARING = "wind_bearing"
ATTR_WEATHER_WIND_SPEED = "wind_speed"
ATTR_WEATHER_WIND_SPEED_UNIT = "wind_speed_unit"
ATTR_WEATHER_PRECIPITATION_UNIT = "precipitation_unit"
DOMAIN = "weather"
ENTITY_ID_FORMAT = DOMAIN + ".{}" ENTITY_ID_FORMAT = DOMAIN + ".{}"
@ -92,48 +88,6 @@ SCAN_INTERVAL = timedelta(seconds=30)
ROUNDING_PRECISION = 2 ROUNDING_PRECISION = 2
VALID_UNITS_PRESSURE: set[str] = {
UnitOfPressure.HPA,
UnitOfPressure.MBAR,
UnitOfPressure.INHG,
UnitOfPressure.MMHG,
}
VALID_UNITS_TEMPERATURE: set[str] = {
UnitOfTemperature.CELSIUS,
UnitOfTemperature.FAHRENHEIT,
}
VALID_UNITS_PRECIPITATION: set[str] = {
UnitOfPrecipitationDepth.MILLIMETERS,
UnitOfPrecipitationDepth.INCHES,
}
VALID_UNITS_VISIBILITY: set[str] = {
UnitOfLength.KILOMETERS,
UnitOfLength.MILES,
}
VALID_UNITS_WIND_SPEED: set[str] = {
UnitOfSpeed.FEET_PER_SECOND,
UnitOfSpeed.KILOMETERS_PER_HOUR,
UnitOfSpeed.KNOTS,
UnitOfSpeed.METERS_PER_SECOND,
UnitOfSpeed.MILES_PER_HOUR,
}
UNIT_CONVERSIONS: dict[str, Callable[[float, str, str], float]] = {
ATTR_WEATHER_PRESSURE_UNIT: PressureConverter.convert,
ATTR_WEATHER_TEMPERATURE_UNIT: TemperatureConverter.convert,
ATTR_WEATHER_VISIBILITY_UNIT: DistanceConverter.convert,
ATTR_WEATHER_PRECIPITATION_UNIT: DistanceConverter.convert,
ATTR_WEATHER_WIND_SPEED_UNIT: SpeedConverter.convert,
}
VALID_UNITS: dict[str, set[str]] = {
ATTR_WEATHER_PRESSURE_UNIT: VALID_UNITS_PRESSURE,
ATTR_WEATHER_TEMPERATURE_UNIT: VALID_UNITS_TEMPERATURE,
ATTR_WEATHER_VISIBILITY_UNIT: VALID_UNITS_VISIBILITY,
ATTR_WEATHER_PRECIPITATION_UNIT: VALID_UNITS_PRECIPITATION,
ATTR_WEATHER_WIND_SPEED_UNIT: VALID_UNITS_WIND_SPEED,
}
# mypy: disallow-any-generics # mypy: disallow-any-generics
@ -182,6 +136,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
component = hass.data[DOMAIN] = EntityComponent[WeatherEntity]( component = hass.data[DOMAIN] = EntityComponent[WeatherEntity](
_LOGGER, DOMAIN, hass, SCAN_INTERVAL _LOGGER, DOMAIN, hass, SCAN_INTERVAL
) )
async_setup_ws_api(hass)
await component.async_setup(config) await component.async_setup(config)
return True return True

View File

@ -0,0 +1,76 @@
"""Constants for weather."""
from __future__ import annotations
from collections.abc import Callable
from typing import Final
from homeassistant.const import (
UnitOfLength,
UnitOfPrecipitationDepth,
UnitOfPressure,
UnitOfSpeed,
UnitOfTemperature,
)
from homeassistant.util.unit_conversion import (
DistanceConverter,
PressureConverter,
SpeedConverter,
TemperatureConverter,
)
ATTR_WEATHER_HUMIDITY = "humidity"
ATTR_WEATHER_OZONE = "ozone"
ATTR_WEATHER_PRESSURE = "pressure"
ATTR_WEATHER_PRESSURE_UNIT = "pressure_unit"
ATTR_WEATHER_TEMPERATURE = "temperature"
ATTR_WEATHER_TEMPERATURE_UNIT = "temperature_unit"
ATTR_WEATHER_VISIBILITY = "visibility"
ATTR_WEATHER_VISIBILITY_UNIT = "visibility_unit"
ATTR_WEATHER_WIND_BEARING = "wind_bearing"
ATTR_WEATHER_WIND_SPEED = "wind_speed"
ATTR_WEATHER_WIND_SPEED_UNIT = "wind_speed_unit"
ATTR_WEATHER_PRECIPITATION_UNIT = "precipitation_unit"
DOMAIN: Final = "weather"
VALID_UNITS_PRESSURE: set[str] = {
UnitOfPressure.HPA,
UnitOfPressure.MBAR,
UnitOfPressure.INHG,
UnitOfPressure.MMHG,
}
VALID_UNITS_TEMPERATURE: set[str] = {
UnitOfTemperature.CELSIUS,
UnitOfTemperature.FAHRENHEIT,
}
VALID_UNITS_PRECIPITATION: set[str] = {
UnitOfPrecipitationDepth.MILLIMETERS,
UnitOfPrecipitationDepth.INCHES,
}
VALID_UNITS_VISIBILITY: set[str] = {
UnitOfLength.KILOMETERS,
UnitOfLength.MILES,
}
VALID_UNITS_WIND_SPEED: set[str] = {
UnitOfSpeed.FEET_PER_SECOND,
UnitOfSpeed.KILOMETERS_PER_HOUR,
UnitOfSpeed.KNOTS,
UnitOfSpeed.METERS_PER_SECOND,
UnitOfSpeed.MILES_PER_HOUR,
}
UNIT_CONVERSIONS: dict[str, Callable[[float, str, str], float]] = {
ATTR_WEATHER_PRESSURE_UNIT: PressureConverter.convert,
ATTR_WEATHER_TEMPERATURE_UNIT: TemperatureConverter.convert,
ATTR_WEATHER_VISIBILITY_UNIT: DistanceConverter.convert,
ATTR_WEATHER_PRECIPITATION_UNIT: DistanceConverter.convert,
ATTR_WEATHER_WIND_SPEED_UNIT: SpeedConverter.convert,
}
VALID_UNITS: dict[str, set[str]] = {
ATTR_WEATHER_PRESSURE_UNIT: VALID_UNITS_PRESSURE,
ATTR_WEATHER_TEMPERATURE_UNIT: VALID_UNITS_TEMPERATURE,
ATTR_WEATHER_VISIBILITY_UNIT: VALID_UNITS_VISIBILITY,
ATTR_WEATHER_PRECIPITATION_UNIT: VALID_UNITS_PRECIPITATION,
ATTR_WEATHER_WIND_SPEED_UNIT: VALID_UNITS_WIND_SPEED,
}

View File

@ -0,0 +1,30 @@
"""The weather websocket API."""
from __future__ import annotations
from typing import Any
import voluptuous as vol
from homeassistant.components import websocket_api
from homeassistant.core import HomeAssistant, callback
from .const import VALID_UNITS
@callback
def async_setup(hass: HomeAssistant) -> None:
"""Set up the weather websocket API."""
websocket_api.async_register_command(hass, ws_convertible_units)
@callback
@websocket_api.websocket_command(
{
vol.Required("type"): "weather/convertible_units",
}
)
def ws_convertible_units(
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any]
) -> None:
"""Return supported units for a device class."""
connection.send_result(msg["id"], {"units": VALID_UNITS})

View File

@ -0,0 +1,31 @@
"""Test the weather websocket API."""
from pytest_unordered import unordered
from homeassistant.components.weather.const import DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
async def test_device_class_units(hass: HomeAssistant, hass_ws_client) -> None:
"""Test we can get supported units."""
assert await async_setup_component(hass, DOMAIN, {})
client = await hass_ws_client(hass)
await client.send_json(
{
"id": 1,
"type": "weather/convertible_units",
}
)
msg = await client.receive_json()
assert msg["success"]
assert msg["result"] == {
"units": {
"precipitation_unit": unordered(["mm", "in"]),
"pressure_unit": unordered(["mbar", "mmHg", "inHg", "hPa"]),
"temperature_unit": unordered(["°F", "°C"]),
"visibility_unit": unordered(["km", "mi"]),
"wind_speed_unit": unordered(["mph", "km/h", "kn", "m/s", "ft/s"]),
}
}