From 439b35c3102a0449154451b746d78825242c4189 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Wed, 4 Jan 2023 19:47:10 +0100 Subject: [PATCH] Fix Z-Wave JS sensor units and device classes (#85129) fixes undefined --- .../zwave_js/discovery_data_template.py | 31 +-- .../components/zwave_js/manifest.json | 2 +- homeassistant/components/zwave_js/sensor.py | 178 +++++++++++++++--- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/zwave_js/test_sensor.py | 59 ++++-- 6 files changed, 214 insertions(+), 60 deletions(-) diff --git a/homeassistant/components/zwave_js/discovery_data_template.py b/homeassistant/components/zwave_js/discovery_data_template.py index 5f43d802e30..7d9f20b111e 100644 --- a/homeassistant/components/zwave_js/discovery_data_template.py +++ b/homeassistant/components/zwave_js/discovery_data_template.py @@ -34,6 +34,7 @@ from zwave_js_server.const.command_class.multilevel_sensor import ( PRESSURE_SENSORS, SIGNAL_STRENGTH_SENSORS, TEMPERATURE_SENSORS, + UNIT_A_WEIGHTED_DECIBELS, UNIT_AMPERE as SENSOR_UNIT_AMPERE, UNIT_BTU_H, UNIT_CELSIUS, @@ -52,6 +53,7 @@ from zwave_js_server.const.command_class.multilevel_sensor import ( UNIT_INCHES_PER_HOUR, UNIT_KILOGRAM, UNIT_KILOHERTZ, + UNIT_KILOPASCAL, UNIT_LITER, UNIT_LUX, UNIT_M_S, @@ -69,6 +71,7 @@ from zwave_js_server.const.command_class.multilevel_sensor import ( UNIT_RSSI, UNIT_SECOND, UNIT_SYSTOLIC, + UNIT_UV_INDEX, UNIT_VOLT as SENSOR_UNIT_VOLT, UNIT_WATT as SENSOR_UNIT_WATT, UNIT_WATT_PER_SQUARE_METER, @@ -94,8 +97,8 @@ from homeassistant.const import ( DEGREE, LIGHT_LUX, PERCENTAGE, - SIGNAL_STRENGTH_DECIBELS, SIGNAL_STRENGTH_DECIBELS_MILLIWATT, + UV_INDEX, UnitOfElectricCurrent, UnitOfElectricPotential, UnitOfEnergy, @@ -105,6 +108,7 @@ from homeassistant.const import ( UnitOfMass, UnitOfPower, UnitOfPressure, + UnitOfSoundPressure, UnitOfSpeed, UnitOfTemperature, UnitOfTime, @@ -134,7 +138,7 @@ from .const import ( ) from .helpers import ZwaveValueID -METER_DEVICE_CLASS_MAP: dict[str, set[MeterScaleType]] = { +METER_DEVICE_CLASS_MAP: dict[str, list[MeterScaleType]] = { ENTITY_DESC_KEY_CURRENT: CURRENT_METER_TYPES, ENTITY_DESC_KEY_VOLTAGE: VOLTAGE_METER_TYPES, ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING: ENERGY_TOTAL_INCREASING_METER_TYPES, @@ -142,7 +146,7 @@ METER_DEVICE_CLASS_MAP: dict[str, set[MeterScaleType]] = { ENTITY_DESC_KEY_POWER_FACTOR: POWER_FACTOR_METER_TYPES, } -MULTILEVEL_SENSOR_DEVICE_CLASS_MAP: dict[str, set[MultilevelSensorType]] = { +MULTILEVEL_SENSOR_DEVICE_CLASS_MAP: dict[str, list[MultilevelSensorType]] = { ENTITY_DESC_KEY_CO: CO_SENSORS, ENTITY_DESC_KEY_CO2: CO2_SENSORS, ENTITY_DESC_KEY_CURRENT: CURRENT_SENSORS, @@ -156,7 +160,7 @@ MULTILEVEL_SENSOR_DEVICE_CLASS_MAP: dict[str, set[MultilevelSensorType]] = { ENTITY_DESC_KEY_VOLTAGE: VOLTAGE_SENSORS, } -METER_UNIT_MAP: dict[str, set[MeterScaleType]] = { +METER_UNIT_MAP: dict[str, list[MeterScaleType]] = { UnitOfElectricCurrent.AMPERE: METER_UNIT_AMPERE, UnitOfVolume.CUBIC_FEET: UNIT_CUBIC_FEET, UnitOfVolume.CUBIC_METERS: METER_UNIT_CUBIC_METER, @@ -166,7 +170,7 @@ METER_UNIT_MAP: dict[str, set[MeterScaleType]] = { UnitOfPower.WATT: METER_UNIT_WATT, } -MULTILEVEL_SENSOR_UNIT_MAP: dict[str, set[MultilevelSensorScaleType]] = { +MULTILEVEL_SENSOR_UNIT_MAP: dict[str, list[MultilevelSensorScaleType]] = { UnitOfElectricCurrent.AMPERE: SENSOR_UNIT_AMPERE, UnitOfPower.BTU_PER_HOUR: UNIT_BTU_H, UnitOfTemperature.CELSIUS: UNIT_CELSIUS, @@ -174,17 +178,19 @@ MULTILEVEL_SENSOR_UNIT_MAP: dict[str, set[MultilevelSensorScaleType]] = { UnitOfVolumeFlowRate.CUBIC_FEET_PER_MINUTE: UNIT_CUBIC_FEET_PER_MINUTE, UnitOfVolume.CUBIC_METERS: SENSOR_UNIT_CUBIC_METER, UnitOfVolumeFlowRate.CUBIC_METERS_PER_HOUR: UNIT_CUBIC_METER_PER_HOUR, - SIGNAL_STRENGTH_DECIBELS: UNIT_DECIBEL, + UnitOfSoundPressure.DECIBEL: UNIT_DECIBEL, + UnitOfSoundPressure.WEIGHTED_DECIBEL_A: UNIT_A_WEIGHTED_DECIBELS, DEGREE: UNIT_DEGREES, - CONCENTRATION_MICROGRAMS_PER_CUBIC_METER: { + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER: [ *UNIT_DENSITY, *UNIT_MICROGRAM_PER_CUBIC_METER, - }, + ], UnitOfTemperature.FAHRENHEIT: UNIT_FAHRENHEIT, UnitOfLength.FEET: UNIT_FEET, UnitOfVolume.GALLONS: UNIT_GALLONS, UnitOfFrequency.HERTZ: UNIT_HERTZ, UnitOfPressure.INHG: UNIT_INCHES_OF_MERCURY, + UnitOfPressure.KPA: UNIT_KILOPASCAL, UnitOfVolumetricFlux.INCHES_PER_HOUR: UNIT_INCHES_PER_HOUR, UnitOfMass.KILOGRAMS: UNIT_KILOGRAM, UnitOfFrequency.KILOHERTZ: UNIT_KILOHERTZ, @@ -197,7 +203,7 @@ MULTILEVEL_SENSOR_UNIT_MAP: dict[str, set[MultilevelSensorScaleType]] = { UnitOfSpeed.MILES_PER_HOUR: UNIT_MPH, UnitOfSpeed.METERS_PER_SECOND: UNIT_M_S, CONCENTRATION_PARTS_PER_MILLION: UNIT_PARTS_MILLION, - PERCENTAGE: {*UNIT_PERCENTAGE_VALUE, *UNIT_RSSI}, + PERCENTAGE: [*UNIT_PERCENTAGE_VALUE, *UNIT_RSSI], UnitOfMass.POUNDS: UNIT_POUNDS, UnitOfPressure.PSI: UNIT_POUND_PER_SQUARE_INCH, SIGNAL_STRENGTH_DECIBELS_MILLIWATT: UNIT_POWER_LEVEL, @@ -206,6 +212,7 @@ MULTILEVEL_SENSOR_UNIT_MAP: dict[str, set[MultilevelSensorScaleType]] = { UnitOfElectricPotential.VOLT: SENSOR_UNIT_VOLT, UnitOfPower.WATT: SENSOR_UNIT_WATT, UnitOfIrradiance.WATTS_PER_SQUARE_METER: UNIT_WATT_PER_SQUARE_METER, + UV_INDEX: UNIT_UV_INDEX, } _LOGGER = logging.getLogger(__name__) @@ -319,9 +326,9 @@ class NumericSensorDataTemplate(BaseDiscoverySchemaDataTemplate): enum_value: MultilevelSensorType | MultilevelSensorScaleType | MeterScaleType, set_map: Mapping[ str, - set[MultilevelSensorType] - | set[MultilevelSensorScaleType] - | set[MeterScaleType], + list[MultilevelSensorType] + | list[MultilevelSensorScaleType] + | list[MeterScaleType], ], ) -> str | None: """Find a key in a set map that matches a given enum value.""" diff --git a/homeassistant/components/zwave_js/manifest.json b/homeassistant/components/zwave_js/manifest.json index 4dc86fed92c..9b313582eb5 100644 --- a/homeassistant/components/zwave_js/manifest.json +++ b/homeassistant/components/zwave_js/manifest.json @@ -3,7 +3,7 @@ "name": "Z-Wave", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/zwave_js", - "requirements": ["pyserial==3.5", "zwave-js-server-python==0.43.1"], + "requirements": ["pyserial==3.5", "zwave-js-server-python==0.44.0"], "codeowners": ["@home-assistant/z-wave"], "dependencies": ["usb", "http", "websocket_api"], "iot_class": "local_push", diff --git a/homeassistant/components/zwave_js/sensor.py b/homeassistant/components/zwave_js/sensor.py index c3414836ad8..0177d694ed4 100644 --- a/homeassistant/components/zwave_js/sensor.py +++ b/homeassistant/components/zwave_js/sensor.py @@ -24,6 +24,18 @@ from homeassistant.components.sensor import ( SensorStateClass, ) from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ( + CONCENTRATION_PARTS_PER_MILLION, + LIGHT_LUX, + PERCENTAGE, + SIGNAL_STRENGTH_DECIBELS_MILLIWATT, + UnitOfElectricCurrent, + UnitOfElectricPotential, + UnitOfEnergy, + UnitOfPower, + UnitOfPressure, + UnitOfTemperature, +) from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import entity_platform @@ -76,98 +88,207 @@ STATUS_ICON: dict[NodeStatus, str] = { } -ENTITY_DESCRIPTION_KEY_MAP: dict[str, SensorEntityDescription] = { - ENTITY_DESC_KEY_BATTERY: SensorEntityDescription( +# These descriptions should include device class. +ENTITY_DESCRIPTION_KEY_DEVICE_CLASS_MAP: dict[ + tuple[str, str], SensorEntityDescription +] = { + (ENTITY_DESC_KEY_BATTERY, PERCENTAGE): SensorEntityDescription( ENTITY_DESC_KEY_BATTERY, device_class=SensorDeviceClass.BATTERY, entity_category=EntityCategory.DIAGNOSTIC, state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=PERCENTAGE, ), - ENTITY_DESC_KEY_CURRENT: SensorEntityDescription( + (ENTITY_DESC_KEY_CURRENT, UnitOfElectricCurrent.AMPERE): SensorEntityDescription( ENTITY_DESC_KEY_CURRENT, device_class=SensorDeviceClass.CURRENT, state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, ), - ENTITY_DESC_KEY_VOLTAGE: SensorEntityDescription( + (ENTITY_DESC_KEY_VOLTAGE, UnitOfElectricPotential.VOLT): SensorEntityDescription( ENTITY_DESC_KEY_VOLTAGE, device_class=SensorDeviceClass.VOLTAGE, state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=UnitOfElectricPotential.VOLT, ), - ENTITY_DESC_KEY_ENERGY_MEASUREMENT: SensorEntityDescription( - ENTITY_DESC_KEY_ENERGY_MEASUREMENT, - device_class=SensorDeviceClass.ENERGY, + ( + ENTITY_DESC_KEY_VOLTAGE, + UnitOfElectricPotential.MILLIVOLT, + ): SensorEntityDescription( + ENTITY_DESC_KEY_VOLTAGE, + device_class=SensorDeviceClass.VOLTAGE, state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=UnitOfElectricPotential.MILLIVOLT, ), - ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING: SensorEntityDescription( + ( + ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING, + UnitOfEnergy.KILO_WATT_HOUR, + ): SensorEntityDescription( ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING, device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL_INCREASING, + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, ), - ENTITY_DESC_KEY_POWER: SensorEntityDescription( + (ENTITY_DESC_KEY_POWER, UnitOfPower.WATT): SensorEntityDescription( ENTITY_DESC_KEY_POWER, device_class=SensorDeviceClass.POWER, state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=UnitOfPower.WATT, ), - ENTITY_DESC_KEY_POWER_FACTOR: SensorEntityDescription( + (ENTITY_DESC_KEY_POWER_FACTOR, PERCENTAGE): SensorEntityDescription( ENTITY_DESC_KEY_POWER_FACTOR, device_class=SensorDeviceClass.POWER_FACTOR, state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=PERCENTAGE, ), - ENTITY_DESC_KEY_CO: SensorEntityDescription( + (ENTITY_DESC_KEY_CO, CONCENTRATION_PARTS_PER_MILLION): SensorEntityDescription( ENTITY_DESC_KEY_CO, device_class=SensorDeviceClass.CO, state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, ), - ENTITY_DESC_KEY_CO2: SensorEntityDescription( + (ENTITY_DESC_KEY_CO2, CONCENTRATION_PARTS_PER_MILLION): SensorEntityDescription( ENTITY_DESC_KEY_CO2, device_class=SensorDeviceClass.CO2, state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, ), - ENTITY_DESC_KEY_HUMIDITY: SensorEntityDescription( + (ENTITY_DESC_KEY_HUMIDITY, PERCENTAGE): SensorEntityDescription( ENTITY_DESC_KEY_HUMIDITY, device_class=SensorDeviceClass.HUMIDITY, state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=PERCENTAGE, ), - ENTITY_DESC_KEY_ILLUMINANCE: SensorEntityDescription( + (ENTITY_DESC_KEY_ILLUMINANCE, LIGHT_LUX): SensorEntityDescription( ENTITY_DESC_KEY_ILLUMINANCE, device_class=SensorDeviceClass.ILLUMINANCE, state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=LIGHT_LUX, ), - ENTITY_DESC_KEY_PRESSURE: SensorEntityDescription( + (ENTITY_DESC_KEY_PRESSURE, UnitOfPressure.KPA): SensorEntityDescription( ENTITY_DESC_KEY_PRESSURE, device_class=SensorDeviceClass.PRESSURE, state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=UnitOfPressure.KPA, ), - ENTITY_DESC_KEY_SIGNAL_STRENGTH: SensorEntityDescription( + (ENTITY_DESC_KEY_PRESSURE, UnitOfPressure.PSI): SensorEntityDescription( + ENTITY_DESC_KEY_PRESSURE, + device_class=SensorDeviceClass.PRESSURE, + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=UnitOfPressure.PSI, + ), + (ENTITY_DESC_KEY_PRESSURE, UnitOfPressure.INHG): SensorEntityDescription( + ENTITY_DESC_KEY_PRESSURE, + device_class=SensorDeviceClass.PRESSURE, + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=UnitOfPressure.INHG, + ), + (ENTITY_DESC_KEY_PRESSURE, UnitOfPressure.MMHG): SensorEntityDescription( + ENTITY_DESC_KEY_PRESSURE, + device_class=SensorDeviceClass.PRESSURE, + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=UnitOfPressure.MMHG, + ), + ( + ENTITY_DESC_KEY_SIGNAL_STRENGTH, + SIGNAL_STRENGTH_DECIBELS_MILLIWATT, + ): SensorEntityDescription( ENTITY_DESC_KEY_SIGNAL_STRENGTH, device_class=SensorDeviceClass.SIGNAL_STRENGTH, entity_category=EntityCategory.DIAGNOSTIC, entity_registry_enabled_default=False, state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT, ), - ENTITY_DESC_KEY_TEMPERATURE: SensorEntityDescription( + (ENTITY_DESC_KEY_TEMPERATURE, UnitOfTemperature.CELSIUS): SensorEntityDescription( ENTITY_DESC_KEY_TEMPERATURE, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, ), - ENTITY_DESC_KEY_TARGET_TEMPERATURE: SensorEntityDescription( + ( + ENTITY_DESC_KEY_TEMPERATURE, + UnitOfTemperature.FAHRENHEIT, + ): SensorEntityDescription( + ENTITY_DESC_KEY_TEMPERATURE, + device_class=SensorDeviceClass.TEMPERATURE, + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + ), + ( + ENTITY_DESC_KEY_TARGET_TEMPERATURE, + UnitOfTemperature.CELSIUS, + ): SensorEntityDescription( ENTITY_DESC_KEY_TARGET_TEMPERATURE, device_class=SensorDeviceClass.TEMPERATURE, - state_class=None, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + ), + ( + ENTITY_DESC_KEY_TARGET_TEMPERATURE, + UnitOfTemperature.FAHRENHEIT, + ): SensorEntityDescription( + ENTITY_DESC_KEY_TARGET_TEMPERATURE, + device_class=SensorDeviceClass.TEMPERATURE, + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + ), +} + +# These descriptions are without device class. +ENTITY_DESCRIPTION_KEY_MAP = { + ENTITY_DESC_KEY_CO: SensorEntityDescription( + ENTITY_DESC_KEY_CO, + state_class=SensorStateClass.MEASUREMENT, + ), + ENTITY_DESC_KEY_ENERGY_MEASUREMENT: SensorEntityDescription( + ENTITY_DESC_KEY_ENERGY_MEASUREMENT, + state_class=SensorStateClass.MEASUREMENT, + ), + ENTITY_DESC_KEY_HUMIDITY: SensorEntityDescription( + ENTITY_DESC_KEY_HUMIDITY, + state_class=SensorStateClass.MEASUREMENT, + ), + ENTITY_DESC_KEY_ILLUMINANCE: SensorEntityDescription( + ENTITY_DESC_KEY_ILLUMINANCE, + state_class=SensorStateClass.MEASUREMENT, + ), + ENTITY_DESC_KEY_POWER_FACTOR: SensorEntityDescription( + ENTITY_DESC_KEY_POWER_FACTOR, + state_class=SensorStateClass.MEASUREMENT, + ), + ENTITY_DESC_KEY_SIGNAL_STRENGTH: SensorEntityDescription( + ENTITY_DESC_KEY_SIGNAL_STRENGTH, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + state_class=SensorStateClass.MEASUREMENT, ), ENTITY_DESC_KEY_MEASUREMENT: SensorEntityDescription( ENTITY_DESC_KEY_MEASUREMENT, - device_class=None, state_class=SensorStateClass.MEASUREMENT, ), ENTITY_DESC_KEY_TOTAL_INCREASING: SensorEntityDescription( ENTITY_DESC_KEY_TOTAL_INCREASING, - device_class=None, state_class=SensorStateClass.TOTAL_INCREASING, ), } +def get_entity_description( + data: NumericSensorDataTemplateData, +) -> SensorEntityDescription: + """Return the entity description for the given data.""" + data_description_key = data.entity_description_key or "" + data_unit = data.unit_of_measurement or "" + return ENTITY_DESCRIPTION_KEY_DEVICE_CLASS_MAP.get( + (data_description_key, data_unit), + ENTITY_DESCRIPTION_KEY_MAP.get( + data_description_key, + SensorEntityDescription( + "base_sensor", native_unit_of_measurement=data.unit_of_measurement + ), + ), + ) + + async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, @@ -187,9 +308,8 @@ async def async_setup_entry( data: NumericSensorDataTemplateData = info.platform_data else: data = NumericSensorDataTemplateData() - entity_description = ENTITY_DESCRIPTION_KEY_MAP.get( - data.entity_description_key or "", SensorEntityDescription("base_sensor") - ) + + entity_description = get_entity_description(data) if info.platform_hint == "string_sensor": entities.append( @@ -308,11 +428,9 @@ class ZWaveNumericSensor(ZwaveSensorBase): @callback def on_value_update(self) -> None: """Handle scale changes for this value on value updated event.""" - self._attr_native_unit_of_measurement = ( - NumericSensorDataTemplate() - .resolve_data(self.info.primary_value) - .unit_of_measurement - ) + data = NumericSensorDataTemplate().resolve_data(self.info.primary_value) + self.entity_description = get_entity_description(data) + self._attr_native_unit_of_measurement = data.unit_of_measurement @property def native_value(self) -> float: @@ -324,6 +442,8 @@ class ZWaveNumericSensor(ZwaveSensorBase): @property def native_unit_of_measurement(self) -> str | None: """Return unit of measurement the value is expressed in.""" + if self.entity_description.native_unit_of_measurement is not None: + return self.entity_description.native_unit_of_measurement if self._attr_native_unit_of_measurement is not None: return self._attr_native_unit_of_measurement if self.info.primary_value.metadata.unit is None: diff --git a/requirements_all.txt b/requirements_all.txt index d67da01bdbb..e66bd39e7d3 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2686,7 +2686,7 @@ zigpy==0.52.3 zm-py==0.5.2 # homeassistant.components.zwave_js -zwave-js-server-python==0.43.1 +zwave-js-server-python==0.44.0 # homeassistant.components.zwave_me zwave_me_ws==0.3.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index bb7ac31b497..3be261a3892 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1884,7 +1884,7 @@ zigpy-znp==0.9.2 zigpy==0.52.3 # homeassistant.components.zwave_js -zwave-js-server-python==0.43.1 +zwave-js-server-python==0.44.0 # homeassistant.components.zwave_me zwave_me_ws==0.3.0 diff --git a/tests/components/zwave_js/test_sensor.py b/tests/components/zwave_js/test_sensor.py index a32537b1d0d..59ca814a197 100644 --- a/tests/components/zwave_js/test_sensor.py +++ b/tests/components/zwave_js/test_sensor.py @@ -24,12 +24,13 @@ from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_ICON, ATTR_UNIT_OF_MEASUREMENT, - ELECTRIC_CURRENT_AMPERE, - ELECTRIC_POTENTIAL_VOLT, - ENERGY_KILO_WATT_HOUR, - POWER_WATT, + PERCENTAGE, STATE_UNAVAILABLE, - TEMP_CELSIUS, + UnitOfElectricCurrent, + UnitOfElectricPotential, + UnitOfEnergy, + UnitOfPower, + UnitOfTemperature, ) from homeassistant.helpers import entity_registry as er from homeassistant.helpers.entity import EntityCategory @@ -49,21 +50,25 @@ from .common import ( ) -async def test_numeric_sensor(hass, multisensor_6, integration): +async def test_numeric_sensor( + hass, multisensor_6, express_controls_ezmultipli, integration +): """Test the numeric sensor.""" state = hass.states.get(AIR_TEMPERATURE_SENSOR) assert state assert state.state == "9.0" - assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == TEMP_CELSIUS + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == UnitOfTemperature.CELSIUS assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.TEMPERATURE + assert state.attributes[ATTR_STATE_CLASS] == SensorStateClass.MEASUREMENT state = hass.states.get(BATTERY_SENSOR) assert state assert state.state == "100.0" - assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == "%" + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == PERCENTAGE assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.BATTERY + assert state.attributes[ATTR_STATE_CLASS] == SensorStateClass.MEASUREMENT ent_reg = er.async_get(hass) entity_entry = ent_reg.async_get(BATTERY_SENSOR) @@ -74,8 +79,27 @@ async def test_numeric_sensor(hass, multisensor_6, integration): assert state assert state.state == "65.0" - assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == "%" + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == PERCENTAGE assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.HUMIDITY + assert state.attributes[ATTR_STATE_CLASS] == SensorStateClass.MEASUREMENT + + state = hass.states.get("sensor.multisensor_6_ultraviolet") + + assert state + assert state.state == "0.0" + # TODO: Add UV_INDEX unit of measurement to this sensor + assert ATTR_UNIT_OF_MEASUREMENT not in state.attributes + assert ATTR_DEVICE_CLASS not in state.attributes + # TODO: Add measurement state class to this sensor + assert ATTR_STATE_CLASS not in state.attributes + + state = hass.states.get("sensor.hsm200_illuminance") + + assert state + assert state.state == "61.0" + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == PERCENTAGE + assert ATTR_DEVICE_CLASS not in state.attributes + assert state.attributes[ATTR_STATE_CLASS] == SensorStateClass.MEASUREMENT async def test_energy_sensors(hass, hank_binary_switch, integration): @@ -84,7 +108,7 @@ async def test_energy_sensors(hass, hank_binary_switch, integration): assert state assert state.state == "0.0" - assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == POWER_WATT + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == UnitOfPower.WATT assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.POWER assert state.attributes[ATTR_STATE_CLASS] is SensorStateClass.MEASUREMENT @@ -92,7 +116,7 @@ async def test_energy_sensors(hass, hank_binary_switch, integration): assert state assert state.state == "0.16" - assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == ENERGY_KILO_WATT_HOUR + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == UnitOfEnergy.KILO_WATT_HOUR assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.ENERGY assert state.attributes[ATTR_STATE_CLASS] is SensorStateClass.TOTAL_INCREASING @@ -100,14 +124,14 @@ async def test_energy_sensors(hass, hank_binary_switch, integration): assert state assert state.state == "122.96" - assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == ELECTRIC_POTENTIAL_VOLT + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == UnitOfElectricPotential.VOLT assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.VOLTAGE state = hass.states.get(CURRENT_SENSOR) assert state assert state.state == "0.0" - assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == ELECTRIC_CURRENT_AMPERE + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == UnitOfElectricCurrent.AMPERE assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.CURRENT @@ -401,7 +425,8 @@ async def test_unit_change(hass, zp3111, client, integration): state = hass.states.get(entity_id) assert state assert state.state == "21.98" - assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == TEMP_CELSIUS + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == UnitOfTemperature.CELSIUS + assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.TEMPERATURE event = Event( "metadata updated", { @@ -431,7 +456,8 @@ async def test_unit_change(hass, zp3111, client, integration): state = hass.states.get(entity_id) assert state assert state.state == "21.98" - assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == TEMP_CELSIUS + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == UnitOfTemperature.CELSIUS + assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.TEMPERATURE event = Event( "value updated", { @@ -454,4 +480,5 @@ async def test_unit_change(hass, zp3111, client, integration): state = hass.states.get(entity_id) assert state assert state.state == "100.0" - assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == TEMP_CELSIUS + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == UnitOfTemperature.CELSIUS + assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.TEMPERATURE