diff --git a/homeassistant/components/number/__init__.py b/homeassistant/components/number/__init__.py index e4ed8bb1d3e..0cdb9465360 100644 --- a/homeassistant/components/number/__init__.py +++ b/homeassistant/components/number/__init__.py @@ -24,7 +24,6 @@ from homeassistant.helpers.entity import Entity, EntityDescription from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.restore_state import ExtraStoredData, RestoreEntity from homeassistant.helpers.typing import ConfigType -from homeassistant.util.unit_conversion import BaseUnitConverter, TemperatureConverter from .const import ( ATTR_MAX, @@ -36,7 +35,10 @@ from .const import ( DEFAULT_STEP, DOMAIN, SERVICE_SET_VALUE, + UNIT_CONVERTERS, + NumberDeviceClass, ) +from .websocket_api import async_setup as async_setup_ws_api SCAN_INTERVAL = timedelta(seconds=30) @@ -46,297 +48,6 @@ MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) _LOGGER = logging.getLogger(__name__) - -class NumberDeviceClass(StrEnum): - """Device class for numbers.""" - - # NumberDeviceClass should be aligned with SensorDeviceClass - - APPARENT_POWER = "apparent_power" - """Apparent power. - - Unit of measurement: `VA` - """ - - AQI = "aqi" - """Air Quality Index. - - Unit of measurement: `None` - """ - - ATMOSPHERIC_PRESSURE = "atmospheric_pressure" - """Atmospheric pressure. - - Unit of measurement: `UnitOfPressure` units - """ - - BATTERY = "battery" - """Percentage of battery that is left. - - Unit of measurement: `%` - """ - - CO = "carbon_monoxide" - """Carbon Monoxide gas concentration. - - Unit of measurement: `ppm` (parts per million) - """ - - CO2 = "carbon_dioxide" - """Carbon Dioxide gas concentration. - - Unit of measurement: `ppm` (parts per million) - """ - - CURRENT = "current" - """Current. - - Unit of measurement: `A`, `mA` - """ - - DATA_RATE = "data_rate" - """Data rate. - - Unit of measurement: UnitOfDataRate - """ - - DATA_SIZE = "data_size" - """Data size. - - Unit of measurement: UnitOfInformation - """ - - DISTANCE = "distance" - """Generic distance. - - Unit of measurement: `LENGTH_*` units - - SI /metric: `mm`, `cm`, `m`, `km` - - USCS / imperial: `in`, `ft`, `yd`, `mi` - """ - - ENERGY = "energy" - """Energy. - - Unit of measurement: `Wh`, `kWh`, `MWh`, `GJ` - """ - - FREQUENCY = "frequency" - """Frequency. - - Unit of measurement: `Hz`, `kHz`, `MHz`, `GHz` - """ - - GAS = "gas" - """Gas. - - Unit of measurement: - - SI / metric: `m³` - - USCS / imperial: `ft³`, `CCF` - """ - - HUMIDITY = "humidity" - """Relative humidity. - - Unit of measurement: `%` - """ - - ILLUMINANCE = "illuminance" - """Illuminance. - - Unit of measurement: `lx` - """ - - IRRADIANCE = "irradiance" - """Irradiance. - - Unit of measurement: - - SI / metric: `W/m²` - - USCS / imperial: `BTU/(h⋅ft²)` - """ - - MOISTURE = "moisture" - """Moisture. - - Unit of measurement: `%` - """ - - MONETARY = "monetary" - """Amount of money. - - Unit of measurement: ISO4217 currency code - - See https://en.wikipedia.org/wiki/ISO_4217#Active_codes for active codes - """ - - NITROGEN_DIOXIDE = "nitrogen_dioxide" - """Amount of NO2. - - Unit of measurement: `µg/m³` - """ - - NITROGEN_MONOXIDE = "nitrogen_monoxide" - """Amount of NO. - - Unit of measurement: `µg/m³` - """ - - NITROUS_OXIDE = "nitrous_oxide" - """Amount of N2O. - - Unit of measurement: `µg/m³` - """ - - OZONE = "ozone" - """Amount of O3. - - Unit of measurement: `µg/m³` - """ - - PM1 = "pm1" - """Particulate matter <= 0.1 μm. - - Unit of measurement: `µg/m³` - """ - - PM10 = "pm10" - """Particulate matter <= 10 μm. - - Unit of measurement: `µg/m³` - """ - - PM25 = "pm25" - """Particulate matter <= 2.5 μm. - - Unit of measurement: `µg/m³` - """ - - POWER_FACTOR = "power_factor" - """Power factor. - - Unit of measurement: `%`, `None` - """ - - POWER = "power" - """Power. - - Unit of measurement: `W`, `kW` - """ - - PRECIPITATION = "precipitation" - """Accumulated precipitation. - - Unit of measurement: UnitOfPrecipitationDepth - - SI / metric: `cm`, `mm` - - USCS / imperial: `in` - """ - - PRECIPITATION_INTENSITY = "precipitation_intensity" - """Precipitation intensity. - - Unit of measurement: UnitOfVolumetricFlux - - SI /metric: `mm/d`, `mm/h` - - USCS / imperial: `in/d`, `in/h` - """ - - PRESSURE = "pressure" - """Pressure. - - Unit of measurement: - - `mbar`, `cbar`, `bar` - - `Pa`, `hPa`, `kPa` - - `inHg` - - `psi` - """ - - REACTIVE_POWER = "reactive_power" - """Reactive power. - - Unit of measurement: `var` - """ - - SIGNAL_STRENGTH = "signal_strength" - """Signal strength. - - Unit of measurement: `dB`, `dBm` - """ - - SOUND_PRESSURE = "sound_pressure" - """Sound pressure. - - Unit of measurement: `dB`, `dBA` - """ - - SPEED = "speed" - """Generic speed. - - Unit of measurement: `SPEED_*` units or `UnitOfVolumetricFlux` - - SI /metric: `mm/d`, `mm/h`, `m/s`, `km/h` - - USCS / imperial: `in/d`, `in/h`, `ft/s`, `mph` - - Nautical: `kn` - """ - - SULPHUR_DIOXIDE = "sulphur_dioxide" - """Amount of SO2. - - Unit of measurement: `µg/m³` - """ - - TEMPERATURE = "temperature" - """Temperature. - - Unit of measurement: `°C`, `°F` - """ - - VOLATILE_ORGANIC_COMPOUNDS = "volatile_organic_compounds" - """Amount of VOC. - - Unit of measurement: `µg/m³` - """ - - VOLTAGE = "voltage" - """Voltage. - - Unit of measurement: `V`, `mV` - """ - - VOLUME = "volume" - """Generic volume. - - Unit of measurement: `VOLUME_*` units - - SI / metric: `mL`, `L`, `m³` - - USCS / imperial: `ft³`, `CCF`, `fl. oz.`, `gal` (warning: volumes expressed in - USCS/imperial units are currently assumed to be US volumes) - """ - - WATER = "water" - """Water. - - Unit of measurement: - - SI / metric: `m³`, `L` - - USCS / imperial: `ft³`, `CCF`, `gal` (warning: volumes expressed in - USCS/imperial units are currently assumed to be US volumes) - """ - - WEIGHT = "weight" - """Generic weight, represents a measurement of an object's mass. - - Weight is used instead of mass to fit with every day language. - - Unit of measurement: `MASS_*` units - - SI / metric: `µg`, `mg`, `g`, `kg` - - USCS / imperial: `oz`, `lb` - """ - - WIND_SPEED = "wind_speed" - """Wind speed. - - Unit of measurement: `SPEED_*` units - - SI /metric: `m/s`, `km/h` - - USCS / imperial: `ft/s`, `mph` - - Nautical: `kn` - """ - - DEVICE_CLASSES_SCHEMA: Final = vol.All(vol.Lower, vol.Coerce(NumberDeviceClass)) @@ -348,10 +59,6 @@ class NumberMode(StrEnum): SLIDER = "slider" -UNIT_CONVERTERS: dict[str, type[BaseUnitConverter]] = { - NumberDeviceClass.TEMPERATURE: TemperatureConverter, -} - # mypy: disallow-any-generics @@ -360,6 +67,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: component = hass.data[DOMAIN] = EntityComponent[NumberEntity]( _LOGGER, DOMAIN, hass, SCAN_INTERVAL ) + async_setup_ws_api(hass) await component.async_setup(config) component.async_register_entity_service( diff --git a/homeassistant/components/number/const.py b/homeassistant/components/number/const.py index 50390e7ab81..e9c4c741e54 100644 --- a/homeassistant/components/number/const.py +++ b/homeassistant/components/number/const.py @@ -1,7 +1,38 @@ """Provides the constants needed for the component.""" +from __future__ import annotations from typing import Final +from homeassistant.backports.enum import StrEnum +from homeassistant.const import ( + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + CONCENTRATION_PARTS_PER_MILLION, + LIGHT_LUX, + PERCENTAGE, + POWER_VOLT_AMPERE_REACTIVE, + SIGNAL_STRENGTH_DECIBELS, + SIGNAL_STRENGTH_DECIBELS_MILLIWATT, + UnitOfApparentPower, + UnitOfDataRate, + UnitOfElectricCurrent, + UnitOfElectricPotential, + UnitOfEnergy, + UnitOfFrequency, + UnitOfInformation, + UnitOfIrradiance, + UnitOfLength, + UnitOfMass, + UnitOfPower, + UnitOfPrecipitationDepth, + UnitOfPressure, + UnitOfSoundPressure, + UnitOfSpeed, + UnitOfTemperature, + UnitOfVolume, + UnitOfVolumetricFlux, +) +from homeassistant.util.unit_conversion import BaseUnitConverter, TemperatureConverter + ATTR_VALUE = "value" ATTR_MIN = "min" ATTR_MAX = "max" @@ -19,3 +50,360 @@ SERVICE_SET_VALUE = "set_value" MODE_AUTO: Final = "auto" MODE_BOX: Final = "box" MODE_SLIDER: Final = "slider" + + +class NumberDeviceClass(StrEnum): + """Device class for numbers.""" + + # NumberDeviceClass should be aligned with NumberDeviceClass + + APPARENT_POWER = "apparent_power" + """Apparent power. + + Unit of measurement: `VA` + """ + + AQI = "aqi" + """Air Quality Index. + + Unit of measurement: `None` + """ + + ATMOSPHERIC_PRESSURE = "atmospheric_pressure" + """Atmospheric pressure. + + Unit of measurement: `UnitOfPressure` units + """ + + BATTERY = "battery" + """Percentage of battery that is left. + + Unit of measurement: `%` + """ + + CO = "carbon_monoxide" + """Carbon Monoxide gas concentration. + + Unit of measurement: `ppm` (parts per million) + """ + + CO2 = "carbon_dioxide" + """Carbon Dioxide gas concentration. + + Unit of measurement: `ppm` (parts per million) + """ + + CURRENT = "current" + """Current. + + Unit of measurement: `A`, `mA` + """ + + DATA_RATE = "data_rate" + """Data rate. + + Unit of measurement: UnitOfDataRate + """ + + DATA_SIZE = "data_size" + """Data size. + + Unit of measurement: UnitOfInformation + """ + + DISTANCE = "distance" + """Generic distance. + + Unit of measurement: `LENGTH_*` units + - SI /metric: `mm`, `cm`, `m`, `km` + - USCS / imperial: `in`, `ft`, `yd`, `mi` + """ + + ENERGY = "energy" + """Energy. + + Unit of measurement: `Wh`, `kWh`, `MWh`, `GJ` + """ + + FREQUENCY = "frequency" + """Frequency. + + Unit of measurement: `Hz`, `kHz`, `MHz`, `GHz` + """ + + GAS = "gas" + """Gas. + + Unit of measurement: + - SI / metric: `m³` + - USCS / imperial: `ft³`, `CCF` + """ + + HUMIDITY = "humidity" + """Relative humidity. + + Unit of measurement: `%` + """ + + ILLUMINANCE = "illuminance" + """Illuminance. + + Unit of measurement: `lx` + """ + + IRRADIANCE = "irradiance" + """Irradiance. + + Unit of measurement: + - SI / metric: `W/m²` + - USCS / imperial: `BTU/(h⋅ft²)` + """ + + MOISTURE = "moisture" + """Moisture. + + Unit of measurement: `%` + """ + + MONETARY = "monetary" + """Amount of money. + + Unit of measurement: ISO4217 currency code + + See https://en.wikipedia.org/wiki/ISO_4217#Active_codes for active codes + """ + + NITROGEN_DIOXIDE = "nitrogen_dioxide" + """Amount of NO2. + + Unit of measurement: `µg/m³` + """ + + NITROGEN_MONOXIDE = "nitrogen_monoxide" + """Amount of NO. + + Unit of measurement: `µg/m³` + """ + + NITROUS_OXIDE = "nitrous_oxide" + """Amount of N2O. + + Unit of measurement: `µg/m³` + """ + + OZONE = "ozone" + """Amount of O3. + + Unit of measurement: `µg/m³` + """ + + PM1 = "pm1" + """Particulate matter <= 0.1 μm. + + Unit of measurement: `µg/m³` + """ + + PM10 = "pm10" + """Particulate matter <= 10 μm. + + Unit of measurement: `µg/m³` + """ + + PM25 = "pm25" + """Particulate matter <= 2.5 μm. + + Unit of measurement: `µg/m³` + """ + + POWER_FACTOR = "power_factor" + """Power factor. + + Unit of measurement: `%`, `None` + """ + + POWER = "power" + """Power. + + Unit of measurement: `W`, `kW` + """ + + PRECIPITATION = "precipitation" + """Accumulated precipitation. + + Unit of measurement: UnitOfPrecipitationDepth + - SI / metric: `cm`, `mm` + - USCS / imperial: `in` + """ + + PRECIPITATION_INTENSITY = "precipitation_intensity" + """Precipitation intensity. + + Unit of measurement: UnitOfVolumetricFlux + - SI /metric: `mm/d`, `mm/h` + - USCS / imperial: `in/d`, `in/h` + """ + + PRESSURE = "pressure" + """Pressure. + + Unit of measurement: + - `mbar`, `cbar`, `bar` + - `Pa`, `hPa`, `kPa` + - `inHg` + - `psi` + """ + + REACTIVE_POWER = "reactive_power" + """Reactive power. + + Unit of measurement: `var` + """ + + SIGNAL_STRENGTH = "signal_strength" + """Signal strength. + + Unit of measurement: `dB`, `dBm` + """ + + SOUND_PRESSURE = "sound_pressure" + """Sound pressure. + + Unit of measurement: `dB`, `dBA` + """ + + SPEED = "speed" + """Generic speed. + + Unit of measurement: `SPEED_*` units or `UnitOfVolumetricFlux` + - SI /metric: `mm/d`, `mm/h`, `m/s`, `km/h` + - USCS / imperial: `in/d`, `in/h`, `ft/s`, `mph` + - Nautical: `kn` + """ + + SULPHUR_DIOXIDE = "sulphur_dioxide" + """Amount of SO2. + + Unit of measurement: `µg/m³` + """ + + TEMPERATURE = "temperature" + """Temperature. + + Unit of measurement: `°C`, `°F` + """ + + VOLATILE_ORGANIC_COMPOUNDS = "volatile_organic_compounds" + """Amount of VOC. + + Unit of measurement: `µg/m³` + """ + + VOLTAGE = "voltage" + """Voltage. + + Unit of measurement: `V`, `mV` + """ + + VOLUME = "volume" + """Generic volume. + + Unit of measurement: `VOLUME_*` units + - SI / metric: `mL`, `L`, `m³` + - USCS / imperial: `ft³`, `CCF`, `fl. oz.`, `gal` (warning: volumes expressed in + USCS/imperial units are currently assumed to be US volumes) + """ + + WATER = "water" + """Water. + + Unit of measurement: + - SI / metric: `m³`, `L` + - USCS / imperial: `ft³`, `CCF`, `gal` (warning: volumes expressed in + USCS/imperial units are currently assumed to be US volumes) + """ + + WEIGHT = "weight" + """Generic weight, represents a measurement of an object's mass. + + Weight is used instead of mass to fit with every day language. + + Unit of measurement: `MASS_*` units + - SI / metric: `µg`, `mg`, `g`, `kg` + - USCS / imperial: `oz`, `lb` + """ + + WIND_SPEED = "wind_speed" + """Wind speed. + + Unit of measurement: `SPEED_*` units + - SI /metric: `m/s`, `km/h` + - USCS / imperial: `ft/s`, `mph` + - Nautical: `kn` + """ + + +DEVICE_CLASS_UNITS: dict[NumberDeviceClass, set[type[StrEnum] | str | None]] = { + NumberDeviceClass.APPARENT_POWER: set(UnitOfApparentPower), + NumberDeviceClass.AQI: {None}, + NumberDeviceClass.ATMOSPHERIC_PRESSURE: set(UnitOfPressure), + NumberDeviceClass.BATTERY: {PERCENTAGE}, + NumberDeviceClass.CO: {CONCENTRATION_PARTS_PER_MILLION}, + NumberDeviceClass.CO2: {CONCENTRATION_PARTS_PER_MILLION}, + NumberDeviceClass.CURRENT: set(UnitOfElectricCurrent), + NumberDeviceClass.DATA_RATE: set(UnitOfDataRate), + NumberDeviceClass.DATA_SIZE: set(UnitOfInformation), + NumberDeviceClass.DISTANCE: set(UnitOfLength), + NumberDeviceClass.ENERGY: set(UnitOfEnergy), + NumberDeviceClass.FREQUENCY: set(UnitOfFrequency), + NumberDeviceClass.GAS: { + UnitOfVolume.CENTUM_CUBIC_FEET, + UnitOfVolume.CUBIC_FEET, + UnitOfVolume.CUBIC_METERS, + }, + NumberDeviceClass.HUMIDITY: {PERCENTAGE}, + NumberDeviceClass.ILLUMINANCE: {LIGHT_LUX}, + NumberDeviceClass.IRRADIANCE: set(UnitOfIrradiance), + NumberDeviceClass.MOISTURE: {PERCENTAGE}, + NumberDeviceClass.NITROGEN_DIOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + NumberDeviceClass.NITROGEN_MONOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + NumberDeviceClass.NITROUS_OXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + NumberDeviceClass.OZONE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + NumberDeviceClass.PM1: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + NumberDeviceClass.PM10: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + NumberDeviceClass.PM25: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + NumberDeviceClass.POWER_FACTOR: {PERCENTAGE, None}, + NumberDeviceClass.POWER: {UnitOfPower.WATT, UnitOfPower.KILO_WATT}, + NumberDeviceClass.PRECIPITATION: set(UnitOfPrecipitationDepth), + NumberDeviceClass.PRECIPITATION_INTENSITY: set(UnitOfVolumetricFlux), + NumberDeviceClass.PRESSURE: set(UnitOfPressure), + NumberDeviceClass.REACTIVE_POWER: {POWER_VOLT_AMPERE_REACTIVE}, + NumberDeviceClass.SIGNAL_STRENGTH: { + SIGNAL_STRENGTH_DECIBELS, + SIGNAL_STRENGTH_DECIBELS_MILLIWATT, + }, + NumberDeviceClass.SOUND_PRESSURE: set(UnitOfSoundPressure), + NumberDeviceClass.SPEED: set(UnitOfSpeed).union(set(UnitOfVolumetricFlux)), + NumberDeviceClass.SULPHUR_DIOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + NumberDeviceClass.TEMPERATURE: { + UnitOfTemperature.CELSIUS, + UnitOfTemperature.FAHRENHEIT, + }, + NumberDeviceClass.VOLATILE_ORGANIC_COMPOUNDS: { + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER + }, + NumberDeviceClass.VOLTAGE: set(UnitOfElectricPotential), + NumberDeviceClass.VOLUME: set(UnitOfVolume), + NumberDeviceClass.WATER: { + UnitOfVolume.CENTUM_CUBIC_FEET, + UnitOfVolume.CUBIC_FEET, + UnitOfVolume.CUBIC_METERS, + UnitOfVolume.GALLONS, + UnitOfVolume.LITERS, + }, + NumberDeviceClass.WEIGHT: set(UnitOfMass), + NumberDeviceClass.WIND_SPEED: set(UnitOfSpeed), +} + +UNIT_CONVERTERS: dict[str, type[BaseUnitConverter]] = { + NumberDeviceClass.TEMPERATURE: TemperatureConverter, +} diff --git a/homeassistant/components/number/websocket_api.py b/homeassistant/components/number/websocket_api.py new file mode 100644 index 00000000000..eca280d7d43 --- /dev/null +++ b/homeassistant/components/number/websocket_api.py @@ -0,0 +1,35 @@ +"""The sensor 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 DEVICE_CLASS_UNITS, UNIT_CONVERTERS + + +@callback +def async_setup(hass: HomeAssistant) -> None: + """Set up the number websocket API.""" + websocket_api.async_register_command(hass, ws_device_class_units) + + +@callback +@websocket_api.websocket_command( + { + vol.Required("type"): "number/device_class_convertible_units", + vol.Required("device_class"): str, + } +) +def ws_device_class_units( + hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any] +) -> None: + """Return supported units for a device class.""" + device_class = msg["device_class"] + convertible_units = set() + if device_class in UNIT_CONVERTERS and device_class in DEVICE_CLASS_UNITS: + convertible_units = DEVICE_CLASS_UNITS[device_class] + connection.send_result(msg["id"], {"units": convertible_units}) diff --git a/tests/components/number/test_init.py b/tests/components/number/test_init.py index f6b2c615123..e65913f1461 100644 --- a/tests/components/number/test_init.py +++ b/tests/components/number/test_init.py @@ -14,7 +14,13 @@ from homeassistant.components.number import ( NumberEntity, NumberEntityDescription, ) -from homeassistant.components.sensor import SensorDeviceClass +from homeassistant.components.number.const import ( + DEVICE_CLASS_UNITS as NUMBER_DEVICE_CLASS_UNITS, +) +from homeassistant.components.sensor import ( + DEVICE_CLASS_UNITS as SENSOR_DEVICE_CLASS_UNITS, + SensorDeviceClass, +) from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_UNIT_OF_MEASUREMENT, @@ -867,3 +873,11 @@ def test_device_classes_aligned(): assert hasattr(NumberDeviceClass, device_class.name) assert getattr(NumberDeviceClass, device_class.name).value == device_class.value + + for device_class in SENSOR_DEVICE_CLASS_UNITS: + if device_class in non_numeric_device_classes: + continue + assert ( + SENSOR_DEVICE_CLASS_UNITS[device_class] + == NUMBER_DEVICE_CLASS_UNITS[device_class] + ) diff --git a/tests/components/number/test_websocket_api.py b/tests/components/number/test_websocket_api.py new file mode 100644 index 00000000000..f920fddd420 --- /dev/null +++ b/tests/components/number/test_websocket_api.py @@ -0,0 +1,49 @@ +"""Test the number websocket API.""" +from pytest_unordered import unordered + +from homeassistant.components.number.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) + + # Device class with units which number allows customizing & converting + await client.send_json( + { + "id": 1, + "type": "number/device_class_convertible_units", + "device_class": "temperature", + } + ) + msg = await client.receive_json() + assert msg["success"] + assert msg["result"] == {"units": unordered(["°F", "°C"])} + + # Device class with units which number doesn't allow customizing & converting + await client.send_json( + { + "id": 2, + "type": "number/device_class_convertible_units", + "device_class": "energy", + } + ) + msg = await client.receive_json() + assert msg["success"] + assert msg["result"] == {"units": []} + + # Unknown device class + await client.send_json( + { + "id": 3, + "type": "number/device_class_convertible_units", + "device_class": "kebabsås", + } + ) + msg = await client.receive_json() + assert msg["success"] + assert msg["result"] == {"units": unordered([])}