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."""
from __future__ import annotations
from collections.abc import Callable
from contextlib import suppress
from dataclasses import dataclass
from datetime import timedelta
@ -16,8 +15,6 @@ from homeassistant.const import (
PRECISION_HALVES,
PRECISION_TENTHS,
PRECISION_WHOLE,
UnitOfLength,
UnitOfPrecipitationDepth,
UnitOfPressure,
UnitOfSpeed,
UnitOfTemperature,
@ -30,14 +27,27 @@ from homeassistant.helpers.config_validation import ( # noqa: F401
from homeassistant.helpers.entity import Entity, EntityDescription
from homeassistant.helpers.entity_component import EntityComponent
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 .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__)
ATTR_CONDITION_CLASS = "condition_class"
@ -71,20 +81,6 @@ ATTR_FORECAST_TIME: Final = "datetime"
ATTR_FORECAST_WIND_BEARING: Final = "wind_bearing"
ATTR_FORECAST_NATIVE_WIND_SPEED: Final = "native_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 + ".{}"
@ -92,48 +88,6 @@ SCAN_INTERVAL = timedelta(seconds=30)
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
@ -182,6 +136,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
component = hass.data[DOMAIN] = EntityComponent[WeatherEntity](
_LOGGER, DOMAIN, hass, SCAN_INTERVAL
)
async_setup_ws_api(hass)
await component.async_setup(config)
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"]),
}
}