Refactor zwave_js.sensor and add test coverage (#93259)

* Refactor zwave_js.sensor and add test coverage

* use walrus

* inherit config parameter class from list class

* use walrus in more places

* improve config parameter test
This commit is contained in:
Raman Gupta 2023-05-22 11:58:10 -04:00 committed by GitHub
parent d6997d8656
commit e1dd7118e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 125 additions and 97 deletions

View file

@ -38,10 +38,10 @@ from homeassistant.const import (
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_platform
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from .const import (
ATTR_METER_TYPE,
@ -311,11 +311,7 @@ async def async_setup_entry(
entity_description = get_entity_description(data)
if info.platform_hint == "string_sensor":
entities.append(
ZWaveStringSensor(config_entry, driver, info, entity_description)
)
elif info.platform_hint == "numeric_sensor":
if info.platform_hint == "numeric_sensor":
entities.append(
ZWaveNumericSensor(
config_entry,
@ -340,12 +336,7 @@ async def async_setup_entry(
ZWaveMeterSensor(config_entry, driver, info, entity_description)
)
else:
LOGGER.warning(
"Sensor not implemented for %s/%s",
info.platform_hint,
info.primary_value.property_name,
)
return
entities.append(ZwaveSensor(config_entry, driver, info, entity_description))
async_add_entities(entities)
@ -383,7 +374,7 @@ async def async_setup_entry(
)
class ZwaveSensorBase(ZWaveBaseEntity, SensorEntity):
class ZwaveSensor(ZWaveBaseEntity, SensorEntity):
"""Basic Representation of a Z-Wave sensor."""
def __init__(
@ -403,26 +394,25 @@ class ZwaveSensorBase(ZWaveBaseEntity, SensorEntity):
self._attr_force_update = True
self._attr_name = self.generate_name(include_value_name=True)
class ZWaveStringSensor(ZwaveSensorBase):
"""Representation of a Z-Wave String sensor."""
@property
def native_value(self) -> str | None:
def native_value(self) -> StateType:
"""Return state of the sensor."""
if self.info.primary_value.value is None:
return None
return str(self.info.primary_value.value)
key = str(self.info.primary_value.value)
if key not in self.info.primary_value.metadata.states:
return self.info.primary_value.value
return str(self.info.primary_value.metadata.states[key])
@property
def native_unit_of_measurement(self) -> str | None:
"""Return unit of measurement the value is expressed in."""
if (unit := super().native_unit_of_measurement) is not None:
return unit
if self.info.primary_value.metadata.unit is None:
return None
return str(self.info.primary_value.metadata.unit)
class ZWaveNumericSensor(ZwaveSensorBase):
class ZWaveNumericSensor(ZwaveSensor):
"""Representation of a Z-Wave Numeric sensor."""
@callback
@ -439,18 +429,6 @@ class ZWaveNumericSensor(ZwaveSensorBase):
return 0
return round(float(self.info.primary_value.value), 2)
@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:
return None
return str(self.info.primary_value.metadata.unit)
class ZWaveMeterSensor(ZWaveNumericSensor):
"""Representation of a Z-Wave Meter CC sensor."""
@ -458,21 +436,18 @@ class ZWaveMeterSensor(ZWaveNumericSensor):
@property
def extra_state_attributes(self) -> Mapping[str, int | str] | None:
"""Return extra state attributes."""
if meter_type := get_meter_type(self.info.primary_value):
return {
ATTR_METER_TYPE: meter_type.value,
ATTR_METER_TYPE_NAME: meter_type.name,
}
return None
meter_type = get_meter_type(self.info.primary_value)
return {
ATTR_METER_TYPE: meter_type.value,
ATTR_METER_TYPE_NAME: meter_type.name,
}
async def async_reset_meter(
self, meter_type: int | None = None, value: int | None = None
) -> None:
"""Reset meter(s) on device."""
node = self.info.node
primary_value = self.info.primary_value
if (endpoint := primary_value.endpoint) is None:
raise HomeAssistantError("Missing endpoint on device.")
endpoint = self.info.primary_value.endpoint or 0
options = {}
if meter_type is not None:
options[RESET_METER_OPTION_TYPE] = meter_type
@ -485,35 +460,19 @@ class ZWaveMeterSensor(ZWaveNumericSensor):
LOGGER.debug(
"Meters on node %s endpoint %s reset with the following options: %s",
node,
primary_value.endpoint,
endpoint,
options,
)
class ZWaveListSensor(ZwaveSensorBase):
"""Representation of a Z-Wave List sensor with multiple states."""
def __init__(
self,
config_entry: ConfigEntry,
driver: Driver,
info: ZwaveDiscoveryInfo,
entity_description: SensorEntityDescription,
unit_of_measurement: str | None = None,
) -> None:
"""Initialize a ZWaveListSensor entity."""
super().__init__(
config_entry, driver, info, entity_description, unit_of_measurement
)
# Entity class attributes
self._attr_name = self.generate_name(include_value_name=True)
class ZWaveListSensor(ZwaveSensor):
"""Representation of a Z-Wave Numeric sensor with multiple states."""
@property
def device_class(self) -> SensorDeviceClass | None:
"""Return sensor device class."""
if super().device_class is not None:
return super().device_class
if (device_class := super().device_class) is not None:
return device_class
if self.info.primary_value.metadata.states:
return SensorDeviceClass.ENUM
return None
@ -525,16 +484,6 @@ class ZWaveListSensor(ZwaveSensorBase):
return list(self.info.primary_value.metadata.states.values())
return None
@property
def native_value(self) -> str | None:
"""Return state of the sensor."""
if self.info.primary_value.value is None:
return None
key = str(self.info.primary_value.value)
if key not in self.info.primary_value.metadata.states:
return key
return str(self.info.primary_value.metadata.states[key])
@property
def extra_state_attributes(self) -> dict[str, str] | None:
"""Return the device specific state attributes."""
@ -544,7 +493,7 @@ class ZWaveListSensor(ZwaveSensorBase):
return {ATTR_VALUE: value}
class ZWaveConfigParameterSensor(ZwaveSensorBase):
class ZWaveConfigParameterSensor(ZWaveListSensor):
"""Representation of a Z-Wave config parameter sensor."""
def __init__(
@ -572,8 +521,8 @@ class ZWaveConfigParameterSensor(ZwaveSensorBase):
@property
def device_class(self) -> SensorDeviceClass | None:
"""Return sensor device class."""
if super().device_class is not None:
return super().device_class
if (device_class := super(ZwaveSensor, self).device_class) is not None:
return device_class
if (
self._primary_value.configuration_value_type
== ConfigurationValueType.ENUMERATED
@ -581,26 +530,6 @@ class ZWaveConfigParameterSensor(ZwaveSensorBase):
return SensorDeviceClass.ENUM
return None
@property
def options(self) -> list[str] | None:
"""Return options for enum sensor."""
if self.device_class == SensorDeviceClass.ENUM:
return list(self.info.primary_value.metadata.states.values())
return None
@property
def native_value(self) -> str | None:
"""Return state of the sensor."""
if self.info.primary_value.value is None:
return None
key = str(self.info.primary_value.value)
if (
self._primary_value.configuration_value_type == ConfigurationValueType.RANGE
or (key not in self.info.primary_value.metadata.states)
):
return key
return str(self.info.primary_value.metadata.states[key])
@property
def extra_state_attributes(self) -> dict[str, str] | None:
"""Return the device specific state attributes."""