From 3b92c4ece54b57ec983ed837054e594ef3737e98 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Fri, 12 Mar 2021 18:35:50 +0100 Subject: [PATCH 01/35] Add temporary state sensor --- custom_components/tahoma/__init__.py | 1 + custom_components/tahoma/sensor.py | 17 ++++ custom_components/tahoma/state_sensor.py | 98 ++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 custom_components/tahoma/state_sensor.py diff --git a/custom_components/tahoma/__init__.py b/custom_components/tahoma/__init__.py index 279bde78c..b07b55454 100644 --- a/custom_components/tahoma/__init__.py +++ b/custom_components/tahoma/__init__.py @@ -151,6 +151,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: platforms = defaultdict(list) platforms[SCENE] = scenarios + platforms["sensor"] = [] hass.data[DOMAIN][entry.entry_id] = { "platforms": platforms, diff --git a/custom_components/tahoma/sensor.py b/custom_components/tahoma/sensor.py index e69cbcfbb..d20eca8ab 100644 --- a/custom_components/tahoma/sensor.py +++ b/custom_components/tahoma/sensor.py @@ -40,6 +40,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import DOMAIN +from .state_sensor import TahomaStateSensor, supported_states from .tahoma_entity import TahomaEntity _LOGGER = logging.getLogger(__name__) @@ -128,6 +129,22 @@ async def async_setup_entry( if device.states ] + for platform, devices in data["platforms"].items(): + if platform == "scene": + continue + + for device in devices: + if device.states: + for state in device.states: + if state.name in supported_states: + entities.append( + TahomaStateSensor( + device.deviceurl, + coordinator, + supported_states[state.name], + ) + ) + async_add_entities(entities) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py new file mode 100644 index 000000000..988a84b06 --- /dev/null +++ b/custom_components/tahoma/state_sensor.py @@ -0,0 +1,98 @@ +"""Support for TaHoma sensors.""" + +from dataclasses import dataclass +from typing import Any, Callable, Optional, Union + +from homeassistant.components import sensor +from homeassistant.const import PERCENTAGE, SIGNAL_STRENGTH_DECIBELS +from homeassistant.helpers.entity import Entity + +from .coordinator import TahomaDataUpdateCoordinator +from .tahoma_entity import TahomaEntity + + +@dataclass +class StateDescription: + """Class to describe a sensor.""" + + key: str + name: str + icon: Optional[str] = None + unit: Union[None, str, Callable[[dict], str]] = None + value: Callable[[Any], Any] = lambda val: val + device_class: Optional[str] = None + default_enabled: bool = True + + +supported_states = { + "core:BatteryState": StateDescription( + key="core:BatteryState", + name="Battery", + unit=PERCENTAGE, + device_class=sensor.DEVICE_CLASS_BATTERY, + ), + "core:RSSILevelState": StateDescription( + key="core:RSSILevelState", + name="RSSI Level", + value=lambda value: round(value), + unit=SIGNAL_STRENGTH_DECIBELS, + device_class=sensor.DEVICE_CLASS_SIGNAL_STRENGTH, + ), + "core:ExpectedNumberOfShowerState": StateDescription( + key="core:ExpectedNumberOfShowerState", + name="Expected Number Of Shower", + icon="mdi-shower-head", + value=lambda value: round(value), + ), +} + + +class TahomaStateSensor(TahomaEntity, Entity): + """Representation of a TaHoma Sensor, based on a secondary device.""" + + def __init__( + self, + device_url: str, + coordinator: TahomaDataUpdateCoordinator, + state_description: StateDescription, + ): + """Initialize the device.""" + super().__init__(device_url, coordinator) + self._state_description = state_description + + @property + def state(self): + """Return the value of the sensor.""" + state = self.select_state(self._state_description.key) + + return self._state_description.value(state) if state is not None else None + + @property + def unit_of_measurement(self): + """Return the unit of measurement of this entity, if any.""" + return self._state_description.unit + + @property + def name(self) -> str: + """Return the name of the device.""" + return self._state_description.name + + @property + def icon(self) -> Optional[str]: + """Return the icon to use in the frontend, if any.""" + return self._state_description.icon + + @property + def device_class(self) -> Optional[str]: + """Return the device class of this entity if any.""" + return self._state_description.device_class + + @property + def entity_registry_enabled_default(self) -> bool: + """Return if the entity should be enabled when first added to the entity registry.""" + return self._state_description.default_enabled + + @property + def unique_id(self) -> str: + """Return a unique ID.""" + return f"{super().unique_id}-{self._state_description.key}" From f5d14701c4c27621a61699d6aa8c7f010ff20f8f Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Sun, 18 Apr 2021 18:41:28 +0200 Subject: [PATCH 02/35] Add extra sensors --- custom_components/tahoma/state_sensor.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index 988a84b06..54e9e3d5c 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -4,7 +4,7 @@ from typing import Any, Callable, Optional, Union from homeassistant.components import sensor -from homeassistant.const import PERCENTAGE, SIGNAL_STRENGTH_DECIBELS +from homeassistant.const import PERCENTAGE, SIGNAL_STRENGTH_DECIBELS, VOLUME_LITERS from homeassistant.helpers.entity import Entity from .coordinator import TahomaDataUpdateCoordinator @@ -41,9 +41,16 @@ class StateDescription: "core:ExpectedNumberOfShowerState": StateDescription( key="core:ExpectedNumberOfShowerState", name="Expected Number Of Shower", - icon="mdi-shower-head", + icon="mdi:shower-head", value=lambda value: round(value), ), + "core:WaterConsumptionState": StateDescription( + key="core:WaterConsumptionState", + name="Water Consumption", + icon="mdi:water", + value=lambda value: round(value), + unit=VOLUME_LITERS, + ), } From 47afb76a2dbb7f126bc220dfd7a23791775c7d99 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 14 Jul 2021 21:53:03 +0200 Subject: [PATCH 03/35] Add more states --- custom_components/tahoma/state_sensor.py | 27 +++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index 54e9e3d5c..32d4d7fb7 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -4,7 +4,12 @@ from typing import Any, Callable, Optional, Union from homeassistant.components import sensor -from homeassistant.const import PERCENTAGE, SIGNAL_STRENGTH_DECIBELS, VOLUME_LITERS +from homeassistant.const import ( + PERCENTAGE, + SIGNAL_STRENGTH_DECIBELS, + VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, + VOLUME_LITERS, +) from homeassistant.helpers.entity import Entity from .coordinator import TahomaDataUpdateCoordinator @@ -51,6 +56,26 @@ class StateDescription: value=lambda value: round(value), unit=VOLUME_LITERS, ), + "io:OutletEngineState": StateDescription( + key="io:OutletEngineState", + name="Outlet Engine", + icon="mdi:fan-chevron-down", + value=lambda value: round(value), + unit=VOLUME_LITERS, + ), + "io:InletEngineState": StateDescription( + key="io:InletEngineState", + name="Inlet Engine", + icon="mdi:fan-chevron-up", + value=lambda value: round(value), + unit=VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, + ), + "hlrrwifi:RoomTemperatureState": StateDescription( + key="hlrrwifi:RoomTemperatureState", + name="Room Temperature", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_TEMPERATURE, + ), } From f959364559370549b0bfd3708d0f22749e8495dd Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Thu, 15 Jul 2021 01:56:06 +0200 Subject: [PATCH 04/35] Add more sensors --- custom_components/tahoma/state_sensor.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index 32d4d7fb7..0f2f99ec0 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -49,6 +49,21 @@ class StateDescription: icon="mdi:shower-head", value=lambda value: round(value), ), + "core:NumberOfShowerRemainingState": StateDescription( + key="core:NumberOfShowerRemainingState", + name="Number of Shower Remaining", + icon="mdi:shower-head", + value=lambda value: round(value), + ), + # V40 is measured in litres (L) and shows the amount of warm (mixed) water with a temperature of 40 C, which can be drained from a switched off electric water heater. + "core:V40WaterVolumeEstimationState": StateDescription( + key="core:V40WaterVolumeEstimationState", + name="Water Volume Estimation at 40 °C", + icon="mdi:water", + value=lambda value: round(value), + unit=VOLUME_LITERS, + default_enabled=False, + ), "core:WaterConsumptionState": StateDescription( key="core:WaterConsumptionState", name="Water Consumption", @@ -76,6 +91,12 @@ class StateDescription: value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_TEMPERATURE, ), + "io:MiddleWaterTemperatureState": StateDescription( + key="io:MiddleWaterTemperatureState", + name="Middle Water Temperature", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_TEMPERATURE, + ), } From 503908bee5a710428230ac0df912030019293eeb Mon Sep 17 00:00:00 2001 From: Thibaut Etienne Date: Tue, 3 Aug 2021 20:15:42 +0000 Subject: [PATCH 05/35] Create supported_platforms variable --- custom_components/tahoma/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/custom_components/tahoma/__init__.py b/custom_components/tahoma/__init__.py index b07b55454..48efb5502 100644 --- a/custom_components/tahoma/__init__.py +++ b/custom_components/tahoma/__init__.py @@ -7,6 +7,7 @@ from aiohttp import ClientError, ServerDisconnectedError from homeassistant.components.scene import DOMAIN as SCENE +from homeassistant.components.sensor import DOMAIN as SENSOR from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.const import CONF_EXCLUDE, CONF_PASSWORD, CONF_SOURCE, CONF_USERNAME from homeassistant.core import HomeAssistant, ServiceCall @@ -151,7 +152,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: platforms = defaultdict(list) platforms[SCENE] = scenarios - platforms["sensor"] = [] hass.data[DOMAIN][entry.entry_id] = { "platforms": platforms, @@ -175,7 +175,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: if device.widget == HOMEKIT_STACK: print_homekit_setup_code(device) - for platform in platforms: + supported_platforms = set(platforms.keys()) + supported_platforms.add(SENSOR) + for platform in supported_platforms: hass.async_create_task( hass.config_entries.async_forward_entry_setup(entry, platform) ) From 84be0bee7bd9faa1e7c4f625fc832071365fcee2 Mon Sep 17 00:00:00 2001 From: Thibaut Etienne Date: Tue, 3 Aug 2021 20:21:24 +0000 Subject: [PATCH 06/35] Use Overkiz label as device name --- custom_components/tahoma/tahoma_entity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/tahoma/tahoma_entity.py b/custom_components/tahoma/tahoma_entity.py index d5458964d..1788d6bbb 100644 --- a/custom_components/tahoma/tahoma_entity.py +++ b/custom_components/tahoma/tahoma_entity.py @@ -128,7 +128,7 @@ def device_info(self) -> Dict[str, Any]: return { "identifiers": {(DOMAIN, self.base_device_url)}, - "name": self.name, + "name": self.device.label, "manufacturer": manufacturer, "model": model, "sw_version": self.device.controllable_name, From 8db4070709dd32f8292805415f450f46f2b79086 Mon Sep 17 00:00:00 2001 From: Thibaut Etienne Date: Tue, 3 Aug 2021 20:40:36 +0000 Subject: [PATCH 07/35] Suffix state sensor name with device index --- custom_components/tahoma/state_sensor.py | 2 ++ custom_components/tahoma/tahoma_entity.py | 15 ++++++--------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index 0f2f99ec0..23fae1ff4 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -128,6 +128,8 @@ def unit_of_measurement(self): @property def name(self) -> str: """Return the name of the device.""" + if self.index: + return f"{self._state_description.name} {self.index}" return self._state_description.name @property diff --git a/custom_components/tahoma/tahoma_entity.py b/custom_components/tahoma/tahoma_entity.py index 1788d6bbb..b0d6ffdd1 100644 --- a/custom_components/tahoma/tahoma_entity.py +++ b/custom_components/tahoma/tahoma_entity.py @@ -49,7 +49,12 @@ def __init__(self, device_url: str, coordinator: TahomaDataUpdateCoordinator): """Initialize the device.""" super().__init__(coordinator) self.device_url = device_url - self.base_device_url = self.get_base_device_url() + + if "#" in self.device_url: + self.base_device_url, self.index = self.device_url.split("#") + else: + self.base_device_url = self.device_url + self.index = None @property def device(self) -> Device: @@ -199,14 +204,6 @@ async def async_cancel_command(self, exec_id: str): """Cancel device command in async context.""" await self.coordinator.client.cancel_command(exec_id) - def get_base_device_url(self): - """Return base device url.""" - if "#" not in self.device_url: - return self.device_url - - device_url, _ = self.device_url.split("#") - return device_url - def get_gateway_id(self): """Retrieve gateway id from device url.""" result = re.search(r":\/\/(.*)\/", self.device_url) From 668a1d823a8c21f4483743e74b4606a176e93903 Mon Sep 17 00:00:00 2001 From: Thibaut Etienne Date: Wed, 4 Aug 2021 07:10:09 +0000 Subject: [PATCH 08/35] Avoid to duplicate state key --- custom_components/tahoma/sensor.py | 23 +++++++++++++---------- custom_components/tahoma/state_sensor.py | 24 ++++++++++++------------ 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/custom_components/tahoma/sensor.py b/custom_components/tahoma/sensor.py index d20eca8ab..4e8fa7e86 100644 --- a/custom_components/tahoma/sensor.py +++ b/custom_components/tahoma/sensor.py @@ -40,7 +40,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import DOMAIN -from .state_sensor import TahomaStateSensor, supported_states +from .state_sensor import TahomaStateSensor, SUPPORTED_STATES from .tahoma_entity import TahomaEntity _LOGGER = logging.getLogger(__name__) @@ -133,17 +133,20 @@ async def async_setup_entry( if platform == "scene": continue + key_supported_states = { + description.key: description for description in SUPPORTED_STATES + } for device in devices: - if device.states: - for state in device.states: - if state.name in supported_states: - entities.append( - TahomaStateSensor( - device.deviceurl, - coordinator, - supported_states[state.name], - ) + for state in device.states: + description = key_supported_states.get(state.name) + if description: + entities.append( + TahomaStateSensor( + device.deviceurl, + coordinator, + description, ) + ) async_add_entities(entities) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index 23fae1ff4..4634bfb7d 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -29,34 +29,34 @@ class StateDescription: default_enabled: bool = True -supported_states = { - "core:BatteryState": StateDescription( +SUPPORTED_STATES = [ + StateDescription( key="core:BatteryState", name="Battery", unit=PERCENTAGE, device_class=sensor.DEVICE_CLASS_BATTERY, ), - "core:RSSILevelState": StateDescription( + StateDescription( key="core:RSSILevelState", name="RSSI Level", value=lambda value: round(value), unit=SIGNAL_STRENGTH_DECIBELS, device_class=sensor.DEVICE_CLASS_SIGNAL_STRENGTH, ), - "core:ExpectedNumberOfShowerState": StateDescription( + StateDescription( key="core:ExpectedNumberOfShowerState", name="Expected Number Of Shower", icon="mdi:shower-head", value=lambda value: round(value), ), - "core:NumberOfShowerRemainingState": StateDescription( + StateDescription( key="core:NumberOfShowerRemainingState", name="Number of Shower Remaining", icon="mdi:shower-head", value=lambda value: round(value), ), # V40 is measured in litres (L) and shows the amount of warm (mixed) water with a temperature of 40 C, which can be drained from a switched off electric water heater. - "core:V40WaterVolumeEstimationState": StateDescription( + StateDescription( key="core:V40WaterVolumeEstimationState", name="Water Volume Estimation at 40 °C", icon="mdi:water", @@ -64,40 +64,40 @@ class StateDescription: unit=VOLUME_LITERS, default_enabled=False, ), - "core:WaterConsumptionState": StateDescription( + StateDescription( key="core:WaterConsumptionState", name="Water Consumption", icon="mdi:water", value=lambda value: round(value), unit=VOLUME_LITERS, ), - "io:OutletEngineState": StateDescription( + StateDescription( key="io:OutletEngineState", name="Outlet Engine", icon="mdi:fan-chevron-down", value=lambda value: round(value), unit=VOLUME_LITERS, ), - "io:InletEngineState": StateDescription( + StateDescription( key="io:InletEngineState", name="Inlet Engine", icon="mdi:fan-chevron-up", value=lambda value: round(value), unit=VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, ), - "hlrrwifi:RoomTemperatureState": StateDescription( + StateDescription( key="hlrrwifi:RoomTemperatureState", name="Room Temperature", value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_TEMPERATURE, ), - "io:MiddleWaterTemperatureState": StateDescription( + StateDescription( key="io:MiddleWaterTemperatureState", name="Middle Water Temperature", value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_TEMPERATURE, ), -} +] class TahomaStateSensor(TahomaEntity, Entity): From 600f30aadddd5816ffc8547ca38a4b798ed50ed0 Mon Sep 17 00:00:00 2001 From: Thibaut Etienne Date: Wed, 4 Aug 2021 07:13:12 +0000 Subject: [PATCH 09/35] Remove now usless rssi level attribute --- custom_components/tahoma/tahoma_entity.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/custom_components/tahoma/tahoma_entity.py b/custom_components/tahoma/tahoma_entity.py index b0d6ffdd1..d04ae49c0 100644 --- a/custom_components/tahoma/tahoma_entity.py +++ b/custom_components/tahoma/tahoma_entity.py @@ -11,8 +11,6 @@ from .const import DOMAIN from .coordinator import TahomaDataUpdateCoordinator -ATTR_RSSI_LEVEL = "rssi_level" - CORE_AVAILABILITY_STATE = "core:AvailabilityState" CORE_BATTERY_STATE = "core:BatteryState" CORE_MANUFACTURER = "core:Manufacturer" @@ -86,9 +84,6 @@ def device_state_attributes(self) -> Dict[str, Any]: """Return the state attributes of the device.""" attr = {} - if self.has_state(CORE_RSSI_LEVEL_STATE): - attr[ATTR_RSSI_LEVEL] = self.select_state(CORE_RSSI_LEVEL_STATE) - if self.has_state(CORE_BATTERY_STATE): battery_state = self.select_state(CORE_BATTERY_STATE) attr[ATTR_BATTERY_LEVEL] = BATTERY_MAP.get(battery_state, battery_state) From e2e1ac9c5678356142f672e7b8524049fc488506 Mon Sep 17 00:00:00 2001 From: Thibaut Etienne Date: Wed, 4 Aug 2021 07:41:37 +0000 Subject: [PATCH 10/35] Migrate LightSensor to TahomaStateSensor --- custom_components/tahoma/const.py | 1 - custom_components/tahoma/sensor.py | 34 +++++++++--------------- custom_components/tahoma/state_sensor.py | 9 +++++++ 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/custom_components/tahoma/const.py b/custom_components/tahoma/const.py index 415f4a8cb..153d62312 100644 --- a/custom_components/tahoma/const.py +++ b/custom_components/tahoma/const.py @@ -76,7 +76,6 @@ "HitachiAirToAirHeatPump": CLIMATE, # widgetName, uiClass is HitachiHeatingSystem (not supported) "HumiditySensor": SENSOR, "Light": LIGHT, - "LightSensor": SENSOR, "MotionSensor": BINARY_SENSOR, "MyFoxSecurityCamera": COVER, # widgetName, uiClass is Camera (not supported) "OccupancySensor": BINARY_SENSOR, diff --git a/custom_components/tahoma/sensor.py b/custom_components/tahoma/sensor.py index 4e8fa7e86..07f137c24 100644 --- a/custom_components/tahoma/sensor.py +++ b/custom_components/tahoma/sensor.py @@ -9,7 +9,6 @@ DEVICE_CLASS_CO, DEVICE_CLASS_CO2, DEVICE_CLASS_HUMIDITY, - DEVICE_CLASS_ILLUMINANCE, DEVICE_CLASS_POWER, DEVICE_CLASS_TEMPERATURE, ENERGY_KILO_WATT_HOUR, @@ -51,7 +50,6 @@ CORE_ELECTRIC_POWER_CONSUMPTION_STATE = "core:ElectricPowerConsumptionState" CORE_FOSSIL_ENERGY_CONSUMPTION_STATE = "core:FossilEnergyConsumptionState" CORE_GAS_CONSUMPTION_STATE = "core:GasConsumptionState" -CORE_LUMINANCE_STATE = "core:LuminanceState" CORE_MEASURED_VALUE_TYPE = "core:MeasuredValueType" CORE_RELATIVE_HUMIDITY_STATE = "core:RelativeHumidityState" CORE_SUN_ENERGY_STATE = "core:SunEnergyState" @@ -76,7 +74,6 @@ "COSensor": DEVICE_CLASS_CO, "ElectricitySensor": DEVICE_CLASS_POWER, "HumiditySensor": DEVICE_CLASS_HUMIDITY, - "LightSensor": DEVICE_CLASS_ILLUMINANCE, "RelativeHumiditySensor": DEVICE_CLASS_HUMIDITY, "SunSensor": DEVICE_CLASS_SUN_ENERGY, "TemperatureSensor": DEVICE_CLASS_TEMPERATURE, @@ -129,24 +126,20 @@ async def async_setup_entry( if device.states ] - for platform, devices in data["platforms"].items(): - if platform == "scene": - continue - - key_supported_states = { - description.key: description for description in SUPPORTED_STATES - } - for device in devices: - for state in device.states: - description = key_supported_states.get(state.name) - if description: - entities.append( - TahomaStateSensor( - device.deviceurl, - coordinator, - description, - ) + key_supported_states = { + description.key: description for description in SUPPORTED_STATES + } + for device in coordinator.data.values(): + for state in device.states: + description = key_supported_states.get(state.name) + if description: + entities.append( + TahomaStateSensor( + device.deviceurl, + coordinator, + description, ) + ) async_add_entities(entities) @@ -164,7 +157,6 @@ def state(self): CORE_ELECTRIC_POWER_CONSUMPTION_STATE, CORE_FOSSIL_ENERGY_CONSUMPTION_STATE, CORE_GAS_CONSUMPTION_STATE, - CORE_LUMINANCE_STATE, CORE_RELATIVE_HUMIDITY_STATE, CORE_SUN_ENERGY_STATE, CORE_TEMPERATURE_STATE, diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index 4634bfb7d..46e90ba6f 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -1,10 +1,12 @@ """Support for TaHoma sensors.""" +from custom_components.tahoma.sensor import UNIT_LX from dataclasses import dataclass from typing import Any, Callable, Optional, Union from homeassistant.components import sensor from homeassistant.const import ( + DEVICE_CLASS_ILLUMINANCE, PERCENTAGE, SIGNAL_STRENGTH_DECIBELS, VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, @@ -97,6 +99,13 @@ class StateDescription: value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_TEMPERATURE, ), + StateDescription( + key="core:LuminanceState", + name="Luminance", + value=lambda value: round(value), + device_class=DEVICE_CLASS_ILLUMINANCE, + unit=UNIT_LX, + ), ] From e3a55d094bfc281baf607657f0c4431868ba45dd Mon Sep 17 00:00:00 2001 From: Thibaut Etienne Date: Wed, 4 Aug 2021 07:42:17 +0000 Subject: [PATCH 11/35] Apply linters --- custom_components/tahoma/sensor.py | 2 +- custom_components/tahoma/state_sensor.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/custom_components/tahoma/sensor.py b/custom_components/tahoma/sensor.py index 07f137c24..775a6b737 100644 --- a/custom_components/tahoma/sensor.py +++ b/custom_components/tahoma/sensor.py @@ -39,7 +39,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import DOMAIN -from .state_sensor import TahomaStateSensor, SUPPORTED_STATES +from .state_sensor import SUPPORTED_STATES, TahomaStateSensor from .tahoma_entity import TahomaEntity _LOGGER = logging.getLogger(__name__) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index 46e90ba6f..c4e0f7928 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -1,6 +1,5 @@ """Support for TaHoma sensors.""" -from custom_components.tahoma.sensor import UNIT_LX from dataclasses import dataclass from typing import Any, Callable, Optional, Union @@ -14,6 +13,8 @@ ) from homeassistant.helpers.entity import Entity +from custom_components.tahoma.sensor import UNIT_LX + from .coordinator import TahomaDataUpdateCoordinator from .tahoma_entity import TahomaEntity From 4c3745f126f6378c484840ebdac155bb937e8ce6 Mon Sep 17 00:00:00 2001 From: Thibaut Etienne Date: Wed, 4 Aug 2021 07:59:10 +0000 Subject: [PATCH 12/35] Add PriorityLockOriginatorState sensor --- .../tahoma/cover_devices/tahoma_cover.py | 27 ------------------- custom_components/tahoma/sensor.py | 5 ++-- custom_components/tahoma/state_sensor.py | 10 ++++--- 3 files changed, 9 insertions(+), 33 deletions(-) diff --git a/custom_components/tahoma/cover_devices/tahoma_cover.py b/custom_components/tahoma/cover_devices/tahoma_cover.py index 75e774dfa..3ad2f452c 100644 --- a/custom_components/tahoma/cover_devices/tahoma_cover.py +++ b/custom_components/tahoma/cover_devices/tahoma_cover.py @@ -64,9 +64,6 @@ ICON_LOCK_ALERT = "mdi:lock-alert" ICON_WEATHER_WINDY = "mdi:weather-windy" -IO_PRIORITY_LOCK_LEVEL_STATE = "io:PriorityLockLevelState" -IO_PRIORITY_LOCK_ORIGINATOR_STATE = "io:PriorityLockOriginatorState" - STATE_CLOSED = "closed" SERVICE_COVER_MY_POSITION = "set_cover_my_position" @@ -128,19 +125,6 @@ def is_closed(self): return None - @property - def icon(self): - """Return the icon to use in the frontend, if any.""" - if ( - self.has_state(CORE_PRIORITY_LOCK_TIMER_STATE) - and self.select_state(CORE_PRIORITY_LOCK_TIMER_STATE) > 0 - ): - if self.select_state(IO_PRIORITY_LOCK_ORIGINATOR_STATE) == "wind": - return ICON_WEATHER_WINDY - return ICON_LOCK_ALERT - - return None - async def async_open_cover_tilt(self, **_): """Open the cover tilt.""" await self.async_execute_command(self.select_command(*COMMANDS_OPEN_TILT)) @@ -257,17 +241,6 @@ def is_closing(self): and current_closure.value < target_closure.value ) - @property - def device_state_attributes(self): - """Return the device state attributes.""" - attr = super().device_state_attributes or {} - - # Obstruction Detected attribute is used by HomeKit - if self.has_state(IO_PRIORITY_LOCK_LEVEL_STATE): - attr[ATTR_OBSTRUCTION_DETECTED] = True - - return attr - @property def supported_features(self): """Flag supported features.""" diff --git a/custom_components/tahoma/sensor.py b/custom_components/tahoma/sensor.py index 775a6b737..dbf5f0629 100644 --- a/custom_components/tahoma/sensor.py +++ b/custom_components/tahoma/sensor.py @@ -13,6 +13,7 @@ DEVICE_CLASS_TEMPERATURE, ENERGY_KILO_WATT_HOUR, ENERGY_WATT_HOUR, + LIGHT_LUX, PERCENTAGE, POWER_KILO_WATT, POWER_WATT, @@ -67,8 +68,6 @@ ICON_SOLAR_POWER = "mdi:solar-power" ICON_WEATHER_WINDY = "mdi:weather-windy" -UNIT_LX = "lx" - TAHOMA_SENSOR_DEVICE_CLASSES = { "CO2Sensor": DEVICE_CLASS_CO2, "COSensor": DEVICE_CLASS_CO, @@ -85,7 +84,7 @@ "core:TemperatureInCelsius": TEMP_CELSIUS, "core:TemperatureInKelvin": TEMP_KELVIN, "core:TemperatureInFahrenheit": TEMP_FAHRENHEIT, - "core:LuminanceInLux": UNIT_LX, + "core:LuminanceInLux": LIGHT_LUX, "core:ElectricCurrentInAmpere": ELECTRIC_CURRENT_AMPERE, "core:VoltageInVolt": ELECTRIC_POTENTIAL_VOLT, "core:ElectricalEnergyInWh": ENERGY_WATT_HOUR, diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index c4e0f7928..7da4642f4 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -6,6 +6,7 @@ from homeassistant.components import sensor from homeassistant.const import ( DEVICE_CLASS_ILLUMINANCE, + LIGHT_LUX, PERCENTAGE, SIGNAL_STRENGTH_DECIBELS, VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, @@ -13,8 +14,6 @@ ) from homeassistant.helpers.entity import Entity -from custom_components.tahoma.sensor import UNIT_LX - from .coordinator import TahomaDataUpdateCoordinator from .tahoma_entity import TahomaEntity @@ -105,7 +104,12 @@ class StateDescription: name="Luminance", value=lambda value: round(value), device_class=DEVICE_CLASS_ILLUMINANCE, - unit=UNIT_LX, + unit=LIGHT_LUX, + ), + StateDescription( + key="io:PriorityLockOriginatorState", + name="Priority Lock Originator", + value=lambda value: value, ), ] From eb59d2c94b3081be089758e3d8d9d48bce163ad6 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 4 Aug 2021 14:39:25 +0200 Subject: [PATCH 13/35] Bump minimum version to 2021.8 --- custom_components/tahoma/sensor.py | 13 ++----------- hacs.json | 2 +- requirements_dev.txt | 2 +- requirements_test.txt | 2 +- 4 files changed, 5 insertions(+), 14 deletions(-) diff --git a/custom_components/tahoma/sensor.py b/custom_components/tahoma/sensor.py index dbf5f0629..1c1f5a17f 100644 --- a/custom_components/tahoma/sensor.py +++ b/custom_components/tahoma/sensor.py @@ -11,6 +11,8 @@ DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_POWER, DEVICE_CLASS_TEMPERATURE, + ELECTRIC_CURRENT_AMPERE, + ELECTRIC_POTENTIAL_VOLT, ENERGY_KILO_WATT_HOUR, ENERGY_WATT_HOUR, LIGHT_LUX, @@ -24,17 +26,6 @@ VOLUME_CUBIC_METERS, VOLUME_LITERS, ) - -try: # Breaking change in 2021.8 - from homeassistant.const import ELECTRIC_CURRENT_AMPERE -except ImportError: - from homeassistant.const import ELECTRICAL_CURRENT_AMPERE as ELECTRIC_CURRENT_AMPERE - -try: # Breaking change in 2021.8 - from homeassistant.const import ELECTRIC_POTENTIAL_VOLT -except ImportError: - from homeassistant.const import VOLT as ELECTRIC_POTENTIAL_VOLT - from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_platform import AddEntitiesCallback diff --git a/hacs.json b/hacs.json index 820d74eca..56a34d54f 100644 --- a/hacs.json +++ b/hacs.json @@ -8,7 +8,7 @@ "switch", "climate" ], - "homeassistant": "2021.7.0", + "homeassistant": "2021.8.0", "render_readme": "true", "iot_class": "Cloud Polling" } \ No newline at end of file diff --git a/requirements_dev.txt b/requirements_dev.txt index f5e6d8b03..646598427 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,2 +1,2 @@ -r requirements.txt -homeassistant==2021.7.0b0 \ No newline at end of file +homeassistant==2021.8.0b0 \ No newline at end of file diff --git a/requirements_test.txt b/requirements_test.txt index dc1e96479..9e62c269f 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,2 +1,2 @@ -r requirements_dev.txt -pytest-homeassistant-custom-component==0.4.2 \ No newline at end of file +pytest-homeassistant-custom-component==0.4.3 \ No newline at end of file From dcb9ee0c742210516bf1309b8c45ffde39f8a649 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 4 Aug 2021 14:40:08 +0200 Subject: [PATCH 14/35] Remove unneeded value key --- custom_components/tahoma/state_sensor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index 7da4642f4..ea62360cf 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -109,7 +109,6 @@ class StateDescription: StateDescription( key="io:PriorityLockOriginatorState", name="Priority Lock Originator", - value=lambda value: value, ), ] From 0441fae7c89a08d91521d00d0e7b7740c4f0421e Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 4 Aug 2021 14:56:02 +0200 Subject: [PATCH 15/35] Migrate to SensorEntityDescription --- custom_components/tahoma/state_sensor.py | 93 +++++++++--------------- 1 file changed, 35 insertions(+), 58 deletions(-) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index ea62360cf..3a5055908 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -1,9 +1,11 @@ """Support for TaHoma sensors.""" +from __future__ import annotations from dataclasses import dataclass -from typing import Any, Callable, Optional, Union +from typing import Any, Callable from homeassistant.components import sensor +from homeassistant.components.sensor import SensorEntity, SensorEntityDescription from homeassistant.const import ( DEVICE_CLASS_ILLUMINANCE, LIGHT_LUX, @@ -12,155 +14,130 @@ VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, VOLUME_LITERS, ) -from homeassistant.helpers.entity import Entity from .coordinator import TahomaDataUpdateCoordinator from .tahoma_entity import TahomaEntity @dataclass -class StateDescription: - """Class to describe a sensor.""" +class OverkizSensorDescription(SensorEntityDescription): + """Class to describe a Overkiz sensor.""" - key: str - name: str - icon: Optional[str] = None - unit: Union[None, str, Callable[[dict], str]] = None value: Callable[[Any], Any] = lambda val: val - device_class: Optional[str] = None - default_enabled: bool = True SUPPORTED_STATES = [ - StateDescription( + OverkizSensorDescription( key="core:BatteryState", name="Battery", - unit=PERCENTAGE, + unit_of_measurement=PERCENTAGE, device_class=sensor.DEVICE_CLASS_BATTERY, + value=lambda value: value, ), - StateDescription( + OverkizSensorDescription( key="core:RSSILevelState", name="RSSI Level", value=lambda value: round(value), - unit=SIGNAL_STRENGTH_DECIBELS, + unit_of_measurement=SIGNAL_STRENGTH_DECIBELS, device_class=sensor.DEVICE_CLASS_SIGNAL_STRENGTH, ), - StateDescription( + OverkizSensorDescription( key="core:ExpectedNumberOfShowerState", name="Expected Number Of Shower", icon="mdi:shower-head", value=lambda value: round(value), ), - StateDescription( + OverkizSensorDescription( key="core:NumberOfShowerRemainingState", name="Number of Shower Remaining", icon="mdi:shower-head", value=lambda value: round(value), ), # V40 is measured in litres (L) and shows the amount of warm (mixed) water with a temperature of 40 C, which can be drained from a switched off electric water heater. - StateDescription( + OverkizSensorDescription( key="core:V40WaterVolumeEstimationState", name="Water Volume Estimation at 40 °C", icon="mdi:water", value=lambda value: round(value), - unit=VOLUME_LITERS, - default_enabled=False, + unit_of_measurement=VOLUME_LITERS, + entity_registry_enabled_default=False, ), - StateDescription( + OverkizSensorDescription( key="core:WaterConsumptionState", name="Water Consumption", icon="mdi:water", value=lambda value: round(value), - unit=VOLUME_LITERS, + unit_of_measurement=VOLUME_LITERS, ), - StateDescription( + OverkizSensorDescription( key="io:OutletEngineState", name="Outlet Engine", icon="mdi:fan-chevron-down", value=lambda value: round(value), - unit=VOLUME_LITERS, + unit_of_measurement=VOLUME_LITERS, ), - StateDescription( + OverkizSensorDescription( key="io:InletEngineState", name="Inlet Engine", icon="mdi:fan-chevron-up", value=lambda value: round(value), - unit=VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, + unit_of_measurement=VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, ), - StateDescription( + OverkizSensorDescription( key="hlrrwifi:RoomTemperatureState", name="Room Temperature", value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_TEMPERATURE, ), - StateDescription( + OverkizSensorDescription( key="io:MiddleWaterTemperatureState", name="Middle Water Temperature", value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_TEMPERATURE, ), - StateDescription( + OverkizSensorDescription( key="core:LuminanceState", name="Luminance", value=lambda value: round(value), device_class=DEVICE_CLASS_ILLUMINANCE, - unit=LIGHT_LUX, + unit_of_measurement=LIGHT_LUX, ), - StateDescription( + OverkizSensorDescription( key="io:PriorityLockOriginatorState", name="Priority Lock Originator", + value=lambda value: value, ), ] -class TahomaStateSensor(TahomaEntity, Entity): +class TahomaStateSensor(TahomaEntity, SensorEntity): """Representation of a TaHoma Sensor, based on a secondary device.""" def __init__( self, device_url: str, coordinator: TahomaDataUpdateCoordinator, - state_description: StateDescription, + description: OverkizSensorDescription, ): """Initialize the device.""" super().__init__(device_url, coordinator) - self._state_description = state_description + self.entity_description = description @property def state(self): """Return the value of the sensor.""" - state = self.select_state(self._state_description.key) + state = self.select_state(self.entity_description.key) - return self._state_description.value(state) if state is not None else None - - @property - def unit_of_measurement(self): - """Return the unit of measurement of this entity, if any.""" - return self._state_description.unit + return self.entity_description.value(state) if state is not None else None @property def name(self) -> str: """Return the name of the device.""" if self.index: - return f"{self._state_description.name} {self.index}" - return self._state_description.name - - @property - def icon(self) -> Optional[str]: - """Return the icon to use in the frontend, if any.""" - return self._state_description.icon - - @property - def device_class(self) -> Optional[str]: - """Return the device class of this entity if any.""" - return self._state_description.device_class - - @property - def entity_registry_enabled_default(self) -> bool: - """Return if the entity should be enabled when first added to the entity registry.""" - return self._state_description.default_enabled + return f"{self.entity_description.name} {self.index}" + return self.entity_description.name @property def unique_id(self) -> str: """Return a unique ID.""" - return f"{super().unique_id}-{self._state_description.key}" + return f"{super().unique_id}-{self.entity_description.key}" From 92b0131dd10073949ba5f494f604dd37ff115705 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 4 Aug 2021 15:10:57 +0200 Subject: [PATCH 16/35] Small tweaks --- custom_components/tahoma/state_sensor.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index 3a5055908..dc8fa4eef 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -32,7 +32,6 @@ class OverkizSensorDescription(SensorEntityDescription): name="Battery", unit_of_measurement=PERCENTAGE, device_class=sensor.DEVICE_CLASS_BATTERY, - value=lambda value: value, ), OverkizSensorDescription( key="core:RSSILevelState", @@ -105,7 +104,7 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="io:PriorityLockOriginatorState", name="Priority Lock Originator", - value=lambda value: value, + icon="mdi:alert", ), ] @@ -128,7 +127,13 @@ def state(self): """Return the value of the sensor.""" state = self.select_state(self.entity_description.key) - return self.entity_description.value(state) if state is not None else None + if state: + # Transform the value with a lambda function + if hasattr(self.entity_description, "value"): + return self.entity_description.value(state) + return state + + return None @property def name(self) -> str: From 9b0572260a6d870599560fb292a692bbe0f4abad Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 4 Aug 2021 15:15:44 +0200 Subject: [PATCH 17/35] Add battery level --- custom_components/tahoma/state_sensor.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index dc8fa4eef..3e63bacbe 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -27,6 +27,12 @@ class OverkizSensorDescription(SensorEntityDescription): SUPPORTED_STATES = [ + OverkizSensorDescription( + key="core:BatteryLevelState", + name="Battery Level", + unit_of_measurement=PERCENTAGE, + device_class=sensor.DEVICE_CLASS_BATTERY, + ), OverkizSensorDescription( key="core:BatteryState", name="Battery", From d9eb35dfea4f50664038e57094b5511985ed7ad5 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 4 Aug 2021 15:23:40 +0200 Subject: [PATCH 18/35] Remove unused state keys --- custom_components/tahoma/tahoma_entity.py | 27 ----------------------- 1 file changed, 27 deletions(-) diff --git a/custom_components/tahoma/tahoma_entity.py b/custom_components/tahoma/tahoma_entity.py index d04ae49c0..f460664fc 100644 --- a/custom_components/tahoma/tahoma_entity.py +++ b/custom_components/tahoma/tahoma_entity.py @@ -3,7 +3,6 @@ import re from typing import Any, Dict, Optional -from homeassistant.const import ATTR_BATTERY_LEVEL from homeassistant.helpers.entity import Entity from homeassistant.helpers.update_coordinator import CoordinatorEntity from pyhoma.models import Command, Device @@ -11,32 +10,13 @@ from .const import DOMAIN from .coordinator import TahomaDataUpdateCoordinator -CORE_AVAILABILITY_STATE = "core:AvailabilityState" -CORE_BATTERY_STATE = "core:BatteryState" CORE_MANUFACTURER = "core:Manufacturer" CORE_MANUFACTURER_NAME_STATE = "core:ManufacturerNameState" CORE_MODEL_STATE = "core:ModelState" CORE_PRODUCT_MODEL_NAME_STATE = "core:ProductModelNameState" -CORE_RSSI_LEVEL_STATE = "core:RSSILevelState" -CORE_SENSOR_DEFECT_STATE = "core:SensorDefectState" -CORE_STATUS_STATE = "core:StatusState" IO_MODEL_STATE = "io:ModelState" -STATE_AVAILABLE = "available" -STATE_BATTERY_FULL = "full" -STATE_BATTERY_NORMAL = "normal" -STATE_BATTERY_LOW = "low" -STATE_BATTERY_VERY_LOW = "verylow" -STATE_DEAD = "dead" - -BATTERY_MAP = { - STATE_BATTERY_FULL: 100, - STATE_BATTERY_NORMAL: 75, - STATE_BATTERY_LOW: 25, - STATE_BATTERY_VERY_LOW: 10, -} - _LOGGER = logging.getLogger(__name__) @@ -84,13 +64,6 @@ def device_state_attributes(self) -> Dict[str, Any]: """Return the state attributes of the device.""" attr = {} - if self.has_state(CORE_BATTERY_STATE): - battery_state = self.select_state(CORE_BATTERY_STATE) - attr[ATTR_BATTERY_LEVEL] = BATTERY_MAP.get(battery_state, battery_state) - - if self.select_state(CORE_SENSOR_DEFECT_STATE) == STATE_DEAD: - attr[ATTR_BATTERY_LEVEL] = 0 - if self.device.attributes: for attribute in self.device.attributes: attr[attribute.name] = attribute.value From a9fc25a9c37ce4409a70a0ad8efe12cfe8ad3810 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 4 Aug 2021 15:34:09 +0200 Subject: [PATCH 19/35] Test electricity sensor --- custom_components/tahoma/state_sensor.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index 3e63bacbe..c65f6f41d 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -5,15 +5,20 @@ from typing import Any, Callable from homeassistant.components import sensor -from homeassistant.components.sensor import SensorEntity, SensorEntityDescription +from homeassistant.components.sensor import ( + STATE_CLASS_MEASUREMENT, + SensorEntity, + SensorEntityDescription, +) from homeassistant.const import ( - DEVICE_CLASS_ILLUMINANCE, + ENERGY_WATT_HOUR, LIGHT_LUX, PERCENTAGE, SIGNAL_STRENGTH_DECIBELS, VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, VOLUME_LITERS, ) +from homeassistant.util.dt import utc_from_timestamp from .coordinator import TahomaDataUpdateCoordinator from .tahoma_entity import TahomaEntity @@ -104,7 +109,7 @@ class OverkizSensorDescription(SensorEntityDescription): key="core:LuminanceState", name="Luminance", value=lambda value: round(value), - device_class=DEVICE_CLASS_ILLUMINANCE, + device_class=sensor.DEVICE_CLASS_ILLUMINANCE, unit_of_measurement=LIGHT_LUX, ), OverkizSensorDescription( @@ -112,6 +117,16 @@ class OverkizSensorDescription(SensorEntityDescription): name="Priority Lock Originator", icon="mdi:alert", ), + # ElectricitySensor/CumulativeElectricPowerConsumptionSensor + OverkizSensorDescription( + key="core:ElectricEnergyConsumptionState", + name="Electric Energy Consumption", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # could read core:MeasuredValueType attribute.. + state_class=STATE_CLASS_MEASUREMENT, # core:MeasurementCategory attribute = electric/overall + last_reset=utc_from_timestamp(0), + ), ] From f6ba184e9cb708e6bcb5ad7ae66c33a96fcab581 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 4 Aug 2021 15:51:16 +0200 Subject: [PATCH 20/35] Add extra sensors --- custom_components/tahoma/state_sensor.py | 117 +++++++++++++++++++++-- 1 file changed, 110 insertions(+), 7 deletions(-) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index c65f6f41d..42e83eaeb 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -15,6 +15,7 @@ LIGHT_LUX, PERCENTAGE, SIGNAL_STRENGTH_DECIBELS, + TEMP_CELSIUS, VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, VOLUME_LITERS, ) @@ -105,17 +106,18 @@ class OverkizSensorDescription(SensorEntityDescription): value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_TEMPERATURE, ), + OverkizSensorDescription( + key="io:PriorityLockOriginatorState", + name="Priority Lock Originator", + icon="mdi:alert", + ), + # LightSensor/LuminanceSensor OverkizSensorDescription( key="core:LuminanceState", name="Luminance", value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_ILLUMINANCE, - unit_of_measurement=LIGHT_LUX, - ), - OverkizSensorDescription( - key="io:PriorityLockOriginatorState", - name="Priority Lock Originator", - icon="mdi:alert", + unit_of_measurement=LIGHT_LUX, # core:MeasuredValueType = core:LuminanceInLux ), # ElectricitySensor/CumulativeElectricPowerConsumptionSensor OverkizSensorDescription( @@ -123,10 +125,111 @@ class OverkizSensorDescription(SensorEntityDescription): name="Electric Energy Consumption", value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_ENERGY, - unit_of_measurement=ENERGY_WATT_HOUR, # could read core:MeasuredValueType attribute.. + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh state_class=STATE_CLASS_MEASUREMENT, # core:MeasurementCategory attribute = electric/overall last_reset=utc_from_timestamp(0), ), + OverkizSensorDescription( + key="core:ConsumptionTariff1State", + name="Consumption Tariff 1", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:ConsumptionTariff2State", + name="Consumption Tariff 2", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:ConsumptionTariff3State", + name="Consumption Tariff 3", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:ConsumptionTariff4State", + name="Consumption Tariff 4", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:ConsumptionTariff5State", + name="Consumption Tariff 5", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:ConsumptionTariff6State", + name="Consumption Tariff 6", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:ConsumptionTariff7State", + name="Consumption Tariff 7", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:ConsumptionTariff8State", + name="Consumption Tariff 8", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:ConsumptionTariff9State", + name="Consumption Tariff 9", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + # HumiditySensor/RelativeHumiditySensor + OverkizSensorDescription( + key="core:RelativeHumidityState", + name="Relative Humidity", + value=lambda value: round(value, 2), + device_class=sensor.DEVICE_CLASS_HUMIDITY, + unit_of_measurement=PERCENTAGE, # core:MeasuredValueType = core:RelativeValueInPercentage + ), + # TemperatureSensor/TemperatureSensor + OverkizSensorDescription( + key="core:TemperatureState", + name="Temperature", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_TEMPERATURE, + unit_of_measurement=TEMP_CELSIUS, # core:MeasuredValueType = core:TemperatureInCelcius + ), + # WeatherSensor/WeatherForecastSensor + OverkizSensorDescription( + key="core:WeatherStatusState", + name="Weather Status", + ), + OverkizSensorDescription( + key="core:MinimumTemperatureState", + name="Minimum Temperature", + ), + OverkizSensorDescription( + key="core:MaximumTemperatureState", + name="Maximum Temperature", + ), ] From d30727ab4292608345e198efdd6910191a9e10ab Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 4 Aug 2021 15:56:28 +0200 Subject: [PATCH 21/35] Add sensor --- custom_components/tahoma/state_sensor.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index 42e83eaeb..f5facb2ce 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -14,6 +14,7 @@ ENERGY_WATT_HOUR, LIGHT_LUX, PERCENTAGE, + POWER_WATT, SIGNAL_STRENGTH_DECIBELS, TEMP_CELSIUS, VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, @@ -125,10 +126,17 @@ class OverkizSensorDescription(SensorEntityDescription): name="Electric Energy Consumption", value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_ENERGY, - unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh (not for modbus:YutakiV2DHWElectricalEnergyConsumptionComponent) state_class=STATE_CLASS_MEASUREMENT, # core:MeasurementCategory attribute = electric/overall last_reset=utc_from_timestamp(0), ), + OverkizSensorDescription( + key="core:ElectricPowerConsumptionState", + name="Electric Power Consumption", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_POWER, + unit_of_measurement=POWER_WATT, # core:MeasuredValueType = core:ElectricalEnergyInWh (not for modbus:YutakiV2DHWElectricalEnergyConsumptionComponent) + ), OverkizSensorDescription( key="core:ConsumptionTariff1State", name="Consumption Tariff 1", From 513411de960d1193cc54c155a68f2dc5aed61975 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 4 Aug 2021 16:39:54 +0200 Subject: [PATCH 22/35] Add all sensors from sensor.py --- custom_components/tahoma/state_sensor.py | 45 ++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index f5facb2ce..7e6eee0e2 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -11,6 +11,7 @@ SensorEntityDescription, ) from homeassistant.const import ( + CONCENTRATION_PARTS_PER_MILLION, ENERGY_WATT_HOUR, LIGHT_LUX, PERCENTAGE, @@ -112,6 +113,19 @@ class OverkizSensorDescription(SensorEntityDescription): name="Priority Lock Originator", icon="mdi:alert", ), + OverkizSensorDescription( + key="core:FossilEnergyConsumptionState", + name="Fossil Energy Consumption", + device_class=sensor.DEVICE_CLASS_ENERGY, + ), + OverkizSensorDescription( + key="core:GasConsumptionState", + name="Gas Consumption", + ), + OverkizSensorDescription( + key="core:ThermalEnergyConsumptionState", + name="Thermal Energy Consumption", + ), # LightSensor/LuminanceSensor OverkizSensorDescription( key="core:LuminanceState", @@ -238,6 +252,37 @@ class OverkizSensorDescription(SensorEntityDescription): key="core:MaximumTemperatureState", name="Maximum Temperature", ), + # AirSensor/COSensor + OverkizSensorDescription( + key="core:COConcentrationState", + name="CO Concentration", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_CO, + unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, + ), + # AirSensor/CO2Sensor + OverkizSensorDescription( + key="core:CO2ConcentrationState", + name="CO2 Concentration", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_CO2, + unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, + ), + # SunSensor/SunEnergySensor + OverkizSensorDescription( + key="core:SunEnergyState", + name="Sun Energy", + value=lambda value: round(value, 2), + device_class=sensor.DEVICE_CLASS_ENERGY, + icon="mdi:solar-power", + ), + # WindSensor/WindSpeedSensor + OverkizSensorDescription( + key="core:WindSpeedState", + name="Wind Speed", + value=lambda value: round(value, 2), + icon="mdi:weather-windy", + ), ] From 814e22a843cd334b77a242b28e2010ab21ee13c1 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 4 Aug 2021 17:28:24 +0200 Subject: [PATCH 23/35] Add smoke text sensor --- custom_components/tahoma/state_sensor.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index 7e6eee0e2..c50272ec2 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -283,6 +283,13 @@ class OverkizSensorDescription(SensorEntityDescription): value=lambda value: round(value, 2), icon="mdi:weather-windy", ), + # SmokeSensor/SmokeSensor + OverkizSensorDescription( + key="io:SensorRoomState", + name="Sensor Room", + value=lambda value: str(value).capitalize(), + entity_registry_enabled_default=False, + ), ] From 56ef6f909f140a074185db1561ad80f0d85cc66e Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 4 Aug 2021 18:45:40 +0200 Subject: [PATCH 24/35] Make optional --- custom_components/tahoma/state_sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py index c50272ec2..ae756133e 100644 --- a/custom_components/tahoma/state_sensor.py +++ b/custom_components/tahoma/state_sensor.py @@ -31,7 +31,7 @@ class OverkizSensorDescription(SensorEntityDescription): """Class to describe a Overkiz sensor.""" - value: Callable[[Any], Any] = lambda val: val + value: Callable[[Any], Any] | None = lambda val: val SUPPORTED_STATES = [ From ad3d40036ca5a6be9b48fcffd410cdeb8989aabb Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 4 Aug 2021 20:18:47 +0200 Subject: [PATCH 25/35] Change all sensor to new structure --- custom_components/tahoma/sensor.py | 436 ++++++++++++++++------- custom_components/tahoma/state_sensor.py | 332 ----------------- 2 files changed, 307 insertions(+), 461 deletions(-) delete mode 100644 custom_components/tahoma/state_sensor.py diff --git a/custom_components/tahoma/sensor.py b/custom_components/tahoma/sensor.py index 1c1f5a17f..ba74ec024 100644 --- a/custom_components/tahoma/sensor.py +++ b/custom_components/tahoma/sensor.py @@ -1,104 +1,303 @@ """Support for TaHoma sensors.""" +from __future__ import annotations + +from dataclasses import dataclass import logging -from typing import Optional +from typing import Any, Callable -from homeassistant.components.sensor import DOMAIN as SENSOR +from homeassistant.components import sensor +from homeassistant.components.sensor import ( + STATE_CLASS_MEASUREMENT, + SensorEntity, + SensorEntityDescription, +) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( CONCENTRATION_PARTS_PER_MILLION, - DEVICE_CLASS_CO, - DEVICE_CLASS_CO2, - DEVICE_CLASS_HUMIDITY, - DEVICE_CLASS_POWER, - DEVICE_CLASS_TEMPERATURE, - ELECTRIC_CURRENT_AMPERE, - ELECTRIC_POTENTIAL_VOLT, - ENERGY_KILO_WATT_HOUR, ENERGY_WATT_HOUR, LIGHT_LUX, PERCENTAGE, - POWER_KILO_WATT, POWER_WATT, - SPEED_METERS_PER_SECOND, + SIGNAL_STRENGTH_DECIBELS, TEMP_CELSIUS, - TEMP_FAHRENHEIT, - TEMP_KELVIN, - VOLUME_CUBIC_METERS, + VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, VOLUME_LITERS, ) from homeassistant.core import HomeAssistant -from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.util.dt import utc_from_timestamp from .const import DOMAIN -from .state_sensor import SUPPORTED_STATES, TahomaStateSensor +from .coordinator import TahomaDataUpdateCoordinator from .tahoma_entity import TahomaEntity _LOGGER = logging.getLogger(__name__) -CORE_CO2_CONCENTRATION_STATE = "core:CO2ConcentrationState" -CORE_CO_CONCENTRATION_STATE = "core:COConcentrationState" -CORE_ELECTRIC_ENERGY_CONSUMPTION_STATE = "core:ElectricEnergyConsumptionState" -CORE_ELECTRIC_POWER_CONSUMPTION_STATE = "core:ElectricPowerConsumptionState" -CORE_FOSSIL_ENERGY_CONSUMPTION_STATE = "core:FossilEnergyConsumptionState" -CORE_GAS_CONSUMPTION_STATE = "core:GasConsumptionState" -CORE_MEASURED_VALUE_TYPE = "core:MeasuredValueType" -CORE_RELATIVE_HUMIDITY_STATE = "core:RelativeHumidityState" -CORE_SUN_ENERGY_STATE = "core:SunEnergyState" -CORE_TEMPERATURE_STATE = "core:TemperatureState" -CORE_THERMAL_ENERGY_CONSUMPTION_STATE = "core:ThermalEnergyConsumptionState" -CORE_WATER_CONSUMPTION_STATE = "core:WaterConsumptionState" -CORE_WINDSPEED_STATE = "core:WindSpeedState" - - -DEVICE_CLASS_SUN_ENERGY = "sun_energy" -DEVICE_CLASS_WIND_SPEED = "wind_speed" - -ICON_MOLECULE_CO = "mdi:molecule-co" -ICON_MOLECULE_CO2 = "mdi:molecule-co2" -ICON_SOLAR_POWER = "mdi:solar-power" -ICON_WEATHER_WINDY = "mdi:weather-windy" - -TAHOMA_SENSOR_DEVICE_CLASSES = { - "CO2Sensor": DEVICE_CLASS_CO2, - "COSensor": DEVICE_CLASS_CO, - "ElectricitySensor": DEVICE_CLASS_POWER, - "HumiditySensor": DEVICE_CLASS_HUMIDITY, - "RelativeHumiditySensor": DEVICE_CLASS_HUMIDITY, - "SunSensor": DEVICE_CLASS_SUN_ENERGY, - "TemperatureSensor": DEVICE_CLASS_TEMPERATURE, - "WindSensor": DEVICE_CLASS_WIND_SPEED, -} -# From https://www.tahomalink.com/enduser-mobile-web/steer-html5-client/tahoma/bootstrap.js -UNITS = { - "core:TemperatureInCelcius": TEMP_CELSIUS, - "core:TemperatureInCelsius": TEMP_CELSIUS, - "core:TemperatureInKelvin": TEMP_KELVIN, - "core:TemperatureInFahrenheit": TEMP_FAHRENHEIT, - "core:LuminanceInLux": LIGHT_LUX, - "core:ElectricCurrentInAmpere": ELECTRIC_CURRENT_AMPERE, - "core:VoltageInVolt": ELECTRIC_POTENTIAL_VOLT, - "core:ElectricalEnergyInWh": ENERGY_WATT_HOUR, - "core:ElectricalEnergyInKWh": ENERGY_KILO_WATT_HOUR, - "core:ElectricalEnergyInMWh": f"M{ENERGY_WATT_HOUR}", - "core:ElectricalPowerInW": POWER_WATT, - "core:ElectricalPowerInKW": POWER_KILO_WATT, - "core:ElectricalPowerInMW": f"M{POWER_WATT}", - "core:FlowInMeterCubePerHour": VOLUME_CUBIC_METERS, - "core:LinearSpeedInMeterPerSecond": SPEED_METERS_PER_SECOND, - "core:RelativeValueInPercentage": PERCENTAGE, - "core:VolumeInCubicMeter": VOLUME_CUBIC_METERS, - "core:VolumeInLiter": VOLUME_LITERS, - "core:FossilEnergyInWh": ENERGY_WATT_HOUR, - "core:FossilEnergyInKWh": ENERGY_KILO_WATT_HOUR, - "core:FossilEnergyInMWh": f"M{ENERGY_WATT_HOUR}", - "meters_seconds": SPEED_METERS_PER_SECOND, -} - -UNITS_BY_DEVICE_CLASS = { - DEVICE_CLASS_CO2: CONCENTRATION_PARTS_PER_MILLION, - DEVICE_CLASS_CO: CONCENTRATION_PARTS_PER_MILLION, -} + +@dataclass +class OverkizSensorDescription(SensorEntityDescription): + """Class to describe a Overkiz sensor.""" + + value: Callable[[Any], Any] | None = lambda val: val + + +SENSOR_DESCRIPTIONS = [ + OverkizSensorDescription( + key="core:BatteryLevelState", + name="Battery Level", + unit_of_measurement=PERCENTAGE, + device_class=sensor.DEVICE_CLASS_BATTERY, + ), + OverkizSensorDescription( + key="core:BatteryState", + name="Battery", + unit_of_measurement=PERCENTAGE, + device_class=sensor.DEVICE_CLASS_BATTERY, + ), + OverkizSensorDescription( + key="core:RSSILevelState", + name="RSSI Level", + value=lambda value: round(value), + unit_of_measurement=SIGNAL_STRENGTH_DECIBELS, + device_class=sensor.DEVICE_CLASS_SIGNAL_STRENGTH, + ), + OverkizSensorDescription( + key="core:ExpectedNumberOfShowerState", + name="Expected Number Of Shower", + icon="mdi:shower-head", + value=lambda value: round(value), + ), + OverkizSensorDescription( + key="core:NumberOfShowerRemainingState", + name="Number of Shower Remaining", + icon="mdi:shower-head", + value=lambda value: round(value), + ), + # V40 is measured in litres (L) and shows the amount of warm (mixed) water with a temperature of 40 C, which can be drained from a switched off electric water heater. + OverkizSensorDescription( + key="core:V40WaterVolumeEstimationState", + name="Water Volume Estimation at 40 °C", + icon="mdi:water", + value=lambda value: round(value), + unit_of_measurement=VOLUME_LITERS, + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:WaterConsumptionState", + name="Water Consumption", + icon="mdi:water", + value=lambda value: round(value), + unit_of_measurement=VOLUME_LITERS, + ), + OverkizSensorDescription( + key="io:OutletEngineState", + name="Outlet Engine", + icon="mdi:fan-chevron-down", + value=lambda value: round(value), + unit_of_measurement=VOLUME_LITERS, + ), + OverkizSensorDescription( + key="io:InletEngineState", + name="Inlet Engine", + icon="mdi:fan-chevron-up", + value=lambda value: round(value), + unit_of_measurement=VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, + ), + OverkizSensorDescription( + key="hlrrwifi:RoomTemperatureState", + name="Room Temperature", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_TEMPERATURE, + ), + OverkizSensorDescription( + key="io:MiddleWaterTemperatureState", + name="Middle Water Temperature", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_TEMPERATURE, + ), + OverkizSensorDescription( + key="io:PriorityLockOriginatorState", + name="Priority Lock Originator", + icon="mdi:alert", + ), + OverkizSensorDescription( + key="core:FossilEnergyConsumptionState", + name="Fossil Energy Consumption", + device_class=sensor.DEVICE_CLASS_ENERGY, + ), + OverkizSensorDescription( + key="core:GasConsumptionState", + name="Gas Consumption", + ), + OverkizSensorDescription( + key="core:ThermalEnergyConsumptionState", + name="Thermal Energy Consumption", + ), + # LightSensor/LuminanceSensor + OverkizSensorDescription( + key="core:LuminanceState", + name="Luminance", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ILLUMINANCE, + unit_of_measurement=LIGHT_LUX, # core:MeasuredValueType = core:LuminanceInLux + ), + # ElectricitySensor/CumulativeElectricPowerConsumptionSensor + OverkizSensorDescription( + key="core:ElectricEnergyConsumptionState", + name="Electric Energy Consumption", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh (not for modbus:YutakiV2DHWElectricalEnergyConsumptionComponent) + state_class=STATE_CLASS_MEASUREMENT, # core:MeasurementCategory attribute = electric/overall + last_reset=utc_from_timestamp(0), + ), + OverkizSensorDescription( + key="core:ElectricPowerConsumptionState", + name="Electric Power Consumption", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_POWER, + unit_of_measurement=POWER_WATT, # core:MeasuredValueType = core:ElectricalEnergyInWh (not for modbus:YutakiV2DHWElectricalEnergyConsumptionComponent) + ), + OverkizSensorDescription( + key="core:ConsumptionTariff1State", + name="Consumption Tariff 1", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:ConsumptionTariff2State", + name="Consumption Tariff 2", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:ConsumptionTariff3State", + name="Consumption Tariff 3", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:ConsumptionTariff4State", + name="Consumption Tariff 4", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:ConsumptionTariff5State", + name="Consumption Tariff 5", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:ConsumptionTariff6State", + name="Consumption Tariff 6", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:ConsumptionTariff7State", + name="Consumption Tariff 7", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:ConsumptionTariff8State", + name="Consumption Tariff 8", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + OverkizSensorDescription( + key="core:ConsumptionTariff9State", + name="Consumption Tariff 9", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_ENERGY, + unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh + entity_registry_enabled_default=False, + ), + # HumiditySensor/RelativeHumiditySensor + OverkizSensorDescription( + key="core:RelativeHumidityState", + name="Relative Humidity", + value=lambda value: round(value, 2), + device_class=sensor.DEVICE_CLASS_HUMIDITY, + unit_of_measurement=PERCENTAGE, # core:MeasuredValueType = core:RelativeValueInPercentage + ), + # TemperatureSensor/TemperatureSensor + OverkizSensorDescription( + key="core:TemperatureState", + name="Temperature", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_TEMPERATURE, + unit_of_measurement=TEMP_CELSIUS, # core:MeasuredValueType = core:TemperatureInCelcius + ), + # WeatherSensor/WeatherForecastSensor + OverkizSensorDescription( + key="core:WeatherStatusState", + name="Weather Status", + ), + OverkizSensorDescription( + key="core:MinimumTemperatureState", + name="Minimum Temperature", + ), + OverkizSensorDescription( + key="core:MaximumTemperatureState", + name="Maximum Temperature", + ), + # AirSensor/COSensor + OverkizSensorDescription( + key="core:COConcentrationState", + name="CO Concentration", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_CO, + unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, + ), + # AirSensor/CO2Sensor + OverkizSensorDescription( + key="core:CO2ConcentrationState", + name="CO2 Concentration", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_CO2, + unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, + ), + # SunSensor/SunEnergySensor + OverkizSensorDescription( + key="core:SunEnergyState", + name="Sun Energy", + value=lambda value: round(value, 2), + device_class=sensor.DEVICE_CLASS_ENERGY, + icon="mdi:solar-power", + ), + # WindSensor/WindSpeedSensor + OverkizSensorDescription( + key="core:WindSpeedState", + name="Wind Speed", + value=lambda value: round(value, 2), + icon="mdi:weather-windy", + ), + # SmokeSensor/SmokeSensor + OverkizSensorDescription( + key="io:SensorRoomState", + name="Sensor Room", + value=lambda value: str(value).capitalize(), + entity_registry_enabled_default=False, + ), +] async def async_setup_entry( @@ -110,15 +309,12 @@ async def async_setup_entry( data = hass.data[DOMAIN][entry.entry_id] coordinator = data["coordinator"] - entities = [ - TahomaSensor(device.deviceurl, coordinator) - for device in data["platforms"][SENSOR] - if device.states - ] + entities = [] key_supported_states = { - description.key: description for description in SUPPORTED_STATES + description.key: description for description in SENSOR_DESCRIPTIONS } + for device in coordinator.data.values(): for state in device.states: description = key_supported_states.get(state.name) @@ -134,58 +330,40 @@ async def async_setup_entry( async_add_entities(entities) -class TahomaSensor(TahomaEntity, Entity): +class TahomaStateSensor(TahomaEntity, SensorEntity): """Representation of a TaHoma Sensor.""" + def __init__( + self, + device_url: str, + coordinator: TahomaDataUpdateCoordinator, + description: OverkizSensorDescription, + ): + """Initialize the device.""" + super().__init__(device_url, coordinator) + self.entity_description = description + @property def state(self): """Return the value of the sensor.""" - state = self.select_state( - CORE_CO2_CONCENTRATION_STATE, - CORE_CO_CONCENTRATION_STATE, - CORE_ELECTRIC_ENERGY_CONSUMPTION_STATE, - CORE_ELECTRIC_POWER_CONSUMPTION_STATE, - CORE_FOSSIL_ENERGY_CONSUMPTION_STATE, - CORE_GAS_CONSUMPTION_STATE, - CORE_RELATIVE_HUMIDITY_STATE, - CORE_SUN_ENERGY_STATE, - CORE_TEMPERATURE_STATE, - CORE_THERMAL_ENERGY_CONSUMPTION_STATE, - CORE_WINDSPEED_STATE, - CORE_WATER_CONSUMPTION_STATE, - ) - return round(state, 2) if state is not None else None + state = self.select_state(self.entity_description.key) - @property - def unit_of_measurement(self): - """Return the unit of measurement of this entity, if any.""" - if ( - self.device.attributes - and CORE_MEASURED_VALUE_TYPE in self.device.attributes - ): - attribute = self.device.attributes[CORE_MEASURED_VALUE_TYPE] - return UNITS.get(attribute.value) - - if self.device_class in UNITS_BY_DEVICE_CLASS: - return UNITS_BY_DEVICE_CLASS.get(self.device_class) + if state: + # Transform the value with a lambda function + if hasattr(self.entity_description, "value"): + return self.entity_description.value(state) + return state return None @property - def icon(self) -> Optional[str]: - """Return the icon to use in the frontend, if any.""" - icons = { - DEVICE_CLASS_CO: ICON_MOLECULE_CO, - DEVICE_CLASS_CO2: ICON_MOLECULE_CO2, - DEVICE_CLASS_WIND_SPEED: ICON_WEATHER_WINDY, - DEVICE_CLASS_SUN_ENERGY: ICON_SOLAR_POWER, - } - - return icons.get(self.device_class) + def name(self) -> str: + """Return the name of the device.""" + if self.index: + return f"{self.entity_description.name} {self.index}" + return self.entity_description.name @property - def device_class(self) -> Optional[str]: - """Return the device class of this entity if any.""" - return TAHOMA_SENSOR_DEVICE_CLASSES.get( - self.device.widget - ) or TAHOMA_SENSOR_DEVICE_CLASSES.get(self.device.ui_class) + def unique_id(self) -> str: + """Return a unique ID.""" + return f"{super().unique_id}-{self.entity_description.key}" diff --git a/custom_components/tahoma/state_sensor.py b/custom_components/tahoma/state_sensor.py deleted file mode 100644 index ae756133e..000000000 --- a/custom_components/tahoma/state_sensor.py +++ /dev/null @@ -1,332 +0,0 @@ -"""Support for TaHoma sensors.""" -from __future__ import annotations - -from dataclasses import dataclass -from typing import Any, Callable - -from homeassistant.components import sensor -from homeassistant.components.sensor import ( - STATE_CLASS_MEASUREMENT, - SensorEntity, - SensorEntityDescription, -) -from homeassistant.const import ( - CONCENTRATION_PARTS_PER_MILLION, - ENERGY_WATT_HOUR, - LIGHT_LUX, - PERCENTAGE, - POWER_WATT, - SIGNAL_STRENGTH_DECIBELS, - TEMP_CELSIUS, - VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, - VOLUME_LITERS, -) -from homeassistant.util.dt import utc_from_timestamp - -from .coordinator import TahomaDataUpdateCoordinator -from .tahoma_entity import TahomaEntity - - -@dataclass -class OverkizSensorDescription(SensorEntityDescription): - """Class to describe a Overkiz sensor.""" - - value: Callable[[Any], Any] | None = lambda val: val - - -SUPPORTED_STATES = [ - OverkizSensorDescription( - key="core:BatteryLevelState", - name="Battery Level", - unit_of_measurement=PERCENTAGE, - device_class=sensor.DEVICE_CLASS_BATTERY, - ), - OverkizSensorDescription( - key="core:BatteryState", - name="Battery", - unit_of_measurement=PERCENTAGE, - device_class=sensor.DEVICE_CLASS_BATTERY, - ), - OverkizSensorDescription( - key="core:RSSILevelState", - name="RSSI Level", - value=lambda value: round(value), - unit_of_measurement=SIGNAL_STRENGTH_DECIBELS, - device_class=sensor.DEVICE_CLASS_SIGNAL_STRENGTH, - ), - OverkizSensorDescription( - key="core:ExpectedNumberOfShowerState", - name="Expected Number Of Shower", - icon="mdi:shower-head", - value=lambda value: round(value), - ), - OverkizSensorDescription( - key="core:NumberOfShowerRemainingState", - name="Number of Shower Remaining", - icon="mdi:shower-head", - value=lambda value: round(value), - ), - # V40 is measured in litres (L) and shows the amount of warm (mixed) water with a temperature of 40 C, which can be drained from a switched off electric water heater. - OverkizSensorDescription( - key="core:V40WaterVolumeEstimationState", - name="Water Volume Estimation at 40 °C", - icon="mdi:water", - value=lambda value: round(value), - unit_of_measurement=VOLUME_LITERS, - entity_registry_enabled_default=False, - ), - OverkizSensorDescription( - key="core:WaterConsumptionState", - name="Water Consumption", - icon="mdi:water", - value=lambda value: round(value), - unit_of_measurement=VOLUME_LITERS, - ), - OverkizSensorDescription( - key="io:OutletEngineState", - name="Outlet Engine", - icon="mdi:fan-chevron-down", - value=lambda value: round(value), - unit_of_measurement=VOLUME_LITERS, - ), - OverkizSensorDescription( - key="io:InletEngineState", - name="Inlet Engine", - icon="mdi:fan-chevron-up", - value=lambda value: round(value), - unit_of_measurement=VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, - ), - OverkizSensorDescription( - key="hlrrwifi:RoomTemperatureState", - name="Room Temperature", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_TEMPERATURE, - ), - OverkizSensorDescription( - key="io:MiddleWaterTemperatureState", - name="Middle Water Temperature", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_TEMPERATURE, - ), - OverkizSensorDescription( - key="io:PriorityLockOriginatorState", - name="Priority Lock Originator", - icon="mdi:alert", - ), - OverkizSensorDescription( - key="core:FossilEnergyConsumptionState", - name="Fossil Energy Consumption", - device_class=sensor.DEVICE_CLASS_ENERGY, - ), - OverkizSensorDescription( - key="core:GasConsumptionState", - name="Gas Consumption", - ), - OverkizSensorDescription( - key="core:ThermalEnergyConsumptionState", - name="Thermal Energy Consumption", - ), - # LightSensor/LuminanceSensor - OverkizSensorDescription( - key="core:LuminanceState", - name="Luminance", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_ILLUMINANCE, - unit_of_measurement=LIGHT_LUX, # core:MeasuredValueType = core:LuminanceInLux - ), - # ElectricitySensor/CumulativeElectricPowerConsumptionSensor - OverkizSensorDescription( - key="core:ElectricEnergyConsumptionState", - name="Electric Energy Consumption", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_ENERGY, - unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh (not for modbus:YutakiV2DHWElectricalEnergyConsumptionComponent) - state_class=STATE_CLASS_MEASUREMENT, # core:MeasurementCategory attribute = electric/overall - last_reset=utc_from_timestamp(0), - ), - OverkizSensorDescription( - key="core:ElectricPowerConsumptionState", - name="Electric Power Consumption", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_POWER, - unit_of_measurement=POWER_WATT, # core:MeasuredValueType = core:ElectricalEnergyInWh (not for modbus:YutakiV2DHWElectricalEnergyConsumptionComponent) - ), - OverkizSensorDescription( - key="core:ConsumptionTariff1State", - name="Consumption Tariff 1", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_ENERGY, - unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh - entity_registry_enabled_default=False, - ), - OverkizSensorDescription( - key="core:ConsumptionTariff2State", - name="Consumption Tariff 2", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_ENERGY, - unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh - entity_registry_enabled_default=False, - ), - OverkizSensorDescription( - key="core:ConsumptionTariff3State", - name="Consumption Tariff 3", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_ENERGY, - unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh - entity_registry_enabled_default=False, - ), - OverkizSensorDescription( - key="core:ConsumptionTariff4State", - name="Consumption Tariff 4", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_ENERGY, - unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh - entity_registry_enabled_default=False, - ), - OverkizSensorDescription( - key="core:ConsumptionTariff5State", - name="Consumption Tariff 5", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_ENERGY, - unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh - entity_registry_enabled_default=False, - ), - OverkizSensorDescription( - key="core:ConsumptionTariff6State", - name="Consumption Tariff 6", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_ENERGY, - unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh - entity_registry_enabled_default=False, - ), - OverkizSensorDescription( - key="core:ConsumptionTariff7State", - name="Consumption Tariff 7", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_ENERGY, - unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh - entity_registry_enabled_default=False, - ), - OverkizSensorDescription( - key="core:ConsumptionTariff8State", - name="Consumption Tariff 8", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_ENERGY, - unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh - entity_registry_enabled_default=False, - ), - OverkizSensorDescription( - key="core:ConsumptionTariff9State", - name="Consumption Tariff 9", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_ENERGY, - unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh - entity_registry_enabled_default=False, - ), - # HumiditySensor/RelativeHumiditySensor - OverkizSensorDescription( - key="core:RelativeHumidityState", - name="Relative Humidity", - value=lambda value: round(value, 2), - device_class=sensor.DEVICE_CLASS_HUMIDITY, - unit_of_measurement=PERCENTAGE, # core:MeasuredValueType = core:RelativeValueInPercentage - ), - # TemperatureSensor/TemperatureSensor - OverkizSensorDescription( - key="core:TemperatureState", - name="Temperature", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_TEMPERATURE, - unit_of_measurement=TEMP_CELSIUS, # core:MeasuredValueType = core:TemperatureInCelcius - ), - # WeatherSensor/WeatherForecastSensor - OverkizSensorDescription( - key="core:WeatherStatusState", - name="Weather Status", - ), - OverkizSensorDescription( - key="core:MinimumTemperatureState", - name="Minimum Temperature", - ), - OverkizSensorDescription( - key="core:MaximumTemperatureState", - name="Maximum Temperature", - ), - # AirSensor/COSensor - OverkizSensorDescription( - key="core:COConcentrationState", - name="CO Concentration", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_CO, - unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, - ), - # AirSensor/CO2Sensor - OverkizSensorDescription( - key="core:CO2ConcentrationState", - name="CO2 Concentration", - value=lambda value: round(value), - device_class=sensor.DEVICE_CLASS_CO2, - unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, - ), - # SunSensor/SunEnergySensor - OverkizSensorDescription( - key="core:SunEnergyState", - name="Sun Energy", - value=lambda value: round(value, 2), - device_class=sensor.DEVICE_CLASS_ENERGY, - icon="mdi:solar-power", - ), - # WindSensor/WindSpeedSensor - OverkizSensorDescription( - key="core:WindSpeedState", - name="Wind Speed", - value=lambda value: round(value, 2), - icon="mdi:weather-windy", - ), - # SmokeSensor/SmokeSensor - OverkizSensorDescription( - key="io:SensorRoomState", - name="Sensor Room", - value=lambda value: str(value).capitalize(), - entity_registry_enabled_default=False, - ), -] - - -class TahomaStateSensor(TahomaEntity, SensorEntity): - """Representation of a TaHoma Sensor, based on a secondary device.""" - - def __init__( - self, - device_url: str, - coordinator: TahomaDataUpdateCoordinator, - description: OverkizSensorDescription, - ): - """Initialize the device.""" - super().__init__(device_url, coordinator) - self.entity_description = description - - @property - def state(self): - """Return the value of the sensor.""" - state = self.select_state(self.entity_description.key) - - if state: - # Transform the value with a lambda function - if hasattr(self.entity_description, "value"): - return self.entity_description.value(state) - return state - - return None - - @property - def name(self) -> str: - """Return the name of the device.""" - if self.index: - return f"{self.entity_description.name} {self.index}" - return self.entity_description.name - - @property - def unique_id(self) -> str: - """Return a unique ID.""" - return f"{super().unique_id}-{self.entity_description.key}" From 25589885d1ae7f3c4cb8b6f6ebe5a51f9ffe1bd0 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 4 Aug 2021 20:33:04 +0200 Subject: [PATCH 26/35] Improve sensor definitions --- custom_components/tahoma/sensor.py | 37 +++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/custom_components/tahoma/sensor.py b/custom_components/tahoma/sensor.py index ba74ec024..aca7c3d02 100644 --- a/custom_components/tahoma/sensor.py +++ b/custom_components/tahoma/sensor.py @@ -47,12 +47,13 @@ class OverkizSensorDescription(SensorEntityDescription): name="Battery Level", unit_of_measurement=PERCENTAGE, device_class=sensor.DEVICE_CLASS_BATTERY, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="core:BatteryState", name="Battery", - unit_of_measurement=PERCENTAGE, device_class=sensor.DEVICE_CLASS_BATTERY, + value=lambda value: str(value).capitalize(), ), OverkizSensorDescription( key="core:RSSILevelState", @@ -60,18 +61,21 @@ class OverkizSensorDescription(SensorEntityDescription): value=lambda value: round(value), unit_of_measurement=SIGNAL_STRENGTH_DECIBELS, device_class=sensor.DEVICE_CLASS_SIGNAL_STRENGTH, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="core:ExpectedNumberOfShowerState", name="Expected Number Of Shower", icon="mdi:shower-head", value=lambda value: round(value), + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="core:NumberOfShowerRemainingState", name="Number of Shower Remaining", icon="mdi:shower-head", value=lambda value: round(value), + state_class=STATE_CLASS_MEASUREMENT, ), # V40 is measured in litres (L) and shows the amount of warm (mixed) water with a temperature of 40 C, which can be drained from a switched off electric water heater. OverkizSensorDescription( @@ -81,6 +85,7 @@ class OverkizSensorDescription(SensorEntityDescription): value=lambda value: round(value), unit_of_measurement=VOLUME_LITERS, entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="core:WaterConsumptionState", @@ -88,6 +93,7 @@ class OverkizSensorDescription(SensorEntityDescription): icon="mdi:water", value=lambda value: round(value), unit_of_measurement=VOLUME_LITERS, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="io:OutletEngineState", @@ -95,6 +101,7 @@ class OverkizSensorDescription(SensorEntityDescription): icon="mdi:fan-chevron-down", value=lambda value: round(value), unit_of_measurement=VOLUME_LITERS, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="io:InletEngineState", @@ -102,18 +109,21 @@ class OverkizSensorDescription(SensorEntityDescription): icon="mdi:fan-chevron-up", value=lambda value: round(value), unit_of_measurement=VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="hlrrwifi:RoomTemperatureState", name="Room Temperature", value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="io:MiddleWaterTemperatureState", name="Middle Water Temperature", value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="io:PriorityLockOriginatorState", @@ -140,6 +150,7 @@ class OverkizSensorDescription(SensorEntityDescription): value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_ILLUMINANCE, unit_of_measurement=LIGHT_LUX, # core:MeasuredValueType = core:LuminanceInLux + state_class=STATE_CLASS_MEASUREMENT, ), # ElectricitySensor/CumulativeElectricPowerConsumptionSensor OverkizSensorDescription( @@ -157,6 +168,7 @@ class OverkizSensorDescription(SensorEntityDescription): value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_POWER, unit_of_measurement=POWER_WATT, # core:MeasuredValueType = core:ElectricalEnergyInWh (not for modbus:YutakiV2DHWElectricalEnergyConsumptionComponent) + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="core:ConsumptionTariff1State", @@ -165,6 +177,7 @@ class OverkizSensorDescription(SensorEntityDescription): device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="core:ConsumptionTariff2State", @@ -173,6 +186,7 @@ class OverkizSensorDescription(SensorEntityDescription): device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="core:ConsumptionTariff3State", @@ -181,6 +195,7 @@ class OverkizSensorDescription(SensorEntityDescription): device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="core:ConsumptionTariff4State", @@ -189,6 +204,7 @@ class OverkizSensorDescription(SensorEntityDescription): device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="core:ConsumptionTariff5State", @@ -197,6 +213,7 @@ class OverkizSensorDescription(SensorEntityDescription): device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="core:ConsumptionTariff6State", @@ -205,6 +222,7 @@ class OverkizSensorDescription(SensorEntityDescription): device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="core:ConsumptionTariff7State", @@ -213,6 +231,7 @@ class OverkizSensorDescription(SensorEntityDescription): device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="core:ConsumptionTariff8State", @@ -221,6 +240,7 @@ class OverkizSensorDescription(SensorEntityDescription): device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="core:ConsumptionTariff9State", @@ -229,6 +249,7 @@ class OverkizSensorDescription(SensorEntityDescription): device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, ), # HumiditySensor/RelativeHumiditySensor OverkizSensorDescription( @@ -237,6 +258,7 @@ class OverkizSensorDescription(SensorEntityDescription): value=lambda value: round(value, 2), device_class=sensor.DEVICE_CLASS_HUMIDITY, unit_of_measurement=PERCENTAGE, # core:MeasuredValueType = core:RelativeValueInPercentage + state_class=STATE_CLASS_MEASUREMENT, ), # TemperatureSensor/TemperatureSensor OverkizSensorDescription( @@ -245,6 +267,7 @@ class OverkizSensorDescription(SensorEntityDescription): value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_TEMPERATURE, unit_of_measurement=TEMP_CELSIUS, # core:MeasuredValueType = core:TemperatureInCelcius + state_class=STATE_CLASS_MEASUREMENT, ), # WeatherSensor/WeatherForecastSensor OverkizSensorDescription( @@ -254,10 +277,18 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:MinimumTemperatureState", name="Minimum Temperature", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_TEMPERATURE, + unit_of_measurement=TEMP_CELSIUS, + state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="core:MaximumTemperatureState", name="Maximum Temperature", + value=lambda value: round(value), + device_class=sensor.DEVICE_CLASS_TEMPERATURE, + unit_of_measurement=TEMP_CELSIUS, + state_class=STATE_CLASS_MEASUREMENT, ), # AirSensor/COSensor OverkizSensorDescription( @@ -266,6 +297,7 @@ class OverkizSensorDescription(SensorEntityDescription): value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_CO, unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, + state_class=STATE_CLASS_MEASUREMENT, ), # AirSensor/CO2Sensor OverkizSensorDescription( @@ -274,6 +306,7 @@ class OverkizSensorDescription(SensorEntityDescription): value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_CO2, unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, + state_class=STATE_CLASS_MEASUREMENT, ), # SunSensor/SunEnergySensor OverkizSensorDescription( @@ -282,6 +315,7 @@ class OverkizSensorDescription(SensorEntityDescription): value=lambda value: round(value, 2), device_class=sensor.DEVICE_CLASS_ENERGY, icon="mdi:solar-power", + state_class=STATE_CLASS_MEASUREMENT, ), # WindSensor/WindSpeedSensor OverkizSensorDescription( @@ -289,6 +323,7 @@ class OverkizSensorDescription(SensorEntityDescription): name="Wind Speed", value=lambda value: round(value, 2), icon="mdi:weather-windy", + state_class=STATE_CLASS_MEASUREMENT, ), # SmokeSensor/SmokeSensor OverkizSensorDescription( From 3ab2a6604e6ad35f00513641f60f92dc750fee42 Mon Sep 17 00:00:00 2001 From: Thibaut Etienne Date: Thu, 5 Aug 2021 07:24:43 +0000 Subject: [PATCH 27/35] Ease state --- custom_components/tahoma/sensor.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/custom_components/tahoma/sensor.py b/custom_components/tahoma/sensor.py index aca7c3d02..b9acdc159 100644 --- a/custom_components/tahoma/sensor.py +++ b/custom_components/tahoma/sensor.py @@ -381,15 +381,13 @@ def __init__( @property def state(self): """Return the value of the sensor.""" - state = self.select_state(self.entity_description.key) + state = self.device.states[self.entity_description.key] - if state: - # Transform the value with a lambda function - if hasattr(self.entity_description, "value"): - return self.entity_description.value(state) - return state + # Transform the value with a lambda function + if hasattr(self.entity_description, "value"): + return self.entity_description.value(state.value) - return None + return state.value @property def name(self) -> str: From 2500780be501760aa2c9b6ff4d3d5f524620b456 Mon Sep 17 00:00:00 2001 From: Thibaut Etienne Date: Thu, 5 Aug 2021 07:27:52 +0000 Subject: [PATCH 28/35] Ease retrieve of the index --- custom_components/tahoma/tahoma_entity.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/custom_components/tahoma/tahoma_entity.py b/custom_components/tahoma/tahoma_entity.py index f460664fc..c7f082e27 100644 --- a/custom_components/tahoma/tahoma_entity.py +++ b/custom_components/tahoma/tahoma_entity.py @@ -27,12 +27,8 @@ def __init__(self, device_url: str, coordinator: TahomaDataUpdateCoordinator): """Initialize the device.""" super().__init__(coordinator) self.device_url = device_url - - if "#" in self.device_url: - self.base_device_url, self.index = self.device_url.split("#") - else: - self.base_device_url = self.device_url - self.index = None + self.base_device_url, *index = self.device_url.split("#") + self.index = index[0] if index else None @property def device(self) -> Device: From d16f11d1440626f5350fc5c3431379a77e06e67a Mon Sep 17 00:00:00 2001 From: Thibaut Etienne Date: Thu, 5 Aug 2021 07:31:14 +0000 Subject: [PATCH 29/35] Rollback device_state_attributes --- .../tahoma/cover_devices/tahoma_cover.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/custom_components/tahoma/cover_devices/tahoma_cover.py b/custom_components/tahoma/cover_devices/tahoma_cover.py index 3ad2f452c..cd63f38c8 100644 --- a/custom_components/tahoma/cover_devices/tahoma_cover.py +++ b/custom_components/tahoma/cover_devices/tahoma_cover.py @@ -64,6 +64,8 @@ ICON_LOCK_ALERT = "mdi:lock-alert" ICON_WEATHER_WINDY = "mdi:weather-windy" +IO_PRIORITY_LOCK_LEVEL_STATE = "io:PriorityLockLevelState" + STATE_CLOSED = "closed" SERVICE_COVER_MY_POSITION = "set_cover_my_position" @@ -241,6 +243,17 @@ def is_closing(self): and current_closure.value < target_closure.value ) + @property + def device_state_attributes(self): + """Return the device state attributes.""" + attr = super().device_state_attributes or {} + + # Obstruction Detected attribute is used by HomeKit + if self.has_state(IO_PRIORITY_LOCK_LEVEL_STATE): + attr[ATTR_OBSTRUCTION_DETECTED] = True + + return attr + @property def supported_features(self): """Flag supported features.""" From ee567a371a75b0c67c6950ea80c8da2986c7b099 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Mon, 9 Aug 2021 17:39:16 +0200 Subject: [PATCH 30/35] Revert battery changes --- .../tahoma/cover_devices/tahoma_cover.py | 3 --- custom_components/tahoma/tahoma_entity.py | 26 +++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/custom_components/tahoma/cover_devices/tahoma_cover.py b/custom_components/tahoma/cover_devices/tahoma_cover.py index cd63f38c8..d1d22554c 100644 --- a/custom_components/tahoma/cover_devices/tahoma_cover.py +++ b/custom_components/tahoma/cover_devices/tahoma_cover.py @@ -61,9 +61,6 @@ CORE_TARGET_CLOSURE_STATE = "core:TargetClosureState" MYFOX_SHUTTER_STATUS_STATE = "myfox:ShutterStatusState" -ICON_LOCK_ALERT = "mdi:lock-alert" -ICON_WEATHER_WINDY = "mdi:weather-windy" - IO_PRIORITY_LOCK_LEVEL_STATE = "io:PriorityLockLevelState" STATE_CLOSED = "closed" diff --git a/custom_components/tahoma/tahoma_entity.py b/custom_components/tahoma/tahoma_entity.py index c7f082e27..d4fc39e65 100644 --- a/custom_components/tahoma/tahoma_entity.py +++ b/custom_components/tahoma/tahoma_entity.py @@ -3,6 +3,7 @@ import re from typing import Any, Dict, Optional +from homeassistant.const import ATTR_BATTERY_LEVEL from homeassistant.helpers.entity import Entity from homeassistant.helpers.update_coordinator import CoordinatorEntity from pyhoma.models import Command, Device @@ -17,6 +18,24 @@ IO_MODEL_STATE = "io:ModelState" +# To be removed when this is implemented in sensor/binary sensor +CORE_BATTERY_STATE = "core:BatteryState" +CORE_SENSOR_DEFECT_STATE = "core:SensorDefectState" + +STATE_AVAILABLE = "available" +STATE_BATTERY_FULL = "full" +STATE_BATTERY_NORMAL = "normal" +STATE_BATTERY_LOW = "low" +STATE_BATTERY_VERY_LOW = "verylow" +STATE_DEAD = "dead" + +BATTERY_MAP = { + STATE_BATTERY_FULL: 100, + STATE_BATTERY_NORMAL: 75, + STATE_BATTERY_LOW: 25, + STATE_BATTERY_VERY_LOW: 10, +} + _LOGGER = logging.getLogger(__name__) @@ -60,6 +79,13 @@ def device_state_attributes(self) -> Dict[str, Any]: """Return the state attributes of the device.""" attr = {} + if self.has_state(CORE_BATTERY_STATE): + battery_state = self.select_state(CORE_BATTERY_STATE) + attr[ATTR_BATTERY_LEVEL] = BATTERY_MAP.get(battery_state, battery_state) + + if self.select_state(CORE_SENSOR_DEFECT_STATE) == STATE_DEAD: + attr[ATTR_BATTERY_LEVEL] = 0 + if self.device.attributes: for attribute in self.device.attributes: attr[attribute.name] = attribute.value From 44f921596781a73110bbbec5e5a356f1a3c96cc6 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Mon, 9 Aug 2021 17:45:04 +0200 Subject: [PATCH 31/35] Remove const --- custom_components/tahoma/const.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/custom_components/tahoma/const.py b/custom_components/tahoma/const.py index 153d62312..950b15ae3 100644 --- a/custom_components/tahoma/const.py +++ b/custom_components/tahoma/const.py @@ -5,7 +5,6 @@ from homeassistant.components.cover import DOMAIN as COVER from homeassistant.components.light import DOMAIN as LIGHT from homeassistant.components.lock import DOMAIN as LOCK -from homeassistant.components.sensor import DOMAIN as SENSOR from homeassistant.components.switch import DOMAIN as SWITCH from homeassistant.components.water_heater import DOMAIN as WATER_HEATER @@ -39,13 +38,26 @@ IGNORED_TAHOMA_DEVICES = [ "ProtocolGateway", "Pod", + # entries mapped to Sensor based on available states + "AirSensor", + "ConsumptionSensor", + "ElectricitySensor", + "SunIntensitySensor", + "SunSensor", + "GasSensor", + "GenericSensor", + "HumiditySensor", + "TemperatureSensor", + "ThermalEnergySensor", + "WaterSensor", + "WeatherSensor", + "WindSensor", ] # Used to map the Somfy widget and ui_class to the Home Assistant platform TAHOMA_DEVICE_TO_PLATFORM = { "AdjustableSlatsRollerShutter": COVER, "AirFlowSensor": BINARY_SENSOR, # widgetName, uiClass is AirSensor (sensor) - "AirSensor": SENSOR, "Alarm": ALARM_CONTROL_PANEL, "AtlanticElectricalHeater": CLIMATE, # widgetName, uiClass is HeatingSystem (not supported) "AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint": CLIMATE, # widgetName, uiClass is HeatingSystem (not supported) @@ -55,26 +67,21 @@ "AtlanticPassAPCZoneControl": CLIMATE, # widgetName, uiClass is HeatingSystem (not supported) "Awning": COVER, "CarButtonSensor": BINARY_SENSOR, - "ConsumptionSensor": SENSOR, "ContactSensor": BINARY_SENSOR, "Curtain": COVER, "DimmerExteriorHeating": CLIMATE, # widgetName, uiClass is ExteriorHeatingSystem (not supported) "DomesticHotWaterProduction": WATER_HEATER, # widgetName, uiClass is WaterHeatingSystem (not supported) "DomesticHotWaterTank": SWITCH, # widgetName, uiClass is WaterHeatingSystem (not supported) "DoorLock": LOCK, - "ElectricitySensor": SENSOR, "EvoHomeController": CLIMATE, # widgetName, uiClass is EvoHome (not supported) "ExteriorScreen": COVER, "ExteriorVenetianBlind": COVER, "GarageDoor": COVER, - "GasSensor": SENSOR, "Gate": COVER, - "GenericSensor": SENSOR, "HeatingSetPoint": CLIMATE, # widgetName, uiClass is EvoHome (not supported) "HitachiDHW": WATER_HEATER, # widgetName, uiClass is HitachiHeatingSystem (not supported) "HitachiAirToWaterHeatingZone": CLIMATE, # widgetName, uiClass is HitachiHeatingSystem (not supported) "HitachiAirToAirHeatPump": CLIMATE, # widgetName, uiClass is HitachiHeatingSystem (not supported) - "HumiditySensor": SENSOR, "Light": LIGHT, "MotionSensor": BINARY_SENSOR, "MyFoxSecurityCamera": COVER, # widgetName, uiClass is Camera (not supported) @@ -91,17 +98,10 @@ "SmokeSensor": BINARY_SENSOR, "SomfyThermostat": CLIMATE, # widgetName, uiClass is HeatingSystem (not supported) "StatelessExteriorHeating": CLIMATE, # widgetName, uiClass is ExteriorHeatingSystem. - "SunIntensitySensor": SENSOR, - "SunSensor": SENSOR, "SwimmingPool": SWITCH, "SwingingShutter": COVER, - "TemperatureSensor": SENSOR, - "ThermalEnergySensor": SENSOR, "VenetianBlind": COVER, "WaterDetectionSensor": BINARY_SENSOR, # widgetName, uiClass is HumiditySensor (sensor) - "WaterSensor": SENSOR, - "WeatherSensor": SENSOR, - "WindSensor": SENSOR, "Window": COVER, "WindowHandle": BINARY_SENSOR, } From 49e66d8248547742da293715876500412a8bd600 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Tue, 10 Aug 2021 09:44:02 +0200 Subject: [PATCH 32/35] Add LightSensor --- custom_components/tahoma/const.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/custom_components/tahoma/const.py b/custom_components/tahoma/const.py index 950b15ae3..85bf6c352 100644 --- a/custom_components/tahoma/const.py +++ b/custom_components/tahoma/const.py @@ -42,11 +42,12 @@ "AirSensor", "ConsumptionSensor", "ElectricitySensor", - "SunIntensitySensor", - "SunSensor", "GasSensor", "GenericSensor", "HumiditySensor", + "LightSensor", + "SunIntensitySensor", + "SunSensor", "TemperatureSensor", "ThermalEnergySensor", "WaterSensor", From 2b8a4ca1ca1e1e2c8eddd315e28ee680e3909d2b Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Tue, 10 Aug 2021 09:46:16 +0200 Subject: [PATCH 33/35] Rollback icon logic in cover --- .../tahoma/cover_devices/tahoma_cover.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/custom_components/tahoma/cover_devices/tahoma_cover.py b/custom_components/tahoma/cover_devices/tahoma_cover.py index d1d22554c..6cd044e77 100644 --- a/custom_components/tahoma/cover_devices/tahoma_cover.py +++ b/custom_components/tahoma/cover_devices/tahoma_cover.py @@ -62,6 +62,10 @@ MYFOX_SHUTTER_STATUS_STATE = "myfox:ShutterStatusState" IO_PRIORITY_LOCK_LEVEL_STATE = "io:PriorityLockLevelState" +IO_PRIORITY_LOCK_ORIGINATOR_STATE = "io:PriorityLockOriginatorState" + +ICON_LOCK_ALERT = "mdi:lock-alert" +ICON_WEATHER_WINDY = "mdi:weather-windy" STATE_CLOSED = "closed" @@ -275,3 +279,16 @@ def supported_features(self): supported_features |= SUPPORT_MY return supported_features + + @property + def icon(self): + """Return the icon to use in the frontend, if any.""" + if ( + self.has_state(CORE_PRIORITY_LOCK_TIMER_STATE) + and self.select_state(CORE_PRIORITY_LOCK_TIMER_STATE) > 0 + ): + if self.select_state(IO_PRIORITY_LOCK_ORIGINATOR_STATE) == "wind": + return ICON_WEATHER_WINDY + return ICON_LOCK_ALERT + + return None From dedfcb45be47c16e0165e2bf8fce24b154ce0a0a Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Tue, 10 Aug 2021 10:42:55 +0200 Subject: [PATCH 34/35] Bugfixes --- custom_components/tahoma/sensor.py | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/custom_components/tahoma/sensor.py b/custom_components/tahoma/sensor.py index b9acdc159..afa4ca0ef 100644 --- a/custom_components/tahoma/sensor.py +++ b/custom_components/tahoma/sensor.py @@ -58,7 +58,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:RSSILevelState", name="RSSI Level", - value=lambda value: round(value), unit_of_measurement=SIGNAL_STRENGTH_DECIBELS, device_class=sensor.DEVICE_CLASS_SIGNAL_STRENGTH, state_class=STATE_CLASS_MEASUREMENT, @@ -67,14 +66,12 @@ class OverkizSensorDescription(SensorEntityDescription): key="core:ExpectedNumberOfShowerState", name="Expected Number Of Shower", icon="mdi:shower-head", - value=lambda value: round(value), state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="core:NumberOfShowerRemainingState", name="Number of Shower Remaining", icon="mdi:shower-head", - value=lambda value: round(value), state_class=STATE_CLASS_MEASUREMENT, ), # V40 is measured in litres (L) and shows the amount of warm (mixed) water with a temperature of 40 C, which can be drained from a switched off electric water heater. @@ -82,7 +79,6 @@ class OverkizSensorDescription(SensorEntityDescription): key="core:V40WaterVolumeEstimationState", name="Water Volume Estimation at 40 °C", icon="mdi:water", - value=lambda value: round(value), unit_of_measurement=VOLUME_LITERS, entity_registry_enabled_default=False, state_class=STATE_CLASS_MEASUREMENT, @@ -91,7 +87,6 @@ class OverkizSensorDescription(SensorEntityDescription): key="core:WaterConsumptionState", name="Water Consumption", icon="mdi:water", - value=lambda value: round(value), unit_of_measurement=VOLUME_LITERS, state_class=STATE_CLASS_MEASUREMENT, ), @@ -99,7 +94,6 @@ class OverkizSensorDescription(SensorEntityDescription): key="io:OutletEngineState", name="Outlet Engine", icon="mdi:fan-chevron-down", - value=lambda value: round(value), unit_of_measurement=VOLUME_LITERS, state_class=STATE_CLASS_MEASUREMENT, ), @@ -107,21 +101,18 @@ class OverkizSensorDescription(SensorEntityDescription): key="io:InletEngineState", name="Inlet Engine", icon="mdi:fan-chevron-up", - value=lambda value: round(value), unit_of_measurement=VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="hlrrwifi:RoomTemperatureState", name="Room Temperature", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_TEMPERATURE, state_class=STATE_CLASS_MEASUREMENT, ), OverkizSensorDescription( key="io:MiddleWaterTemperatureState", name="Middle Water Temperature", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_TEMPERATURE, state_class=STATE_CLASS_MEASUREMENT, ), @@ -147,7 +138,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:LuminanceState", name="Luminance", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_ILLUMINANCE, unit_of_measurement=LIGHT_LUX, # core:MeasuredValueType = core:LuminanceInLux state_class=STATE_CLASS_MEASUREMENT, @@ -156,7 +146,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:ElectricEnergyConsumptionState", name="Electric Energy Consumption", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh (not for modbus:YutakiV2DHWElectricalEnergyConsumptionComponent) state_class=STATE_CLASS_MEASUREMENT, # core:MeasurementCategory attribute = electric/overall @@ -165,7 +154,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:ElectricPowerConsumptionState", name="Electric Power Consumption", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_POWER, unit_of_measurement=POWER_WATT, # core:MeasuredValueType = core:ElectricalEnergyInWh (not for modbus:YutakiV2DHWElectricalEnergyConsumptionComponent) state_class=STATE_CLASS_MEASUREMENT, @@ -173,7 +161,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:ConsumptionTariff1State", name="Consumption Tariff 1", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, @@ -182,7 +169,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:ConsumptionTariff2State", name="Consumption Tariff 2", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, @@ -191,7 +177,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:ConsumptionTariff3State", name="Consumption Tariff 3", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, @@ -200,7 +185,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:ConsumptionTariff4State", name="Consumption Tariff 4", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, @@ -209,7 +193,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:ConsumptionTariff5State", name="Consumption Tariff 5", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, @@ -218,7 +201,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:ConsumptionTariff6State", name="Consumption Tariff 6", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, @@ -227,7 +209,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:ConsumptionTariff7State", name="Consumption Tariff 7", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, @@ -236,7 +217,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:ConsumptionTariff8State", name="Consumption Tariff 8", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, @@ -245,7 +225,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:ConsumptionTariff9State", name="Consumption Tariff 9", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_ENERGY, unit_of_measurement=ENERGY_WATT_HOUR, # core:MeasuredValueType = core:ElectricalEnergyInWh entity_registry_enabled_default=False, @@ -264,7 +243,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:TemperatureState", name="Temperature", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_TEMPERATURE, unit_of_measurement=TEMP_CELSIUS, # core:MeasuredValueType = core:TemperatureInCelcius state_class=STATE_CLASS_MEASUREMENT, @@ -277,7 +255,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:MinimumTemperatureState", name="Minimum Temperature", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_TEMPERATURE, unit_of_measurement=TEMP_CELSIUS, state_class=STATE_CLASS_MEASUREMENT, @@ -285,7 +262,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:MaximumTemperatureState", name="Maximum Temperature", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_TEMPERATURE, unit_of_measurement=TEMP_CELSIUS, state_class=STATE_CLASS_MEASUREMENT, @@ -294,7 +270,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:COConcentrationState", name="CO Concentration", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_CO, unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, state_class=STATE_CLASS_MEASUREMENT, @@ -303,7 +278,6 @@ class OverkizSensorDescription(SensorEntityDescription): OverkizSensorDescription( key="core:CO2ConcentrationState", name="CO2 Concentration", - value=lambda value: round(value), device_class=sensor.DEVICE_CLASS_CO2, unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, state_class=STATE_CLASS_MEASUREMENT, From 4a513352b5a4380879bb2dcc866358f51078068a Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Tue, 10 Aug 2021 10:47:08 +0200 Subject: [PATCH 35/35] Add round for RSSI value --- custom_components/tahoma/sensor.py | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_components/tahoma/sensor.py b/custom_components/tahoma/sensor.py index afa4ca0ef..b2263b8fe 100644 --- a/custom_components/tahoma/sensor.py +++ b/custom_components/tahoma/sensor.py @@ -61,6 +61,7 @@ class OverkizSensorDescription(SensorEntityDescription): unit_of_measurement=SIGNAL_STRENGTH_DECIBELS, device_class=sensor.DEVICE_CLASS_SIGNAL_STRENGTH, state_class=STATE_CLASS_MEASUREMENT, + value=lambda value: round(value), ), OverkizSensorDescription( key="core:ExpectedNumberOfShowerState",