Use entity descriptions for zwave_js sensors (#53744)

* Use entity descriptions for zwave_js sensors

* reorder

* use new type

* revert typing changes

* switch to using maps

* Get device and state class from discovery instead

* ues constants for keys

* Add meter type attribute and simplify platform data access

* comments

* second refactor

* Add None lookup value

* readability

* Switch base data template to type Any for more flexibility

* Additional changes based on feedback

* rewrite based on new upstream util functions

* Use new combo type

* Handle UnknownValueData in discovery

* bug fixes

* remove redundant comment

* re-add force_update

* fixes and tweaks

* pylint and feedback
pull/54961/head
Raman Gupta 2021-08-20 16:25:39 -04:00 committed by GitHub
parent debc6d632c
commit 1f2134a31a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 310 additions and 94 deletions

View File

@ -75,5 +75,24 @@ ATTR_REFRESH_ALL_VALUES = "refresh_all_values"
ATTR_BROADCAST = "broadcast"
# meter reset
ATTR_METER_TYPE = "meter_type"
ATTR_METER_TYPE_NAME = "meter_type_name"
ADDON_SLUG = "core_zwave_js"
# Sensor entity description constants
ENTITY_DESC_KEY_BATTERY = "battery"
ENTITY_DESC_KEY_CURRENT = "current"
ENTITY_DESC_KEY_VOLTAGE = "voltage"
ENTITY_DESC_KEY_ENERGY_MEASUREMENT = "energy_measurement"
ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING = "energy_total_increasing"
ENTITY_DESC_KEY_POWER = "power"
ENTITY_DESC_KEY_POWER_FACTOR = "power_factor"
ENTITY_DESC_KEY_CO = "co"
ENTITY_DESC_KEY_CO2 = "co2"
ENTITY_DESC_KEY_HUMIDITY = "humidity"
ENTITY_DESC_KEY_ILLUMINANCE = "illuminance"
ENTITY_DESC_KEY_PRESSURE = "pressure"
ENTITY_DESC_KEY_SIGNAL_STRENGTH = "signal_strength"
ENTITY_DESC_KEY_TEMPERATURE = "temperature"
ENTITY_DESC_KEY_TARGET_TEMPERATURE = "target_temperature"
ENTITY_DESC_KEY_TIMESTAMP = "timestamp"

View File

@ -7,15 +7,18 @@ from typing import Any
from awesomeversion import AwesomeVersion
from zwave_js_server.const import THERMOSTAT_CURRENT_TEMP_PROPERTY, CommandClass
from zwave_js_server.exceptions import UnknownValueData
from zwave_js_server.model.device_class import DeviceClassItem
from zwave_js_server.model.node import Node as ZwaveNode
from zwave_js_server.model.value import Value as ZwaveValue
from homeassistant.core import callback
from .const import LOGGER
from .discovery_data_template import (
BaseDiscoverySchemaDataTemplate,
DynamicCurrentTempClimateDataTemplate,
NumericSensorDataTemplate,
ZwaveValueID,
)
@ -59,14 +62,14 @@ class ZwaveDiscoveryInfo:
assumed_state: bool
# the home assistant platform for which an entity should be created
platform: str
# helper data to use in platform setup
platform_data: Any
# additional values that need to be watched by entity
additional_value_ids_to_watch: set[str]
# hint for the platform about this discovered entity
platform_hint: str | None = ""
# data template to use in platform logic
platform_data_template: BaseDiscoverySchemaDataTemplate | None = None
# helper data to use in platform setup
platform_data: dict[str, Any] | None = None
# additional values that need to be watched by entity
additional_value_ids_to_watch: set[str] | None = None
# bool to specify whether entity should be enabled by default
entity_registry_enabled_default: bool = True
@ -487,6 +490,7 @@ DISCOVERY_SCHEMAS = [
},
type={"number"},
),
data_template=NumericSensorDataTemplate(),
),
ZWaveDiscoverySchema(
platform="sensor",
@ -495,6 +499,7 @@ DISCOVERY_SCHEMAS = [
command_class={CommandClass.INDICATOR},
type={"number"},
),
data_template=NumericSensorDataTemplate(),
entity_registry_enabled_default=False,
),
# Meter sensors for Meter CC
@ -508,6 +513,7 @@ DISCOVERY_SCHEMAS = [
type={"number"},
property={"value"},
),
data_template=NumericSensorDataTemplate(),
),
# special list sensors (Notification CC)
ZWaveDiscoverySchema(
@ -542,6 +548,7 @@ DISCOVERY_SCHEMAS = [
property={"targetValue"},
)
],
data_template=NumericSensorDataTemplate(),
entity_registry_enabled_default=False,
),
# binary switches
@ -745,9 +752,15 @@ def async_discover_values(node: ZwaveNode) -> Generator[ZwaveDiscoveryInfo, None
# resolve helper data from template
resolved_data = None
additional_value_ids_to_watch = None
additional_value_ids_to_watch = set()
if schema.data_template:
resolved_data = schema.data_template.resolve_data(value)
try:
resolved_data = schema.data_template.resolve_data(value)
except UnknownValueData as err:
LOGGER.error(
"Discovery for value %s will be skipped: %s", value, err
)
continue
additional_value_ids_to_watch = schema.data_template.value_ids_to_watch(
resolved_data
)

View File

@ -1,12 +1,80 @@
"""Data template classes for discovery used to generate device specific data for setup."""
"""Data template classes for discovery used to generate additional data for setup."""
from __future__ import annotations
from collections.abc import Iterable
from dataclasses import dataclass
from typing import Any
from zwave_js_server.const import (
CO2_SENSORS,
CO_SENSORS,
CURRENT_METER_TYPES,
CURRENT_SENSORS,
ENERGY_METER_TYPES,
ENERGY_SENSORS,
HUMIDITY_SENSORS,
ILLUMINANCE_SENSORS,
POWER_FACTOR_METER_TYPES,
POWER_METER_TYPES,
POWER_SENSORS,
PRESSURE_SENSORS,
SIGNAL_STRENGTH_SENSORS,
TEMPERATURE_SENSORS,
TIMESTAMP_SENSORS,
VOLTAGE_METER_TYPES,
VOLTAGE_SENSORS,
CommandClass,
MeterScaleType,
MultilevelSensorType,
)
from zwave_js_server.model.node import Node as ZwaveNode
from zwave_js_server.model.value import Value as ZwaveValue, get_value_id
from zwave_js_server.util.command_class import (
get_meter_scale_type,
get_multilevel_sensor_type,
)
from .const import (
ENTITY_DESC_KEY_BATTERY,
ENTITY_DESC_KEY_CO,
ENTITY_DESC_KEY_CO2,
ENTITY_DESC_KEY_CURRENT,
ENTITY_DESC_KEY_ENERGY_MEASUREMENT,
ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING,
ENTITY_DESC_KEY_HUMIDITY,
ENTITY_DESC_KEY_ILLUMINANCE,
ENTITY_DESC_KEY_POWER,
ENTITY_DESC_KEY_POWER_FACTOR,
ENTITY_DESC_KEY_PRESSURE,
ENTITY_DESC_KEY_SIGNAL_STRENGTH,
ENTITY_DESC_KEY_TARGET_TEMPERATURE,
ENTITY_DESC_KEY_TEMPERATURE,
ENTITY_DESC_KEY_TIMESTAMP,
ENTITY_DESC_KEY_VOLTAGE,
)
METER_DEVICE_CLASS_MAP: dict[str, set[MeterScaleType]] = {
ENTITY_DESC_KEY_CURRENT: CURRENT_METER_TYPES,
ENTITY_DESC_KEY_VOLTAGE: VOLTAGE_METER_TYPES,
ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING: ENERGY_METER_TYPES,
ENTITY_DESC_KEY_POWER: POWER_METER_TYPES,
ENTITY_DESC_KEY_POWER_FACTOR: POWER_FACTOR_METER_TYPES,
}
MULTILEVEL_SENSOR_DEVICE_CLASS_MAP: dict[str, set[MultilevelSensorType]] = {
ENTITY_DESC_KEY_CO: CO_SENSORS,
ENTITY_DESC_KEY_CO2: CO2_SENSORS,
ENTITY_DESC_KEY_CURRENT: CURRENT_SENSORS,
ENTITY_DESC_KEY_ENERGY_MEASUREMENT: ENERGY_SENSORS,
ENTITY_DESC_KEY_HUMIDITY: HUMIDITY_SENSORS,
ENTITY_DESC_KEY_ILLUMINANCE: ILLUMINANCE_SENSORS,
ENTITY_DESC_KEY_POWER: POWER_SENSORS,
ENTITY_DESC_KEY_PRESSURE: PRESSURE_SENSORS,
ENTITY_DESC_KEY_SIGNAL_STRENGTH: SIGNAL_STRENGTH_SENSORS,
ENTITY_DESC_KEY_TEMPERATURE: TEMPERATURE_SENSORS,
ENTITY_DESC_KEY_TIMESTAMP: TIMESTAMP_SENSORS,
ENTITY_DESC_KEY_VOLTAGE: VOLTAGE_SENSORS,
}
@dataclass
@ -19,11 +87,10 @@ class ZwaveValueID:
property_key: str | int | None = None
@dataclass
class BaseDiscoverySchemaDataTemplate:
"""Base class for discovery schema data templates."""
def resolve_data(self, value: ZwaveValue) -> dict[str, Any]:
def resolve_data(self, value: ZwaveValue) -> Any:
"""
Resolve helper class data for a discovered value.
@ -33,7 +100,7 @@ class BaseDiscoverySchemaDataTemplate:
# pylint: disable=no-self-use
return {}
def values_to_watch(self, resolved_data: dict[str, Any]) -> Iterable[ZwaveValue]:
def values_to_watch(self, resolved_data: Any) -> Iterable[ZwaveValue]:
"""
Return list of all ZwaveValues resolved by helper that should be watched.
@ -42,7 +109,7 @@ class BaseDiscoverySchemaDataTemplate:
# pylint: disable=no-self-use
return []
def value_ids_to_watch(self, resolved_data: dict[str, Any]) -> set[str]:
def value_ids_to_watch(self, resolved_data: Any) -> set[str]:
"""
Return list of all Value IDs resolved by helper that should be watched.
@ -107,3 +174,32 @@ class DynamicCurrentTempClimateDataTemplate(BaseDiscoverySchemaDataTemplate):
return lookup_table.get(lookup_key)
return None
class NumericSensorDataTemplate(BaseDiscoverySchemaDataTemplate):
"""Data template class for Z-Wave Sensor entities."""
def resolve_data(self, value: ZwaveValue) -> str | None:
"""Resolve helper class data for a discovered value."""
if value.command_class == CommandClass.BATTERY:
return ENTITY_DESC_KEY_BATTERY
if value.command_class == CommandClass.METER:
scale_type = get_meter_scale_type(value)
for key, scale_type_set in METER_DEVICE_CLASS_MAP.items():
if scale_type in scale_type_set:
return key
if value.command_class == CommandClass.SENSOR_MULTILEVEL:
sensor_type = get_multilevel_sensor_type(value)
if sensor_type == MultilevelSensorType.TARGET_TEMPERATURE:
return ENTITY_DESC_KEY_TARGET_TEMPERATURE
for (
key,
sensor_type_set,
) in MULTILEVEL_SENSOR_DEVICE_CLASS_MAP.items():
if sensor_type in sensor_type_set:
return key
return None

View File

@ -1,30 +1,45 @@
"""Representation of Z-Wave sensors."""
from __future__ import annotations
from collections.abc import Mapping
from dataclasses import dataclass
import logging
from typing import cast
import voluptuous as vol
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.const import CommandClass, ConfigurationValueType
from zwave_js_server.const import (
RESET_METER_OPTION_TARGET_VALUE,
RESET_METER_OPTION_TYPE,
CommandClass,
ConfigurationValueType,
)
from zwave_js_server.model.node import Node as ZwaveNode
from zwave_js_server.model.value import ConfigurationValue
from zwave_js_server.util.command_class import get_meter_type
from homeassistant.components.sensor import (
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_ILLUMINANCE,
DEVICE_CLASS_POWER,
DOMAIN as SENSOR_DOMAIN,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_TOTAL_INCREASING,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_CO,
DEVICE_CLASS_CO2,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_ILLUMINANCE,
DEVICE_CLASS_POWER,
DEVICE_CLASS_POWER_FACTOR,
DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_SIGNAL_STRENGTH,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_TIMESTAMP,
DEVICE_CLASS_VOLTAGE,
TEMP_CELSIUS,
TEMP_FAHRENHEIT,
@ -34,7 +49,30 @@ from homeassistant.helpers import entity_platform
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import ATTR_METER_TYPE, ATTR_VALUE, DATA_CLIENT, DOMAIN, SERVICE_RESET_METER
from .const import (
ATTR_METER_TYPE,
ATTR_METER_TYPE_NAME,
ATTR_VALUE,
DATA_CLIENT,
DOMAIN,
ENTITY_DESC_KEY_BATTERY,
ENTITY_DESC_KEY_CO,
ENTITY_DESC_KEY_CO2,
ENTITY_DESC_KEY_CURRENT,
ENTITY_DESC_KEY_ENERGY_MEASUREMENT,
ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING,
ENTITY_DESC_KEY_HUMIDITY,
ENTITY_DESC_KEY_ILLUMINANCE,
ENTITY_DESC_KEY_POWER,
ENTITY_DESC_KEY_POWER_FACTOR,
ENTITY_DESC_KEY_PRESSURE,
ENTITY_DESC_KEY_SIGNAL_STRENGTH,
ENTITY_DESC_KEY_TARGET_TEMPERATURE,
ENTITY_DESC_KEY_TEMPERATURE,
ENTITY_DESC_KEY_TIMESTAMP,
ENTITY_DESC_KEY_VOLTAGE,
SERVICE_RESET_METER,
)
from .discovery import ZwaveDiscoveryInfo
from .entity import ZWaveBaseEntity
from .helpers import get_device_id
@ -42,6 +80,97 @@ from .helpers import get_device_id
LOGGER = logging.getLogger(__name__)
@dataclass
class ZwaveSensorEntityDescription(SensorEntityDescription):
"""Base description of a Zwave Sensor entity."""
info: ZwaveDiscoveryInfo | None = None
ENTITY_DESCRIPTION_KEY_MAP: dict[str, ZwaveSensorEntityDescription] = {
ENTITY_DESC_KEY_BATTERY: ZwaveSensorEntityDescription(
ENTITY_DESC_KEY_BATTERY,
device_class=DEVICE_CLASS_BATTERY,
state_class=STATE_CLASS_MEASUREMENT,
),
ENTITY_DESC_KEY_CURRENT: ZwaveSensorEntityDescription(
ENTITY_DESC_KEY_CURRENT,
device_class=DEVICE_CLASS_CURRENT,
state_class=STATE_CLASS_MEASUREMENT,
),
ENTITY_DESC_KEY_VOLTAGE: ZwaveSensorEntityDescription(
ENTITY_DESC_KEY_VOLTAGE,
device_class=DEVICE_CLASS_VOLTAGE,
state_class=STATE_CLASS_MEASUREMENT,
),
ENTITY_DESC_KEY_ENERGY_MEASUREMENT: ZwaveSensorEntityDescription(
ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING,
device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_MEASUREMENT,
),
ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING: ZwaveSensorEntityDescription(
ENTITY_DESC_KEY_ENERGY_TOTAL_INCREASING,
device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
ENTITY_DESC_KEY_POWER: ZwaveSensorEntityDescription(
ENTITY_DESC_KEY_POWER,
device_class=DEVICE_CLASS_POWER,
state_class=STATE_CLASS_MEASUREMENT,
),
ENTITY_DESC_KEY_POWER_FACTOR: ZwaveSensorEntityDescription(
ENTITY_DESC_KEY_POWER_FACTOR,
device_class=DEVICE_CLASS_POWER_FACTOR,
state_class=STATE_CLASS_MEASUREMENT,
),
ENTITY_DESC_KEY_CO: ZwaveSensorEntityDescription(
ENTITY_DESC_KEY_CO,
device_class=DEVICE_CLASS_CO,
state_class=STATE_CLASS_MEASUREMENT,
),
ENTITY_DESC_KEY_CO2: ZwaveSensorEntityDescription(
ENTITY_DESC_KEY_CO2,
device_class=DEVICE_CLASS_CO2,
state_class=STATE_CLASS_MEASUREMENT,
),
ENTITY_DESC_KEY_HUMIDITY: ZwaveSensorEntityDescription(
ENTITY_DESC_KEY_HUMIDITY,
device_class=DEVICE_CLASS_HUMIDITY,
state_class=STATE_CLASS_MEASUREMENT,
),
ENTITY_DESC_KEY_ILLUMINANCE: ZwaveSensorEntityDescription(
ENTITY_DESC_KEY_ILLUMINANCE,
device_class=DEVICE_CLASS_ILLUMINANCE,
state_class=STATE_CLASS_MEASUREMENT,
),
ENTITY_DESC_KEY_PRESSURE: ZwaveSensorEntityDescription(
ENTITY_DESC_KEY_PRESSURE,
device_class=DEVICE_CLASS_PRESSURE,
state_class=STATE_CLASS_MEASUREMENT,
),
ENTITY_DESC_KEY_SIGNAL_STRENGTH: ZwaveSensorEntityDescription(
ENTITY_DESC_KEY_SIGNAL_STRENGTH,
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
state_class=STATE_CLASS_MEASUREMENT,
),
ENTITY_DESC_KEY_TEMPERATURE: ZwaveSensorEntityDescription(
ENTITY_DESC_KEY_TEMPERATURE,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
ENTITY_DESC_KEY_TIMESTAMP: ZwaveSensorEntityDescription(
ENTITY_DESC_KEY_TIMESTAMP,
device_class=DEVICE_CLASS_TIMESTAMP,
state_class=STATE_CLASS_MEASUREMENT,
),
ENTITY_DESC_KEY_TARGET_TEMPERATURE: ZwaveSensorEntityDescription(
ENTITY_DESC_KEY_TARGET_TEMPERATURE,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=None,
),
}
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
@ -55,16 +184,25 @@ async def async_setup_entry(
"""Add Z-Wave Sensor."""
entities: list[ZWaveBaseEntity] = []
entity_description = ENTITY_DESCRIPTION_KEY_MAP.get(
info.platform_data
) or ZwaveSensorEntityDescription("base_sensor")
entity_description.info = info
if info.platform_hint == "string_sensor":
entities.append(ZWaveStringSensor(config_entry, client, info))
entities.append(ZWaveStringSensor(config_entry, client, entity_description))
elif info.platform_hint == "numeric_sensor":
entities.append(ZWaveNumericSensor(config_entry, client, info))
entities.append(
ZWaveNumericSensor(config_entry, client, entity_description)
)
elif info.platform_hint == "list_sensor":
entities.append(ZWaveListSensor(config_entry, client, info))
entities.append(ZWaveListSensor(config_entry, client, entity_description))
elif info.platform_hint == "config_parameter":
entities.append(ZWaveConfigParameterSensor(config_entry, client, info))
entities.append(
ZWaveConfigParameterSensor(config_entry, client, entity_description)
)
elif info.platform_hint == "meter":
entities.append(ZWaveMeterSensor(config_entry, client, info))
entities.append(ZWaveMeterSensor(config_entry, client, entity_description))
else:
LOGGER.warning(
"Sensor not implemented for %s/%s",
@ -114,62 +252,16 @@ class ZwaveSensorBase(ZWaveBaseEntity, SensorEntity):
self,
config_entry: ConfigEntry,
client: ZwaveClient,
info: ZwaveDiscoveryInfo,
entity_description: ZwaveSensorEntityDescription,
) -> None:
"""Initialize a ZWaveSensorBase entity."""
super().__init__(config_entry, client, info)
assert entity_description.info
super().__init__(config_entry, client, entity_description.info)
self.entity_description = entity_description
# Entity class attributes
self._attr_force_update = True
self._attr_name = self.generate_name(include_value_name=True)
self._attr_device_class = self._get_device_class()
self._attr_state_class = self._get_state_class()
def _get_device_class(self) -> str | None:
"""
Get the device class of the sensor.
This should be run once during initialization so we don't have to calculate
this value on every state update.
"""
if self.info.primary_value.command_class == CommandClass.BATTERY:
return DEVICE_CLASS_BATTERY
if isinstance(self.info.primary_value.property_, str):
property_lower = self.info.primary_value.property_.lower()
if "humidity" in property_lower:
return DEVICE_CLASS_HUMIDITY
if "temperature" in property_lower:
return DEVICE_CLASS_TEMPERATURE
if self.info.primary_value.metadata.unit == "A":
return DEVICE_CLASS_CURRENT
if self.info.primary_value.metadata.unit == "W":
return DEVICE_CLASS_POWER
if self.info.primary_value.metadata.unit == "kWh":
return DEVICE_CLASS_ENERGY
if self.info.primary_value.metadata.unit == "V":
return DEVICE_CLASS_VOLTAGE
if self.info.primary_value.metadata.unit == "Lux":
return DEVICE_CLASS_ILLUMINANCE
return None
def _get_state_class(self) -> str | None:
"""
Get the state class of the sensor.
This should be run once during initialization so we don't have to calculate
this value on every state update.
"""
if self.info.primary_value.command_class == CommandClass.BATTERY:
return STATE_CLASS_MEASUREMENT
if isinstance(self.info.primary_value.property_, str):
property_lower = self.info.primary_value.property_.lower()
if "humidity" in property_lower or "temperature" in property_lower:
return STATE_CLASS_MEASUREMENT
return None
@property
def force_update(self) -> bool:
"""Force updates."""
return True
class ZWaveStringSensor(ZwaveSensorBase):
@ -216,20 +308,16 @@ class ZWaveNumericSensor(ZwaveSensorBase):
class ZWaveMeterSensor(ZWaveNumericSensor):
"""Representation of a Z-Wave Meter CC sensor."""
def __init__(
self,
config_entry: ConfigEntry,
client: ZwaveClient,
info: ZwaveDiscoveryInfo,
) -> None:
"""Initialize a ZWaveNumericSensor entity."""
super().__init__(config_entry, client, info)
# Entity class attributes
if self.device_class == DEVICE_CLASS_ENERGY:
self._attr_state_class = STATE_CLASS_TOTAL_INCREASING
else:
self._attr_state_class = STATE_CLASS_MEASUREMENT
@property
def extra_state_attributes(self) -> Mapping[str, int | str] | None:
"""Return extra state attributes."""
meter_type = get_meter_type(self.info.primary_value)
if meter_type:
return {
ATTR_METER_TYPE: meter_type.value,
ATTR_METER_TYPE_NAME: meter_type.name,
}
return None
async def async_reset_meter(
self, meter_type: int | None = None, value: int | None = None
@ -239,9 +327,9 @@ class ZWaveMeterSensor(ZWaveNumericSensor):
primary_value = self.info.primary_value
options = {}
if meter_type is not None:
options["type"] = meter_type
options[RESET_METER_OPTION_TYPE] = meter_type
if value is not None:
options["targetValue"] = value
options[RESET_METER_OPTION_TARGET_VALUE] = value
args = [options] if options else []
await node.endpoints[primary_value.endpoint].async_invoke_cc_api(
CommandClass.METER, "reset", *args, wait_for_result=False
@ -261,10 +349,10 @@ class ZWaveListSensor(ZwaveSensorBase):
self,
config_entry: ConfigEntry,
client: ZwaveClient,
info: ZwaveDiscoveryInfo,
entity_description: ZwaveSensorEntityDescription,
) -> None:
"""Initialize a ZWaveListSensor entity."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, client, entity_description)
# Entity class attributes
self._attr_name = self.generate_name(
@ -291,7 +379,7 @@ class ZWaveListSensor(ZwaveSensorBase):
def extra_state_attributes(self) -> dict[str, str] | None:
"""Return the device specific state attributes."""
# add the value's int value as property for multi-value (list) items
return {"value": self.info.primary_value.value}
return {ATTR_VALUE: self.info.primary_value.value}
class ZWaveConfigParameterSensor(ZwaveSensorBase):
@ -301,10 +389,10 @@ class ZWaveConfigParameterSensor(ZwaveSensorBase):
self,
config_entry: ConfigEntry,
client: ZwaveClient,
info: ZwaveDiscoveryInfo,
entity_description: ZwaveSensorEntityDescription,
) -> None:
"""Initialize a ZWaveConfigParameterSensor entity."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, client, entity_description)
self._primary_value = cast(ConfigurationValue, self.info.primary_value)
# Entity class attributes
@ -338,7 +426,7 @@ class ZWaveConfigParameterSensor(ZwaveSensorBase):
if self._primary_value.configuration_value_type == ConfigurationValueType.RANGE:
return None
# add the value's int value as property for multi-value (list) items
return {"value": self.info.primary_value.value}
return {ATTR_VALUE: self.info.primary_value.value}
class ZWaveNodeStatusSensor(SensorEntity):