Fix Z-Wave JS sensor units and device classes (#85129)

fixes undefined
This commit is contained in:
Martin Hjelmare 2023-01-04 19:47:10 +01:00 committed by GitHub
parent a9640d9c94
commit 439b35c310
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 214 additions and 60 deletions

View File

@ -34,6 +34,7 @@ from zwave_js_server.const.command_class.multilevel_sensor import (
PRESSURE_SENSORS, PRESSURE_SENSORS,
SIGNAL_STRENGTH_SENSORS, SIGNAL_STRENGTH_SENSORS,
TEMPERATURE_SENSORS, TEMPERATURE_SENSORS,
UNIT_A_WEIGHTED_DECIBELS,
UNIT_AMPERE as SENSOR_UNIT_AMPERE, UNIT_AMPERE as SENSOR_UNIT_AMPERE,
UNIT_BTU_H, UNIT_BTU_H,
UNIT_CELSIUS, UNIT_CELSIUS,
@ -52,6 +53,7 @@ from zwave_js_server.const.command_class.multilevel_sensor import (
UNIT_INCHES_PER_HOUR, UNIT_INCHES_PER_HOUR,
UNIT_KILOGRAM, UNIT_KILOGRAM,
UNIT_KILOHERTZ, UNIT_KILOHERTZ,
UNIT_KILOPASCAL,
UNIT_LITER, UNIT_LITER,
UNIT_LUX, UNIT_LUX,
UNIT_M_S, UNIT_M_S,
@ -69,6 +71,7 @@ from zwave_js_server.const.command_class.multilevel_sensor import (
UNIT_RSSI, UNIT_RSSI,
UNIT_SECOND, UNIT_SECOND,
UNIT_SYSTOLIC, UNIT_SYSTOLIC,
UNIT_UV_INDEX,
UNIT_VOLT as SENSOR_UNIT_VOLT, UNIT_VOLT as SENSOR_UNIT_VOLT,
UNIT_WATT as SENSOR_UNIT_WATT, UNIT_WATT as SENSOR_UNIT_WATT,
UNIT_WATT_PER_SQUARE_METER, UNIT_WATT_PER_SQUARE_METER,
@ -94,8 +97,8 @@ from homeassistant.const import (
DEGREE, DEGREE,
LIGHT_LUX, LIGHT_LUX,
PERCENTAGE, PERCENTAGE,
SIGNAL_STRENGTH_DECIBELS,
SIGNAL_STRENGTH_DECIBELS_MILLIWATT, SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
UV_INDEX,
UnitOfElectricCurrent, UnitOfElectricCurrent,
UnitOfElectricPotential, UnitOfElectricPotential,
UnitOfEnergy, UnitOfEnergy,
@ -105,6 +108,7 @@ from homeassistant.const import (
UnitOfMass, UnitOfMass,
UnitOfPower, UnitOfPower,
UnitOfPressure, UnitOfPressure,
UnitOfSoundPressure,
UnitOfSpeed, UnitOfSpeed,
UnitOfTemperature, UnitOfTemperature,
UnitOfTime, UnitOfTime,
@ -134,7 +138,7 @@ from .const import (
) )
from .helpers import ZwaveValueID 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_CURRENT: CURRENT_METER_TYPES,
ENTITY_DESC_KEY_VOLTAGE: VOLTAGE_METER_TYPES, ENTITY_DESC_KEY_VOLTAGE: VOLTAGE_METER_TYPES,
ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING: ENERGY_TOTAL_INCREASING_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, 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_CO: CO_SENSORS,
ENTITY_DESC_KEY_CO2: CO2_SENSORS, ENTITY_DESC_KEY_CO2: CO2_SENSORS,
ENTITY_DESC_KEY_CURRENT: CURRENT_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, 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, UnitOfElectricCurrent.AMPERE: METER_UNIT_AMPERE,
UnitOfVolume.CUBIC_FEET: UNIT_CUBIC_FEET, UnitOfVolume.CUBIC_FEET: UNIT_CUBIC_FEET,
UnitOfVolume.CUBIC_METERS: METER_UNIT_CUBIC_METER, UnitOfVolume.CUBIC_METERS: METER_UNIT_CUBIC_METER,
@ -166,7 +170,7 @@ METER_UNIT_MAP: dict[str, set[MeterScaleType]] = {
UnitOfPower.WATT: METER_UNIT_WATT, 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, UnitOfElectricCurrent.AMPERE: SENSOR_UNIT_AMPERE,
UnitOfPower.BTU_PER_HOUR: UNIT_BTU_H, UnitOfPower.BTU_PER_HOUR: UNIT_BTU_H,
UnitOfTemperature.CELSIUS: UNIT_CELSIUS, 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, UnitOfVolumeFlowRate.CUBIC_FEET_PER_MINUTE: UNIT_CUBIC_FEET_PER_MINUTE,
UnitOfVolume.CUBIC_METERS: SENSOR_UNIT_CUBIC_METER, UnitOfVolume.CUBIC_METERS: SENSOR_UNIT_CUBIC_METER,
UnitOfVolumeFlowRate.CUBIC_METERS_PER_HOUR: UNIT_CUBIC_METER_PER_HOUR, 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, DEGREE: UNIT_DEGREES,
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER: { CONCENTRATION_MICROGRAMS_PER_CUBIC_METER: [
*UNIT_DENSITY, *UNIT_DENSITY,
*UNIT_MICROGRAM_PER_CUBIC_METER, *UNIT_MICROGRAM_PER_CUBIC_METER,
}, ],
UnitOfTemperature.FAHRENHEIT: UNIT_FAHRENHEIT, UnitOfTemperature.FAHRENHEIT: UNIT_FAHRENHEIT,
UnitOfLength.FEET: UNIT_FEET, UnitOfLength.FEET: UNIT_FEET,
UnitOfVolume.GALLONS: UNIT_GALLONS, UnitOfVolume.GALLONS: UNIT_GALLONS,
UnitOfFrequency.HERTZ: UNIT_HERTZ, UnitOfFrequency.HERTZ: UNIT_HERTZ,
UnitOfPressure.INHG: UNIT_INCHES_OF_MERCURY, UnitOfPressure.INHG: UNIT_INCHES_OF_MERCURY,
UnitOfPressure.KPA: UNIT_KILOPASCAL,
UnitOfVolumetricFlux.INCHES_PER_HOUR: UNIT_INCHES_PER_HOUR, UnitOfVolumetricFlux.INCHES_PER_HOUR: UNIT_INCHES_PER_HOUR,
UnitOfMass.KILOGRAMS: UNIT_KILOGRAM, UnitOfMass.KILOGRAMS: UNIT_KILOGRAM,
UnitOfFrequency.KILOHERTZ: UNIT_KILOHERTZ, UnitOfFrequency.KILOHERTZ: UNIT_KILOHERTZ,
@ -197,7 +203,7 @@ MULTILEVEL_SENSOR_UNIT_MAP: dict[str, set[MultilevelSensorScaleType]] = {
UnitOfSpeed.MILES_PER_HOUR: UNIT_MPH, UnitOfSpeed.MILES_PER_HOUR: UNIT_MPH,
UnitOfSpeed.METERS_PER_SECOND: UNIT_M_S, UnitOfSpeed.METERS_PER_SECOND: UNIT_M_S,
CONCENTRATION_PARTS_PER_MILLION: UNIT_PARTS_MILLION, CONCENTRATION_PARTS_PER_MILLION: UNIT_PARTS_MILLION,
PERCENTAGE: {*UNIT_PERCENTAGE_VALUE, *UNIT_RSSI}, PERCENTAGE: [*UNIT_PERCENTAGE_VALUE, *UNIT_RSSI],
UnitOfMass.POUNDS: UNIT_POUNDS, UnitOfMass.POUNDS: UNIT_POUNDS,
UnitOfPressure.PSI: UNIT_POUND_PER_SQUARE_INCH, UnitOfPressure.PSI: UNIT_POUND_PER_SQUARE_INCH,
SIGNAL_STRENGTH_DECIBELS_MILLIWATT: UNIT_POWER_LEVEL, SIGNAL_STRENGTH_DECIBELS_MILLIWATT: UNIT_POWER_LEVEL,
@ -206,6 +212,7 @@ MULTILEVEL_SENSOR_UNIT_MAP: dict[str, set[MultilevelSensorScaleType]] = {
UnitOfElectricPotential.VOLT: SENSOR_UNIT_VOLT, UnitOfElectricPotential.VOLT: SENSOR_UNIT_VOLT,
UnitOfPower.WATT: SENSOR_UNIT_WATT, UnitOfPower.WATT: SENSOR_UNIT_WATT,
UnitOfIrradiance.WATTS_PER_SQUARE_METER: UNIT_WATT_PER_SQUARE_METER, UnitOfIrradiance.WATTS_PER_SQUARE_METER: UNIT_WATT_PER_SQUARE_METER,
UV_INDEX: UNIT_UV_INDEX,
} }
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -319,9 +326,9 @@ class NumericSensorDataTemplate(BaseDiscoverySchemaDataTemplate):
enum_value: MultilevelSensorType | MultilevelSensorScaleType | MeterScaleType, enum_value: MultilevelSensorType | MultilevelSensorScaleType | MeterScaleType,
set_map: Mapping[ set_map: Mapping[
str, str,
set[MultilevelSensorType] list[MultilevelSensorType]
| set[MultilevelSensorScaleType] | list[MultilevelSensorScaleType]
| set[MeterScaleType], | list[MeterScaleType],
], ],
) -> str | None: ) -> str | None:
"""Find a key in a set map that matches a given enum value.""" """Find a key in a set map that matches a given enum value."""

View File

@ -3,7 +3,7 @@
"name": "Z-Wave", "name": "Z-Wave",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/zwave_js", "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"], "codeowners": ["@home-assistant/z-wave"],
"dependencies": ["usb", "http", "websocket_api"], "dependencies": ["usb", "http", "websocket_api"],
"iot_class": "local_push", "iot_class": "local_push",

View File

@ -24,6 +24,18 @@ from homeassistant.components.sensor import (
SensorStateClass, SensorStateClass,
) )
from homeassistant.config_entries import ConfigEntry 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.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_platform from homeassistant.helpers import entity_platform
@ -76,98 +88,207 @@ STATUS_ICON: dict[NodeStatus, str] = {
} }
ENTITY_DESCRIPTION_KEY_MAP: dict[str, SensorEntityDescription] = { # These descriptions should include device class.
ENTITY_DESC_KEY_BATTERY: SensorEntityDescription( ENTITY_DESCRIPTION_KEY_DEVICE_CLASS_MAP: dict[
tuple[str, str], SensorEntityDescription
] = {
(ENTITY_DESC_KEY_BATTERY, PERCENTAGE): SensorEntityDescription(
ENTITY_DESC_KEY_BATTERY, ENTITY_DESC_KEY_BATTERY,
device_class=SensorDeviceClass.BATTERY, device_class=SensorDeviceClass.BATTERY,
entity_category=EntityCategory.DIAGNOSTIC, entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.MEASUREMENT, 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, ENTITY_DESC_KEY_CURRENT,
device_class=SensorDeviceClass.CURRENT, device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT, 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, ENTITY_DESC_KEY_VOLTAGE,
device_class=SensorDeviceClass.VOLTAGE, device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
), ),
ENTITY_DESC_KEY_ENERGY_MEASUREMENT: SensorEntityDescription( (
ENTITY_DESC_KEY_ENERGY_MEASUREMENT, ENTITY_DESC_KEY_VOLTAGE,
device_class=SensorDeviceClass.ENERGY, UnitOfElectricPotential.MILLIVOLT,
): SensorEntityDescription(
ENTITY_DESC_KEY_VOLTAGE,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT, 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, ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING,
device_class=SensorDeviceClass.ENERGY, device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING, 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, ENTITY_DESC_KEY_POWER,
device_class=SensorDeviceClass.POWER, device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT, 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, ENTITY_DESC_KEY_POWER_FACTOR,
device_class=SensorDeviceClass.POWER_FACTOR, device_class=SensorDeviceClass.POWER_FACTOR,
state_class=SensorStateClass.MEASUREMENT, 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, ENTITY_DESC_KEY_CO,
device_class=SensorDeviceClass.CO, device_class=SensorDeviceClass.CO,
state_class=SensorStateClass.MEASUREMENT, 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, ENTITY_DESC_KEY_CO2,
device_class=SensorDeviceClass.CO2, device_class=SensorDeviceClass.CO2,
state_class=SensorStateClass.MEASUREMENT, 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, ENTITY_DESC_KEY_HUMIDITY,
device_class=SensorDeviceClass.HUMIDITY, device_class=SensorDeviceClass.HUMIDITY,
state_class=SensorStateClass.MEASUREMENT, 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, ENTITY_DESC_KEY_ILLUMINANCE,
device_class=SensorDeviceClass.ILLUMINANCE, device_class=SensorDeviceClass.ILLUMINANCE,
state_class=SensorStateClass.MEASUREMENT, 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, ENTITY_DESC_KEY_PRESSURE,
device_class=SensorDeviceClass.PRESSURE, device_class=SensorDeviceClass.PRESSURE,
state_class=SensorStateClass.MEASUREMENT, 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, ENTITY_DESC_KEY_SIGNAL_STRENGTH,
device_class=SensorDeviceClass.SIGNAL_STRENGTH, device_class=SensorDeviceClass.SIGNAL_STRENGTH,
entity_category=EntityCategory.DIAGNOSTIC, entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
state_class=SensorStateClass.MEASUREMENT, 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, ENTITY_DESC_KEY_TEMPERATURE,
device_class=SensorDeviceClass.TEMPERATURE, device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT, 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, ENTITY_DESC_KEY_TARGET_TEMPERATURE,
device_class=SensorDeviceClass.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: SensorEntityDescription(
ENTITY_DESC_KEY_MEASUREMENT, ENTITY_DESC_KEY_MEASUREMENT,
device_class=None,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
), ),
ENTITY_DESC_KEY_TOTAL_INCREASING: SensorEntityDescription( ENTITY_DESC_KEY_TOTAL_INCREASING: SensorEntityDescription(
ENTITY_DESC_KEY_TOTAL_INCREASING, ENTITY_DESC_KEY_TOTAL_INCREASING,
device_class=None,
state_class=SensorStateClass.TOTAL_INCREASING, 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( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: ConfigEntry,
@ -187,9 +308,8 @@ async def async_setup_entry(
data: NumericSensorDataTemplateData = info.platform_data data: NumericSensorDataTemplateData = info.platform_data
else: else:
data = NumericSensorDataTemplateData() 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": if info.platform_hint == "string_sensor":
entities.append( entities.append(
@ -308,11 +428,9 @@ class ZWaveNumericSensor(ZwaveSensorBase):
@callback @callback
def on_value_update(self) -> None: def on_value_update(self) -> None:
"""Handle scale changes for this value on value updated event.""" """Handle scale changes for this value on value updated event."""
self._attr_native_unit_of_measurement = ( data = NumericSensorDataTemplate().resolve_data(self.info.primary_value)
NumericSensorDataTemplate() self.entity_description = get_entity_description(data)
.resolve_data(self.info.primary_value) self._attr_native_unit_of_measurement = data.unit_of_measurement
.unit_of_measurement
)
@property @property
def native_value(self) -> float: def native_value(self) -> float:
@ -324,6 +442,8 @@ class ZWaveNumericSensor(ZwaveSensorBase):
@property @property
def native_unit_of_measurement(self) -> str | None: def native_unit_of_measurement(self) -> str | None:
"""Return unit of measurement the value is expressed in.""" """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: if self._attr_native_unit_of_measurement is not None:
return self._attr_native_unit_of_measurement return self._attr_native_unit_of_measurement
if self.info.primary_value.metadata.unit is None: if self.info.primary_value.metadata.unit is None:

View File

@ -2686,7 +2686,7 @@ zigpy==0.52.3
zm-py==0.5.2 zm-py==0.5.2
# homeassistant.components.zwave_js # homeassistant.components.zwave_js
zwave-js-server-python==0.43.1 zwave-js-server-python==0.44.0
# homeassistant.components.zwave_me # homeassistant.components.zwave_me
zwave_me_ws==0.3.0 zwave_me_ws==0.3.0

View File

@ -1884,7 +1884,7 @@ zigpy-znp==0.9.2
zigpy==0.52.3 zigpy==0.52.3
# homeassistant.components.zwave_js # homeassistant.components.zwave_js
zwave-js-server-python==0.43.1 zwave-js-server-python==0.44.0
# homeassistant.components.zwave_me # homeassistant.components.zwave_me
zwave_me_ws==0.3.0 zwave_me_ws==0.3.0

View File

@ -24,12 +24,13 @@ from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
ATTR_ICON, ATTR_ICON,
ATTR_UNIT_OF_MEASUREMENT, ATTR_UNIT_OF_MEASUREMENT,
ELECTRIC_CURRENT_AMPERE, PERCENTAGE,
ELECTRIC_POTENTIAL_VOLT,
ENERGY_KILO_WATT_HOUR,
POWER_WATT,
STATE_UNAVAILABLE, STATE_UNAVAILABLE,
TEMP_CELSIUS, UnitOfElectricCurrent,
UnitOfElectricPotential,
UnitOfEnergy,
UnitOfPower,
UnitOfTemperature,
) )
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity import EntityCategory 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.""" """Test the numeric sensor."""
state = hass.states.get(AIR_TEMPERATURE_SENSOR) state = hass.states.get(AIR_TEMPERATURE_SENSOR)
assert state assert state
assert state.state == "9.0" 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_DEVICE_CLASS] == SensorDeviceClass.TEMPERATURE
assert state.attributes[ATTR_STATE_CLASS] == SensorStateClass.MEASUREMENT
state = hass.states.get(BATTERY_SENSOR) state = hass.states.get(BATTERY_SENSOR)
assert state assert state
assert state.state == "100.0" 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_DEVICE_CLASS] == SensorDeviceClass.BATTERY
assert state.attributes[ATTR_STATE_CLASS] == SensorStateClass.MEASUREMENT
ent_reg = er.async_get(hass) ent_reg = er.async_get(hass)
entity_entry = ent_reg.async_get(BATTERY_SENSOR) 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
assert state.state == "65.0" 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_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): 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
assert state.state == "0.0" 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_DEVICE_CLASS] == SensorDeviceClass.POWER
assert state.attributes[ATTR_STATE_CLASS] is SensorStateClass.MEASUREMENT 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
assert state.state == "0.16" 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_DEVICE_CLASS] == SensorDeviceClass.ENERGY
assert state.attributes[ATTR_STATE_CLASS] is SensorStateClass.TOTAL_INCREASING 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
assert state.state == "122.96" 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 assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.VOLTAGE
state = hass.states.get(CURRENT_SENSOR) state = hass.states.get(CURRENT_SENSOR)
assert state assert state
assert state.state == "0.0" 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 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) state = hass.states.get(entity_id)
assert state assert state
assert state.state == "21.98" 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( event = Event(
"metadata updated", "metadata updated",
{ {
@ -431,7 +456,8 @@ async def test_unit_change(hass, zp3111, client, integration):
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state assert state
assert state.state == "21.98" 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( event = Event(
"value updated", "value updated",
{ {
@ -454,4 +480,5 @@ async def test_unit_change(hass, zp3111, client, integration):
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state assert state
assert state.state == "100.0" 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