mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Add long-term statistics support for homematic sensors (#57396)
* Add long-term statistics support for homematic * Refactor cast list to SensorEntityDescription dict Additional: - Gas power, gas energy counter, air pressure and voltage uses long-term-statistics - Gas power, gas energy counter uses device class gas - Voltage uses device class voltage - air pressure uses device class pressure * Refactor expensive loop to separate dictionarys * Use entity description property + fix humidity sensor * Log missing sensor descriptions * Use state class measurement for illumination sensors * Move sensor entity desc missing warning to setup_platform * Set type for hmdevice and homematic to fix mypy error * Use EntityDescription instead of SensorEntityDescription * Update entity.py * fix type * Update climate.py * fix v2 Co-authored-by: Pascal Vizeli <pascal.vizeli@syshack.ch>
This commit is contained in:
parent
9241d80730
commit
5151c4d99b
@ -1,11 +1,16 @@
|
||||
"""Homematic base entity."""
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import abstractmethod
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from pyhomematic import HMConnection
|
||||
from pyhomematic.devicetypes.generic import HMGeneric
|
||||
|
||||
from homeassistant.const import ATTR_NAME
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.entity import Entity, EntityDescription
|
||||
|
||||
from .const import (
|
||||
ATTR_ADDRESS,
|
||||
@ -27,7 +32,14 @@ SCAN_INTERVAL_VARIABLES = timedelta(seconds=30)
|
||||
class HMDevice(Entity):
|
||||
"""The HomeMatic device base object."""
|
||||
|
||||
def __init__(self, config):
|
||||
_homematic: HMConnection
|
||||
_hmdevice: HMGeneric
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
config: dict[str, str],
|
||||
entity_description: EntityDescription | None = None,
|
||||
) -> None:
|
||||
"""Initialize a generic HomeMatic device."""
|
||||
self._name = config.get(ATTR_NAME)
|
||||
self._address = config.get(ATTR_ADDRESS)
|
||||
@ -35,12 +47,13 @@ class HMDevice(Entity):
|
||||
self._channel = config.get(ATTR_CHANNEL)
|
||||
self._state = config.get(ATTR_PARAM)
|
||||
self._unique_id = config.get(ATTR_UNIQUE_ID)
|
||||
self._data = {}
|
||||
self._homematic = None
|
||||
self._hmdevice = None
|
||||
self._data: dict[str, str] = {}
|
||||
self._connected = False
|
||||
self._available = False
|
||||
self._channel_map = set()
|
||||
self._channel_map: set[str] = set()
|
||||
|
||||
if entity_description is not None:
|
||||
self.entity_description = entity_description
|
||||
|
||||
# Set parameter to uppercase
|
||||
if self._state:
|
||||
|
@ -1,15 +1,29 @@
|
||||
"""Support for HomeMatic sensors."""
|
||||
from __future__ import annotations
|
||||
|
||||
from copy import copy
|
||||
import logging
|
||||
|
||||
from homeassistant.components.sensor import SensorEntity
|
||||
from homeassistant.components.sensor import (
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
STATE_CLASS_TOTAL_INCREASING,
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_NAME,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
DEGREE,
|
||||
DEVICE_CLASS_CO2,
|
||||
DEVICE_CLASS_CURRENT,
|
||||
DEVICE_CLASS_ENERGY,
|
||||
DEVICE_CLASS_GAS,
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
DEVICE_CLASS_ILLUMINANCE,
|
||||
DEVICE_CLASS_POWER,
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
ELECTRIC_CURRENT_MILLIAMPERE,
|
||||
ELECTRIC_POTENTIAL_VOLT,
|
||||
ENERGY_WATT_HOUR,
|
||||
@ -24,7 +38,7 @@ from homeassistant.const import (
|
||||
VOLUME_CUBIC_METERS,
|
||||
)
|
||||
|
||||
from .const import ATTR_DISCOVER_DEVICES
|
||||
from .const import ATTR_DISCOVER_DEVICES, ATTR_PARAM
|
||||
from .entity import HMDevice
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -45,54 +59,174 @@ HM_STATE_HA_CAST = {
|
||||
"IPLockDLD": {0: None, 1: "locked", 2: "unlocked"},
|
||||
}
|
||||
|
||||
HM_UNIT_HA_CAST = {
|
||||
"HUMIDITY": PERCENTAGE,
|
||||
"TEMPERATURE": TEMP_CELSIUS,
|
||||
"ACTUAL_TEMPERATURE": TEMP_CELSIUS,
|
||||
"BRIGHTNESS": "#",
|
||||
"POWER": POWER_WATT,
|
||||
"CURRENT": ELECTRIC_CURRENT_MILLIAMPERE,
|
||||
"VOLTAGE": ELECTRIC_POTENTIAL_VOLT,
|
||||
"ENERGY_COUNTER": ENERGY_WATT_HOUR,
|
||||
"GAS_POWER": VOLUME_CUBIC_METERS,
|
||||
"GAS_ENERGY_COUNTER": VOLUME_CUBIC_METERS,
|
||||
"IEC_POWER": POWER_WATT,
|
||||
"IEC_ENERGY_COUNTER": ENERGY_WATT_HOUR,
|
||||
"LUX": LIGHT_LUX,
|
||||
"ILLUMINATION": LIGHT_LUX,
|
||||
"CURRENT_ILLUMINATION": LIGHT_LUX,
|
||||
"AVERAGE_ILLUMINATION": LIGHT_LUX,
|
||||
"LOWEST_ILLUMINATION": LIGHT_LUX,
|
||||
"HIGHEST_ILLUMINATION": LIGHT_LUX,
|
||||
"RAIN_COUNTER": LENGTH_MILLIMETERS,
|
||||
"WIND_SPEED": SPEED_KILOMETERS_PER_HOUR,
|
||||
"WIND_DIRECTION": DEGREE,
|
||||
"WIND_DIRECTION_RANGE": DEGREE,
|
||||
"SUNSHINEDURATION": "#",
|
||||
"AIR_PRESSURE": PRESSURE_HPA,
|
||||
"FREQUENCY": FREQUENCY_HERTZ,
|
||||
"VALUE": "#",
|
||||
"VALVE_STATE": PERCENTAGE,
|
||||
"CARRIER_SENSE_LEVEL": PERCENTAGE,
|
||||
"DUTY_CYCLE_LEVEL": PERCENTAGE,
|
||||
"CONCENTRATION": CONCENTRATION_PARTS_PER_MILLION,
|
||||
|
||||
SENSOR_DESCRIPTIONS: dict[str, SensorEntityDescription] = {
|
||||
"HUMIDITY": SensorEntityDescription(
|
||||
key="HUMIDITY",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
device_class=DEVICE_CLASS_HUMIDITY,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
"ACTUAL_TEMPERATURE": SensorEntityDescription(
|
||||
key="ACTUAL_TEMPERATURE",
|
||||
native_unit_of_measurement=TEMP_CELSIUS,
|
||||
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
"TEMPERATURE": SensorEntityDescription(
|
||||
key="TEMPERATURE",
|
||||
native_unit_of_measurement=TEMP_CELSIUS,
|
||||
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
"LUX": SensorEntityDescription(
|
||||
key="LUX",
|
||||
native_unit_of_measurement=LIGHT_LUX,
|
||||
device_class=DEVICE_CLASS_ILLUMINANCE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
"CURRENT_ILLUMINATION": SensorEntityDescription(
|
||||
key="CURRENT_ILLUMINATION",
|
||||
native_unit_of_measurement=LIGHT_LUX,
|
||||
device_class=DEVICE_CLASS_ILLUMINANCE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
"ILLUMINATION": SensorEntityDescription(
|
||||
key="ILLUMINATION",
|
||||
native_unit_of_measurement=LIGHT_LUX,
|
||||
device_class=DEVICE_CLASS_ILLUMINANCE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
"AVERAGE_ILLUMINATION": SensorEntityDescription(
|
||||
key="AVERAGE_ILLUMINATION",
|
||||
native_unit_of_measurement=LIGHT_LUX,
|
||||
device_class=DEVICE_CLASS_ILLUMINANCE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
"LOWEST_ILLUMINATION": SensorEntityDescription(
|
||||
key="LOWEST_ILLUMINATION",
|
||||
native_unit_of_measurement=LIGHT_LUX,
|
||||
device_class=DEVICE_CLASS_ILLUMINANCE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
"HIGHEST_ILLUMINATION": SensorEntityDescription(
|
||||
key="HIGHEST_ILLUMINATION",
|
||||
native_unit_of_measurement=LIGHT_LUX,
|
||||
device_class=DEVICE_CLASS_ILLUMINANCE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
"POWER": SensorEntityDescription(
|
||||
key="POWER",
|
||||
native_unit_of_measurement=POWER_WATT,
|
||||
device_class=DEVICE_CLASS_POWER,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
"IEC_POWER": SensorEntityDescription(
|
||||
key="IEC_POWER",
|
||||
native_unit_of_measurement=POWER_WATT,
|
||||
device_class=DEVICE_CLASS_POWER,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
"CURRENT": SensorEntityDescription(
|
||||
key="CURRENT",
|
||||
native_unit_of_measurement=ELECTRIC_CURRENT_MILLIAMPERE,
|
||||
device_class=DEVICE_CLASS_CURRENT,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
"CONCENTRATION": SensorEntityDescription(
|
||||
key="CONCENTRATION",
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
device_class=DEVICE_CLASS_CO2,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
"ENERGY_COUNTER": SensorEntityDescription(
|
||||
key="ENERGY_COUNTER",
|
||||
native_unit_of_measurement=ENERGY_WATT_HOUR,
|
||||
device_class=DEVICE_CLASS_ENERGY,
|
||||
state_class=STATE_CLASS_TOTAL_INCREASING,
|
||||
),
|
||||
"IEC_ENERGY_COUNTER": SensorEntityDescription(
|
||||
key="IEC_ENERGY_COUNTER",
|
||||
native_unit_of_measurement=ENERGY_WATT_HOUR,
|
||||
device_class=DEVICE_CLASS_ENERGY,
|
||||
state_class=STATE_CLASS_TOTAL_INCREASING,
|
||||
),
|
||||
"VOLTAGE": SensorEntityDescription(
|
||||
key="VOLTAGE",
|
||||
native_unit_of_measurement=ELECTRIC_POTENTIAL_VOLT,
|
||||
device_class=DEVICE_CLASS_VOLTAGE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
"GAS_POWER": SensorEntityDescription(
|
||||
key="GAS_POWER",
|
||||
native_unit_of_measurement=VOLUME_CUBIC_METERS,
|
||||
device_class=DEVICE_CLASS_GAS,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
"GAS_ENERGY_COUNTER": SensorEntityDescription(
|
||||
key="GAS_ENERGY_COUNTER",
|
||||
native_unit_of_measurement=VOLUME_CUBIC_METERS,
|
||||
device_class=DEVICE_CLASS_GAS,
|
||||
state_class=STATE_CLASS_TOTAL_INCREASING,
|
||||
),
|
||||
"RAIN_COUNTER": SensorEntityDescription(
|
||||
key="RAIN_COUNTER",
|
||||
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
||||
),
|
||||
"WIND_SPEED": SensorEntityDescription(
|
||||
key="WIND_SPEED",
|
||||
native_unit_of_measurement=SPEED_KILOMETERS_PER_HOUR,
|
||||
icon="mdi:weather-windy",
|
||||
),
|
||||
"WIND_DIRECTION": SensorEntityDescription(
|
||||
key="WIND_DIRECTION",
|
||||
native_unit_of_measurement=DEGREE,
|
||||
),
|
||||
"WIND_DIRECTION_RANGE": SensorEntityDescription(
|
||||
key="WIND_DIRECTION_RANGE",
|
||||
native_unit_of_measurement=DEGREE,
|
||||
),
|
||||
"SUNSHINEDURATION": SensorEntityDescription(
|
||||
key="SUNSHINEDURATION",
|
||||
native_unit_of_measurement="#",
|
||||
),
|
||||
"AIR_PRESSURE": SensorEntityDescription(
|
||||
key="AIR_PRESSURE",
|
||||
native_unit_of_measurement=PRESSURE_HPA,
|
||||
device_class=DEVICE_CLASS_PRESSURE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
"FREQUENCY": SensorEntityDescription(
|
||||
key="FREQUENCY",
|
||||
native_unit_of_measurement=FREQUENCY_HERTZ,
|
||||
),
|
||||
"VALUE": SensorEntityDescription(
|
||||
key="VALUE",
|
||||
native_unit_of_measurement="#",
|
||||
),
|
||||
"VALVE_STATE": SensorEntityDescription(
|
||||
key="VALVE_STATE",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
),
|
||||
"CARRIER_SENSE_LEVEL": SensorEntityDescription(
|
||||
key="CARRIER_SENSE_LEVEL",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
),
|
||||
"DUTY_CYCLE_LEVEL": SensorEntityDescription(
|
||||
key="DUTY_CYCLE_LEVEL",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
),
|
||||
"BRIGHTNESS": SensorEntityDescription(
|
||||
key="BRIGHTNESS",
|
||||
native_unit_of_measurement="#",
|
||||
icon="mdi:invert-colors",
|
||||
),
|
||||
}
|
||||
|
||||
HM_DEVICE_CLASS_HA_CAST = {
|
||||
"HUMIDITY": DEVICE_CLASS_HUMIDITY,
|
||||
"TEMPERATURE": DEVICE_CLASS_TEMPERATURE,
|
||||
"ACTUAL_TEMPERATURE": DEVICE_CLASS_TEMPERATURE,
|
||||
"LUX": DEVICE_CLASS_ILLUMINANCE,
|
||||
"CURRENT_ILLUMINATION": DEVICE_CLASS_ILLUMINANCE,
|
||||
"AVERAGE_ILLUMINATION": DEVICE_CLASS_ILLUMINANCE,
|
||||
"LOWEST_ILLUMINATION": DEVICE_CLASS_ILLUMINANCE,
|
||||
"HIGHEST_ILLUMINATION": DEVICE_CLASS_ILLUMINANCE,
|
||||
"POWER": DEVICE_CLASS_POWER,
|
||||
"CURRENT": DEVICE_CLASS_POWER,
|
||||
"CONCENTRATION": DEVICE_CLASS_CO2,
|
||||
}
|
||||
|
||||
HM_ICON_HA_CAST = {"WIND_SPEED": "mdi:weather-windy", "BRIGHTNESS": "mdi:invert-colors"}
|
||||
DEFAULT_SENSOR_DESCRIPTION = SensorEntityDescription(
|
||||
key="",
|
||||
entity_registry_enabled_default=True,
|
||||
)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
@ -102,7 +236,18 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
|
||||
devices = []
|
||||
for conf in discovery_info[ATTR_DISCOVER_DEVICES]:
|
||||
new_device = HMSensor(conf)
|
||||
state = conf.get(ATTR_PARAM)
|
||||
entity_desc = SENSOR_DESCRIPTIONS.get(state)
|
||||
if entity_desc is None:
|
||||
name = conf.get(ATTR_NAME)
|
||||
_LOGGER.warning(
|
||||
"Sensor (%s) entity description is missing. Sensor state (%s) needs to be maintained",
|
||||
name,
|
||||
state,
|
||||
)
|
||||
entity_desc = copy(DEFAULT_SENSOR_DESCRIPTION)
|
||||
|
||||
new_device = HMSensor(conf, entity_desc)
|
||||
devices.append(new_device)
|
||||
|
||||
add_entities(devices, True)
|
||||
@ -122,21 +267,6 @@ class HMSensor(HMDevice, SensorEntity):
|
||||
# No cast, return original value
|
||||
return self._hm_get_state()
|
||||
|
||||
@property
|
||||
def native_unit_of_measurement(self):
|
||||
"""Return the unit of measurement of this entity, if any."""
|
||||
return HM_UNIT_HA_CAST.get(self._state)
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
"""Return the device class to use in the frontend, if any."""
|
||||
return HM_DEVICE_CLASS_HA_CAST.get(self._state)
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
"""Return the icon to use in the frontend, if any."""
|
||||
return HM_ICON_HA_CAST.get(self._state)
|
||||
|
||||
def _init_data_struct(self):
|
||||
"""Generate a data dictionary (self._data) from metadata."""
|
||||
if self._state:
|
||||
|
Loading…
x
Reference in New Issue
Block a user