From 00293be492c95a79f41b3a54bd4eb80aaab4fd7d Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Thu, 11 Feb 2021 22:34:55 +0100 Subject: [PATCH 01/24] First try for AtlanticHeatRecoveryVentilation --- custom_components/tahoma/climate.py | 5 + .../atlantic_heat_recovery_ventilation.py | 162 ++++++++++++++++++ .../climate_devices/atlantic_pass_apcdhw.py | 2 +- custom_components/tahoma/const.py | 1 + 4 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py diff --git a/custom_components/tahoma/climate.py b/custom_components/tahoma/climate.py index dc8950b00..4e52ac9fa 100644 --- a/custom_components/tahoma/climate.py +++ b/custom_components/tahoma/climate.py @@ -2,6 +2,10 @@ from homeassistant.components.climate import DOMAIN as CLIMATE +from custom_components.tahoma.climate_devices.atlantic_heat_recovery_ventilation import ( + AtlanticHeatRecoveryVentilation, +) + from .climate_devices.atlantic_electrical_heater import AtlanticElectricalHeater from .climate_devices.atlantic_pass_apcdhw import AtlanticPassAPCDHW from .climate_devices.dimmer_exterior_heating import DimmerExteriorHeating @@ -11,6 +15,7 @@ TYPE = { "AtlanticElectricalHeater": AtlanticElectricalHeater, + "AtlanticHeatRecoveryVentilation": AtlanticHeatRecoveryVentilation, "SomfyThermostat": SomfyThermostat, "DimmerExteriorHeating": DimmerExteriorHeating, "StatelessExteriorHeating": StatelessExteriorHeating, diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py new file mode 100644 index 000000000..eaed6bd70 --- /dev/null +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -0,0 +1,162 @@ +"""Support for AtlanticHeatRecoveryVentilation.""" + +import logging +from typing import List, Optional + +from homeassistant.components.climate import ( + HVAC_MODE_COOL, + HVAC_MODE_HEAT, + SUPPORT_FAN_MODE, + SUPPORT_PRESET_MODE, + ClimateEntity, +) +from homeassistant.components.climate.const import ( + FAN_AUTO, + FAN_HIGH, + PRESET_COMFORT, + PRESET_ECO, +) + +from ..tahoma_device import TahomaDevice + +FAN_BOOST = "boost" +FAN_AWAY = "away" + +PRESET_PROG = "prog" +PRESET_MANUAL = "manual" + +COMMAND_SET_AIR_DEMAND_MODE = "setAirDemandMode" +COMMAND_SET_VENTILATION_CONFIGURATION_MODE = "setVentilationConfigurationMode" +COMMAND_SET_VENTILATION_MODE = "setVentilationMode" + +IO_AIR_DEMAND_MODE_STATE = "io:AirDemandModeState" + +FAN_MODE_TO_TAHOMA = { + FAN_AUTO: "auto", + FAN_BOOST: "boost", + FAN_HIGH: "high", + FAN_AWAY: "away", +} + +TAHOMA_TO_FAN_MODE = {v: k for k, v in FAN_MODE_TO_TAHOMA.items()} + +HVAC_MODES = [HVAC_MODE_COOL, HVAC_MODE_HEAT] +PRESET_MODES = [PRESET_COMFORT, PRESET_ECO, PRESET_PROG, PRESET_MANUAL] +_LOGGER = logging.getLogger(__name__) + + +class AtlanticHeatRecoveryVentilation(TahomaDevice, ClimateEntity): + """Representation of a AtlanticHeatRecoveryVentilation device.""" + + @property + def supported_features(self) -> int: + """Flag supported features.""" + return SUPPORT_PRESET_MODE | SUPPORT_FAN_MODE + + @property + def hvac_mode(self) -> str: + """Return hvac operation ie. heat, cool mode.""" + state = self.select_state("io:VentilationModeState") + _LOGGER.debug(state) + cooling = state.get("cooling") + + if cooling == "on": + return HVAC_MODE_COOL + else: + return HVAC_MODE_HEAT + + @property + def hvac_modes(self) -> List[str]: + """Return the list of available hvac operation modes.""" + return [HVAC_MODES] + + async def async_set_hvac_mode(self, hvac_mode: str) -> None: + """Set new target hvac mode.""" + if hvac_mode == HVAC_MODE_COOL: + await self.async_execute_command( + COMMAND_SET_VENTILATION_MODE, {"cooling": "on"} + ) + + if hvac_mode == HVAC_MODE_HEAT: + await self.async_execute_command( + COMMAND_SET_VENTILATION_MODE, {"cooling": "off"} + ) + + @property + def preset_mode(self) -> Optional[str]: + """Return the current preset mode, e.g., auto, smart, interval, favorite.""" + state_ventilation_configuration = self.select_state( + "io:VentilationConfigurationModeState" + ) + state_ventilation_mode = self.select_state("io:VentilationModeState") + state_prog = state_ventilation_mode.get("prog") + + if state_prog == "on": + return PRESET_PROG + + if state_ventilation_configuration == "comfort": + return PRESET_COMFORT + + if state_ventilation_configuration == "manual": + return PRESET_MANUAL + + if state_ventilation_configuration == "eco": + return PRESET_ECO + + return None + + @property + def preset_modes(self) -> Optional[List[str]]: + """Return a list of available preset modes.""" + return PRESET_MODES + + async def async_set_preset_mode(self, preset_mode: str) -> None: + """Set the preset mode of the fan.""" + + if preset_mode == PRESET_COMFORT: + await self.async_execute_command( + COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "comfort" + ) + await self.async_execute_command( + COMMAND_SET_VENTILATION_MODE, {"prog": "off"} + ) + + if preset_mode == PRESET_PROG: + await self.async_execute_command( + COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "standard" + ) + await self.async_execute_command( + COMMAND_SET_VENTILATION_MODE, {"prog": "on"} + ) + + if preset_mode == PRESET_MANUAL: + await self.async_execute_command( + COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "standard" + ) + await self.async_execute_command( + COMMAND_SET_VENTILATION_MODE, {"prog": "off"} + ) + + if preset_mode == PRESET_ECO: + await self.async_execute_command( + COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "eco" + ) + await self.async_execute_command( + COMMAND_SET_VENTILATION_MODE, {"prog": "off"} + ) + + @property + def fan_mode(self) -> Optional[str]: + """Return the fan setting.""" + return TAHOMA_TO_FAN_MODE[self.select_state(IO_AIR_DEMAND_MODE_STATE)] + + @property + def fan_modes(self) -> Optional[List[str]]: + """Return the list of available fan modes.""" + raise [*TAHOMA_TO_FAN_MODE] + + async def async_set_fan_mode(self, fan_mode: str) -> None: + """Set new target fan mode.""" + await self.async_execute_command( + COMMAND_SET_AIR_DEMAND_MODE, FAN_MODE_TO_TAHOMA[fan_mode] + ) diff --git a/custom_components/tahoma/climate_devices/atlantic_pass_apcdhw.py b/custom_components/tahoma/climate_devices/atlantic_pass_apcdhw.py index 52dce69e1..59dfd4d3b 100644 --- a/custom_components/tahoma/climate_devices/atlantic_pass_apcdhw.py +++ b/custom_components/tahoma/climate_devices/atlantic_pass_apcdhw.py @@ -1,4 +1,4 @@ -"""Support for AtlanticPassAPCDHWComponement.""" +"""Support for AtlanticPassAPCDHW.""" from typing import List, Optional from homeassistant.components.climate import ( diff --git a/custom_components/tahoma/const.py b/custom_components/tahoma/const.py index 5894aad67..c67b89630 100644 --- a/custom_components/tahoma/const.py +++ b/custom_components/tahoma/const.py @@ -38,6 +38,7 @@ "AirSensor": SENSOR, "Alarm": ALARM_CONTROL_PANEL, "AtlanticElectricalHeater": CLIMATE, # widgetName, uiClass is HeatingSystem (not supported) + "AtlanticHeatRecoveryVentilation": CLIMATE, # widgetName, uiClass is VentilationSystem (not supported) "AtlanticPassAPCDHW": CLIMATE, # widgetName, uiClass is WaterHeatingSystem (not supported) "Awning": COVER, "CarButtonSensor": BINARY_SENSOR, From dd5bd2cbd899b20cff3ece614b90ff382caf8e8b Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Thu, 11 Feb 2021 22:37:32 +0100 Subject: [PATCH 02/24] Bugfix --- custom_components/tahoma/climate.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/custom_components/tahoma/climate.py b/custom_components/tahoma/climate.py index 4e52ac9fa..5b860b618 100644 --- a/custom_components/tahoma/climate.py +++ b/custom_components/tahoma/climate.py @@ -2,11 +2,10 @@ from homeassistant.components.climate import DOMAIN as CLIMATE -from custom_components.tahoma.climate_devices.atlantic_heat_recovery_ventilation import ( +from .climate_devices.atlantic_electrical_heater import AtlanticElectricalHeater +from .climate_devices.atlantic_heat_recovery_ventilation import ( AtlanticHeatRecoveryVentilation, ) - -from .climate_devices.atlantic_electrical_heater import AtlanticElectricalHeater from .climate_devices.atlantic_pass_apcdhw import AtlanticPassAPCDHW from .climate_devices.dimmer_exterior_heating import DimmerExteriorHeating from .climate_devices.somfy_thermostat import SomfyThermostat From 4d0b8169ee114f19a69e6083d4ff69a05ef4885e Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 10 Mar 2021 16:59:31 +0100 Subject: [PATCH 03/24] Bugfix for sensor --- custom_components/tahoma/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/tahoma/sensor.py b/custom_components/tahoma/sensor.py index 5deab7413..bd36af3ef 100644 --- a/custom_components/tahoma/sensor.py +++ b/custom_components/tahoma/sensor.py @@ -134,7 +134,7 @@ def state(self): @property def unit_of_measurement(self): """Return the unit of measurement of this entity, if any.""" - if self.device.attributes: + if self.device.attributes and self.device.attributes[CORE_MEASURED_VALUE_TYPE]: attribute = self.device.attributes[CORE_MEASURED_VALUE_TYPE] return UNITS.get(attribute.value) return None From dc9ff4fd0322452339b15da58391cc6cc0daa930 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 10 Mar 2021 16:59:44 +0100 Subject: [PATCH 04/24] Bugfix --- .../climate_devices/atlantic_heat_recovery_ventilation.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index eaed6bd70..cfcfcb5c9 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -16,6 +16,7 @@ PRESET_COMFORT, PRESET_ECO, ) +from homeassistant.const import TEMP_CELSIUS from ..tahoma_device import TahomaDevice @@ -48,6 +49,11 @@ class AtlanticHeatRecoveryVentilation(TahomaDevice, ClimateEntity): """Representation of a AtlanticHeatRecoveryVentilation device.""" + @property + def temperature_unit(self) -> str: + """Return the unit of measurement used by the platform.""" + return TEMP_CELSIUS # TODO Investigate why this is required.. + @property def supported_features(self) -> int: """Flag supported features.""" @@ -153,7 +159,7 @@ def fan_mode(self) -> Optional[str]: @property def fan_modes(self) -> Optional[List[str]]: """Return the list of available fan modes.""" - raise [*TAHOMA_TO_FAN_MODE] + return [*FAN_MODE_TO_TAHOMA] async def async_set_fan_mode(self, fan_mode: str) -> None: """Set new target fan mode.""" From 619762dde2891a9f8e94115cb080d8e8c3baa593 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 10 Mar 2021 20:59:04 +0100 Subject: [PATCH 05/24] Fix merge conflict --- .../climate_devices/atlantic_heat_recovery_ventilation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index cfcfcb5c9..3109e260e 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -18,7 +18,7 @@ ) from homeassistant.const import TEMP_CELSIUS -from ..tahoma_device import TahomaDevice +from ..tahoma_entity import TahomaEntity FAN_BOOST = "boost" FAN_AWAY = "away" @@ -46,7 +46,7 @@ _LOGGER = logging.getLogger(__name__) -class AtlanticHeatRecoveryVentilation(TahomaDevice, ClimateEntity): +class AtlanticHeatRecoveryVentilation(TahomaEntity, ClimateEntity): """Representation of a AtlanticHeatRecoveryVentilation device.""" @property From 72529fb4c2f639fa137296e6b37a4658f30583f6 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Thu, 11 Mar 2021 00:00:07 +0100 Subject: [PATCH 06/24] Bugfix --- .../climate_devices/atlantic_heat_recovery_ventilation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index 3109e260e..35348784d 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -74,7 +74,7 @@ def hvac_mode(self) -> str: @property def hvac_modes(self) -> List[str]: """Return the list of available hvac operation modes.""" - return [HVAC_MODES] + return HVAC_MODES async def async_set_hvac_mode(self, hvac_mode: str) -> None: """Set new target hvac mode.""" From 907074d95f9cc8f2a71c3c71399e758714950cb4 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Thu, 11 Mar 2021 00:53:43 +0100 Subject: [PATCH 07/24] Add support for temperature --- .../atlantic_heat_recovery_ventilation.py | 75 ++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index 35348784d..c2ef1f4af 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -16,8 +16,11 @@ PRESET_COMFORT, PRESET_ECO, ) -from homeassistant.const import TEMP_CELSIUS +from homeassistant.const import EVENT_HOMEASSISTANT_START, STATE_UNKNOWN, TEMP_CELSIUS +from homeassistant.core import callback +from homeassistant.helpers.event import async_track_state_change +from ..coordinator import TahomaDataUpdateCoordinator from ..tahoma_entity import TahomaEntity FAN_BOOST = "boost" @@ -49,10 +52,78 @@ class AtlanticHeatRecoveryVentilation(TahomaEntity, ClimateEntity): """Representation of a AtlanticHeatRecoveryVentilation device.""" + def __init__(self, device_url: str, coordinator: TahomaDataUpdateCoordinator): + """Init method.""" + super().__init__(device_url, coordinator) + + self._temp_sensor_entity_id = None + self._current_temperature = None + + async def async_added_to_hass(self): + """Register temperature sensor after added to hass.""" + await super().async_added_to_hass() + + base_url = self.get_base_device_url() + entity_registry = await self.hass.helpers.entity_registry.async_get_registry() + self._temp_sensor_entity_id = next( + ( + entity_id + for entity_id, entry in entity_registry.entities.items() + if entry.unique_id == f"{base_url}#4" + ), + None, + ) + + if self._temp_sensor_entity_id: + async_track_state_change( + self.hass, self._temp_sensor_entity_id, self._async_temp_sensor_changed + ) + + else: + _LOGGER.warning( + "Temperature sensor could not be found for entity %s", self.name + ) + + @callback + def _async_startup(event): + """Init on startup.""" + if self._temp_sensor_entity_id: + temp_sensor_state = self.hass.states.get(self._temp_sensor_entity_id) + if temp_sensor_state and temp_sensor_state.state != STATE_UNKNOWN: + self.update_temp(temp_sensor_state) + + self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, _async_startup) + + self.schedule_update_ha_state(True) + + async def _async_temp_sensor_changed(self, entity_id, old_state, new_state) -> None: + """Handle temperature changes.""" + if new_state is None or old_state == new_state: + return + + self.update_temp(new_state) + self.schedule_update_ha_state() + + @callback + def update_temp(self, state): + """Update thermostat with latest state from sensor.""" + if state is None or state.state == STATE_UNKNOWN: + return + + try: + self._current_temperature = float(state.state) + except ValueError as ex: + _LOGGER.error("Unable to update from sensor: %s", ex) + + @property + def current_temperature(self) -> Optional[float]: + """Return the current temperature.""" + return self._current_temperature + @property def temperature_unit(self) -> str: """Return the unit of measurement used by the platform.""" - return TEMP_CELSIUS # TODO Investigate why this is required.. + return TEMP_CELSIUS @property def supported_features(self) -> int: From 2102846fa927977a0829019386ade0c6807a5304 Mon Sep 17 00:00:00 2001 From: tillstaff Date: Thu, 27 May 2021 22:10:31 +0200 Subject: [PATCH 08/24] fixes for "Add support for AtlanticHeatRecoveryVentilation" (#438) * fix ventilation commands * refactor ventilation command * refactor cooling mode --- .../atlantic_heat_recovery_ventilation.py | 126 ++++++++++-------- 1 file changed, 72 insertions(+), 54 deletions(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index c2ef1f4af..67dabdf31 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -1,20 +1,16 @@ """Support for AtlanticHeatRecoveryVentilation.""" import logging +import time +from datetime import date from typing import List, Optional -from homeassistant.components.climate import ( - HVAC_MODE_COOL, - HVAC_MODE_HEAT, - SUPPORT_FAN_MODE, - SUPPORT_PRESET_MODE, - ClimateEntity, -) +from homeassistant.components.climate import ClimateEntity from homeassistant.components.climate.const import ( FAN_AUTO, - FAN_HIGH, - PRESET_COMFORT, - PRESET_ECO, + HVAC_MODE_FAN_ONLY, + SUPPORT_FAN_MODE, + SUPPORT_PRESET_MODE, ) from homeassistant.const import EVENT_HOMEASSISTANT_START, STATE_UNKNOWN, TEMP_CELSIUS from homeassistant.core import callback @@ -23,29 +19,42 @@ from ..coordinator import TahomaDataUpdateCoordinator from ..tahoma_entity import TahomaEntity -FAN_BOOST = "boost" -FAN_AWAY = "away" +FAN_BOOST = "Home Boost" +FAN_KITCHEN = "Kitchen Boost" +FAN_AWAY = "Away" +FAN_BYPASS = "Bypass Boost" -PRESET_PROG = "prog" -PRESET_MANUAL = "manual" +PRESET_AUTO = "Auto" +PRESET_PROG = "Prog" +PRESET_MANUAL = "Manual" COMMAND_SET_AIR_DEMAND_MODE = "setAirDemandMode" COMMAND_SET_VENTILATION_CONFIGURATION_MODE = "setVentilationConfigurationMode" COMMAND_SET_VENTILATION_MODE = "setVentilationMode" +COMMAND_REFRESH_VENTILATION_STATE = "refreshVentilationState" +COMMAND_REFRESH_VENTILATION_CONFIGURATION_MODE = "refreshVentilationConfigurationMode" IO_AIR_DEMAND_MODE_STATE = "io:AirDemandModeState" FAN_MODE_TO_TAHOMA = { FAN_AUTO: "auto", FAN_BOOST: "boost", - FAN_HIGH: "high", + FAN_KITCHEN: "high", FAN_AWAY: "away", } TAHOMA_TO_FAN_MODE = {v: k for k, v in FAN_MODE_TO_TAHOMA.items()} -HVAC_MODES = [HVAC_MODE_COOL, HVAC_MODE_HEAT] -PRESET_MODES = [PRESET_COMFORT, PRESET_ECO, PRESET_PROG, PRESET_MANUAL] +HVAC_MODES = [HVAC_MODE_FAN_ONLY] +PRESET_MODES = [PRESET_AUTO, PRESET_PROG, PRESET_MANUAL] +FAN_MODES = [FAN_AUTO, FAN_BOOST, FAN_KITCHEN, FAN_AWAY, FAN_BYPASS] + +date=date.today() +DAY=date.day +MONTH=date.month + +VENTILATION_MODE_STATE = {"dayNight": "night","month": MONTH,"test": "off","endOfLineTest": "off","leapYear": "off","day": DAY,"cooling": "off","prog": "off"} + _LOGGER = logging.getLogger(__name__) @@ -133,14 +142,7 @@ def supported_features(self) -> int: @property def hvac_mode(self) -> str: """Return hvac operation ie. heat, cool mode.""" - state = self.select_state("io:VentilationModeState") - _LOGGER.debug(state) - cooling = state.get("cooling") - - if cooling == "on": - return HVAC_MODE_COOL - else: - return HVAC_MODE_HEAT + return HVAC_MODE_FAN_ONLY @property def hvac_modes(self) -> List[str]: @@ -149,15 +151,6 @@ def hvac_modes(self) -> List[str]: async def async_set_hvac_mode(self, hvac_mode: str) -> None: """Set new target hvac mode.""" - if hvac_mode == HVAC_MODE_COOL: - await self.async_execute_command( - COMMAND_SET_VENTILATION_MODE, {"cooling": "on"} - ) - - if hvac_mode == HVAC_MODE_HEAT: - await self.async_execute_command( - COMMAND_SET_VENTILATION_MODE, {"cooling": "off"} - ) @property def preset_mode(self) -> Optional[str]: @@ -172,14 +165,11 @@ def preset_mode(self) -> Optional[str]: return PRESET_PROG if state_ventilation_configuration == "comfort": - return PRESET_COMFORT + return PRESET_AUTO - if state_ventilation_configuration == "manual": + if state_ventilation_configuration == "standard": return PRESET_MANUAL - if state_ventilation_configuration == "eco": - return PRESET_ECO - return None @property @@ -190,50 +180,78 @@ def preset_modes(self) -> Optional[List[str]]: async def async_set_preset_mode(self, preset_mode: str) -> None: """Set the preset mode of the fan.""" - if preset_mode == PRESET_COMFORT: + if preset_mode == PRESET_AUTO: await self.async_execute_command( COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "comfort" ) + VENTILATION_MODE_STATE["prog"] = "off" await self.async_execute_command( - COMMAND_SET_VENTILATION_MODE, {"prog": "off"} + COMMAND_SET_VENTILATION_MODE, VENTILATION_MODE_STATE ) if preset_mode == PRESET_PROG: await self.async_execute_command( COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "standard" ) + VENTILATION_MODE_STATE["prog"] = "on" await self.async_execute_command( - COMMAND_SET_VENTILATION_MODE, {"prog": "on"} + COMMAND_SET_VENTILATION_MODE, VENTILATION_MODE_STATE ) if preset_mode == PRESET_MANUAL: await self.async_execute_command( COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "standard" ) + VENTILATION_MODE_STATE["prog"] = "off" await self.async_execute_command( - COMMAND_SET_VENTILATION_MODE, {"prog": "off"} - ) - - if preset_mode == PRESET_ECO: - await self.async_execute_command( - COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "eco" - ) - await self.async_execute_command( - COMMAND_SET_VENTILATION_MODE, {"prog": "off"} + COMMAND_SET_VENTILATION_MODE, VENTILATION_MODE_STATE ) + time.sleep(0.5) + await self.async_execute_command( + COMMAND_REFRESH_VENTILATION_STATE, + ) + await self.async_execute_command( + COMMAND_REFRESH_VENTILATION_CONFIGURATION_MODE, + ) @property def fan_mode(self) -> Optional[str]: """Return the fan setting.""" - return TAHOMA_TO_FAN_MODE[self.select_state(IO_AIR_DEMAND_MODE_STATE)] + state = self.select_state("io:VentilationModeState") + cooling = state.get("cooling") + if cooling == "on": + return FAN_BYPASS + else: + return TAHOMA_TO_FAN_MODE[self.select_state(IO_AIR_DEMAND_MODE_STATE)] @property def fan_modes(self) -> Optional[List[str]]: """Return the list of available fan modes.""" - return [*FAN_MODE_TO_TAHOMA] + return FAN_MODES async def async_set_fan_mode(self, fan_mode: str) -> None: """Set new target fan mode.""" + if fan_mode == FAN_BYPASS: + await self.async_execute_command( + COMMAND_SET_AIR_DEMAND_MODE, "auto" + ) + VENTILATION_MODE_STATE["cooling"] = "on" + await self.async_execute_command( + COMMAND_SET_VENTILATION_MODE, VENTILATION_MODE_STATE + ) + else: + if VENTILATION_MODE_STATE["cooling"] == "on": + VENTILATION_MODE_STATE["cooling"] = "off" + await self.async_execute_command( + COMMAND_SET_VENTILATION_MODE, VENTILATION_MODE_STATE + ) + await self.async_execute_command( + COMMAND_SET_AIR_DEMAND_MODE, FAN_MODE_TO_TAHOMA[fan_mode] + ) + time.sleep(0.5) + await self.async_execute_command( + COMMAND_REFRESH_VENTILATION_STATE, + ) await self.async_execute_command( - COMMAND_SET_AIR_DEMAND_MODE, FAN_MODE_TO_TAHOMA[fan_mode] + COMMAND_REFRESH_VENTILATION_CONFIGURATION_MODE, ) From d54163210c74741de1348c26bcee15def02ff759 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Fri, 28 May 2021 12:35:41 +0200 Subject: [PATCH 09/24] Clean up code --- .../atlantic_heat_recovery_ventilation.py | 110 +++++++++--------- 1 file changed, 53 insertions(+), 57 deletions(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index 67dabdf31..7939f5e58 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -1,8 +1,6 @@ """Support for AtlanticHeatRecoveryVentilation.""" - +import asyncio import logging -import time -from datetime import date from typing import List, Optional from homeassistant.components.climate import ClimateEntity @@ -19,14 +17,14 @@ from ..coordinator import TahomaDataUpdateCoordinator from ..tahoma_entity import TahomaEntity -FAN_BOOST = "Home Boost" -FAN_KITCHEN = "Kitchen Boost" -FAN_AWAY = "Away" -FAN_BYPASS = "Bypass Boost" +FAN_BOOST = "home_boost" +FAN_KITCHEN = "kitchen_boost" +FAN_AWAY = "away" +FAN_BYPASS = "bypass_boost" -PRESET_AUTO = "Auto" -PRESET_PROG = "Prog" -PRESET_MANUAL = "Manual" +PRESET_AUTO = "auto" +PRESET_PROG = "prog" +PRESET_MANUAL = "manual" COMMAND_SET_AIR_DEMAND_MODE = "setAirDemandMode" COMMAND_SET_VENTILATION_CONFIGURATION_MODE = "setVentilationConfigurationMode" @@ -35,25 +33,21 @@ COMMAND_REFRESH_VENTILATION_CONFIGURATION_MODE = "refreshVentilationConfigurationMode" IO_AIR_DEMAND_MODE_STATE = "io:AirDemandModeState" - -FAN_MODE_TO_TAHOMA = { - FAN_AUTO: "auto", - FAN_BOOST: "boost", - FAN_KITCHEN: "high", - FAN_AWAY: "away", +IO_VENTILATION_MODE_STATE = "io:VentilationModeState" +IO_VENTILATION_CONFIGURATION_MODE_STATE = "io:VentilationConfigurationModeState" + +TAHOMA_TO_FAN_MODES = { + "auto": FAN_AUTO, + "away": FAN_BOOST, + "boost": FAN_KITCHEN, + "high": FAN_AWAY, } -TAHOMA_TO_FAN_MODE = {v: k for k, v in FAN_MODE_TO_TAHOMA.items()} +FAN_MODES_TO_TAHOMA = {v: k for k, v in TAHOMA_TO_FAN_MODES.items()} HVAC_MODES = [HVAC_MODE_FAN_ONLY] PRESET_MODES = [PRESET_AUTO, PRESET_PROG, PRESET_MANUAL] -FAN_MODES = [FAN_AUTO, FAN_BOOST, FAN_KITCHEN, FAN_AWAY, FAN_BYPASS] - -date=date.today() -DAY=date.day -MONTH=date.month - -VENTILATION_MODE_STATE = {"dayNight": "night","month": MONTH,"test": "off","endOfLineTest": "off","leapYear": "off","day": DAY,"cooling": "off","prog": "off"} +FAN_MODES = [FAN_AUTO, FAN_BOOST, FAN_KITCHEN, FAN_AWAY] _LOGGER = logging.getLogger(__name__) @@ -156,9 +150,9 @@ async def async_set_hvac_mode(self, hvac_mode: str) -> None: def preset_mode(self) -> Optional[str]: """Return the current preset mode, e.g., auto, smart, interval, favorite.""" state_ventilation_configuration = self.select_state( - "io:VentilationConfigurationModeState" + IO_VENTILATION_CONFIGURATION_MODE_STATE ) - state_ventilation_mode = self.select_state("io:VentilationModeState") + state_ventilation_mode = self.select_state(IO_VENTILATION_MODE_STATE) state_prog = state_ventilation_mode.get("prog") if state_prog == "on": @@ -179,34 +173,26 @@ def preset_modes(self) -> Optional[List[str]]: async def async_set_preset_mode(self, preset_mode: str) -> None: """Set the preset mode of the fan.""" - if preset_mode == PRESET_AUTO: await self.async_execute_command( COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "comfort" ) - VENTILATION_MODE_STATE["prog"] = "off" - await self.async_execute_command( - COMMAND_SET_VENTILATION_MODE, VENTILATION_MODE_STATE - ) + await self._set_ventilation_mode(prog="off") if preset_mode == PRESET_PROG: await self.async_execute_command( COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "standard" ) - VENTILATION_MODE_STATE["prog"] = "on" - await self.async_execute_command( - COMMAND_SET_VENTILATION_MODE, VENTILATION_MODE_STATE - ) + await self._set_ventilation_mode(prog="on") if preset_mode == PRESET_MANUAL: await self.async_execute_command( COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "standard" ) - VENTILATION_MODE_STATE["prog"] = "off" - await self.async_execute_command( - COMMAND_SET_VENTILATION_MODE, VENTILATION_MODE_STATE - ) - time.sleep(0.5) + await self._set_ventilation_mode(prog="off") + + # TODO Get rid of sleep command + asyncio.sleep(0.5) await self.async_execute_command( COMMAND_REFRESH_VENTILATION_STATE, ) @@ -217,12 +203,13 @@ async def async_set_preset_mode(self, preset_mode: str) -> None: @property def fan_mode(self) -> Optional[str]: """Return the fan setting.""" - state = self.select_state("io:VentilationModeState") - cooling = state.get("cooling") + ventilation_mode_state = self.select_state(IO_VENTILATION_MODE_STATE) + cooling = ventilation_mode_state.get("cooling") + if cooling == "on": return FAN_BYPASS else: - return TAHOMA_TO_FAN_MODE[self.select_state(IO_AIR_DEMAND_MODE_STATE)] + return TAHOMA_TO_FAN_MODES[self.select_state(IO_AIR_DEMAND_MODE_STATE)] @property def fan_modes(self) -> Optional[List[str]]: @@ -232,26 +219,35 @@ def fan_modes(self) -> Optional[List[str]]: async def async_set_fan_mode(self, fan_mode: str) -> None: """Set new target fan mode.""" if fan_mode == FAN_BYPASS: - await self.async_execute_command( - COMMAND_SET_AIR_DEMAND_MODE, "auto" - ) - VENTILATION_MODE_STATE["cooling"] = "on" - await self.async_execute_command( - COMMAND_SET_VENTILATION_MODE, VENTILATION_MODE_STATE - ) + await self.async_execute_command(COMMAND_SET_AIR_DEMAND_MODE, "auto") else: - if VENTILATION_MODE_STATE["cooling"] == "on": - VENTILATION_MODE_STATE["cooling"] = "off" - await self.async_execute_command( - COMMAND_SET_VENTILATION_MODE, VENTILATION_MODE_STATE - ) await self.async_execute_command( - COMMAND_SET_AIR_DEMAND_MODE, FAN_MODE_TO_TAHOMA[fan_mode] + COMMAND_SET_AIR_DEMAND_MODE, FAN_MODES_TO_TAHOMA[fan_mode] ) - time.sleep(0.5) + + # TODO Get rid of sleep command + asyncio.sleep(0.5) await self.async_execute_command( COMMAND_REFRESH_VENTILATION_STATE, ) await self.async_execute_command( COMMAND_REFRESH_VENTILATION_CONFIGURATION_MODE, ) + + async def _set_ventilation_mode( + self, + cooling=None, + prog=None, + ): + """Execute ventilation mode command with all parameters.""" + ventilation_mode_state = self.select_state(IO_VENTILATION_MODE_STATE) + + if cooling: + ventilation_mode_state["cooling"] = cooling + + if prog: + ventilation_mode_state["prog"] = prog + + await self.async_execute_command( + COMMAND_SET_VENTILATION_MODE, ventilation_mode_state + ) From 1aae48cae65cefa3b1e27a910aab73cdaf994e92 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Fri, 28 May 2021 16:49:40 +0200 Subject: [PATCH 10/24] Small improvements --- .../climate_devices/atlantic_heat_recovery_ventilation.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index 7939f5e58..341027536 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -41,13 +41,12 @@ "away": FAN_BOOST, "boost": FAN_KITCHEN, "high": FAN_AWAY, + None: FAN_BYPASS, } FAN_MODES_TO_TAHOMA = {v: k for k, v in TAHOMA_TO_FAN_MODES.items()} -HVAC_MODES = [HVAC_MODE_FAN_ONLY] PRESET_MODES = [PRESET_AUTO, PRESET_PROG, PRESET_MANUAL] -FAN_MODES = [FAN_AUTO, FAN_BOOST, FAN_KITCHEN, FAN_AWAY] _LOGGER = logging.getLogger(__name__) @@ -141,7 +140,7 @@ def hvac_mode(self) -> str: @property def hvac_modes(self) -> List[str]: """Return the list of available hvac operation modes.""" - return HVAC_MODES + return HVAC_MODE_FAN_ONLY async def async_set_hvac_mode(self, hvac_mode: str) -> None: """Set new target hvac mode.""" @@ -214,7 +213,7 @@ def fan_mode(self) -> Optional[str]: @property def fan_modes(self) -> Optional[List[str]]: """Return the list of available fan modes.""" - return FAN_MODES + return [*FAN_MODES_TO_TAHOMA] async def async_set_fan_mode(self, fan_mode: str) -> None: """Set new target fan mode.""" From af7e54f384c9d4f6862e27195a0dc97f32ace5a6 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Fri, 28 May 2021 16:57:14 +0200 Subject: [PATCH 11/24] Bugfixes --- .../atlantic_heat_recovery_ventilation.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index 341027536..621a9e93c 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -1,5 +1,4 @@ """Support for AtlanticHeatRecoveryVentilation.""" -import asyncio import logging from typing import List, Optional @@ -140,10 +139,10 @@ def hvac_mode(self) -> str: @property def hvac_modes(self) -> List[str]: """Return the list of available hvac operation modes.""" - return HVAC_MODE_FAN_ONLY + return [HVAC_MODE_FAN_ONLY] async def async_set_hvac_mode(self, hvac_mode: str) -> None: - """Set new target hvac mode.""" + """Not implemented since there is only one hvac_mode.""" @property def preset_mode(self) -> Optional[str]: @@ -190,8 +189,6 @@ async def async_set_preset_mode(self, preset_mode: str) -> None: ) await self._set_ventilation_mode(prog="off") - # TODO Get rid of sleep command - asyncio.sleep(0.5) await self.async_execute_command( COMMAND_REFRESH_VENTILATION_STATE, ) @@ -224,8 +221,6 @@ async def async_set_fan_mode(self, fan_mode: str) -> None: COMMAND_SET_AIR_DEMAND_MODE, FAN_MODES_TO_TAHOMA[fan_mode] ) - # TODO Get rid of sleep command - asyncio.sleep(0.5) await self.async_execute_command( COMMAND_REFRESH_VENTILATION_STATE, ) From 22d9e7d6a04db0f21bf8944ae8f347d6edcb2239 Mon Sep 17 00:00:00 2001 From: Vincent Le Bourlot Date: Wed, 9 Feb 2022 21:31:26 +0000 Subject: [PATCH 12/24] fix linter error --- custom_components/tahoma/climate.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_components/tahoma/climate.py b/custom_components/tahoma/climate.py index 1f9e7125b..702d41877 100644 --- a/custom_components/tahoma/climate.py +++ b/custom_components/tahoma/climate.py @@ -6,16 +6,16 @@ from pyoverkiz.enums import UIWidget from . import HomeAssistantOverkizData -from .climate_devices.atlantic_electrical_heater import AtlanticElectricalHeater² -from .climate_devices.atlantic_heat_recovery_ventilation import ( - AtlanticHeatRecoveryVentilation, -) +from .climate_devices.atlantic_electrical_heater import AtlanticElectricalHeater from .climate_devices.atlantic_electrical_heater_with_adjustable_temperature_setpoint import ( AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint, ) from .climate_devices.atlantic_electrical_towel_dryer import ( AtlanticElectricalTowelDryer, ) +from .climate_devices.atlantic_heat_recovery_ventilation import ( + AtlanticHeatRecoveryVentilation, +) from .climate_devices.atlantic_pass_apc_heating_and_cooling_zone import ( AtlanticPassAPCHeatingAndCoolingZone, ) From a1b0d4893f85166bab3a998870474c71c4f11cde Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Sun, 20 Feb 2022 20:16:37 +0100 Subject: [PATCH 13/24] Bring back up to speed --- .../atlantic_heat_recovery_ventilation.py | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index 621a9e93c..40d6da9c4 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -13,8 +13,8 @@ from homeassistant.core import callback from homeassistant.helpers.event import async_track_state_change -from ..coordinator import TahomaDataUpdateCoordinator -from ..tahoma_entity import TahomaEntity +from ..coordinator import OverkizDataUpdateCoordinator +from ..entity import OverkizEntity FAN_BOOST = "home_boost" FAN_KITCHEN = "kitchen_boost" @@ -50,10 +50,10 @@ _LOGGER = logging.getLogger(__name__) -class AtlanticHeatRecoveryVentilation(TahomaEntity, ClimateEntity): +class AtlanticHeatRecoveryVentilation(OverkizEntity, ClimateEntity): """Representation of a AtlanticHeatRecoveryVentilation device.""" - def __init__(self, device_url: str, coordinator: TahomaDataUpdateCoordinator): + def __init__(self, device_url: str, coordinator: OverkizDataUpdateCoordinator): """Init method.""" super().__init__(device_url, coordinator) @@ -147,10 +147,10 @@ async def async_set_hvac_mode(self, hvac_mode: str) -> None: @property def preset_mode(self) -> Optional[str]: """Return the current preset mode, e.g., auto, smart, interval, favorite.""" - state_ventilation_configuration = self.select_state( + state_ventilation_configuration = self.executor.select_state( IO_VENTILATION_CONFIGURATION_MODE_STATE ) - state_ventilation_mode = self.select_state(IO_VENTILATION_MODE_STATE) + state_ventilation_mode = self.executor.select_state(IO_VENTILATION_MODE_STATE) state_prog = state_ventilation_mode.get("prog") if state_prog == "on": @@ -172,40 +172,42 @@ def preset_modes(self) -> Optional[List[str]]: async def async_set_preset_mode(self, preset_mode: str) -> None: """Set the preset mode of the fan.""" if preset_mode == PRESET_AUTO: - await self.async_execute_command( + await self.executor.async_execute_command( COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "comfort" ) await self._set_ventilation_mode(prog="off") if preset_mode == PRESET_PROG: - await self.async_execute_command( + await self.executor.async_execute_command( COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "standard" ) await self._set_ventilation_mode(prog="on") if preset_mode == PRESET_MANUAL: - await self.async_execute_command( + await self.executor.async_execute_command( COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "standard" ) await self._set_ventilation_mode(prog="off") - await self.async_execute_command( + await self.executor.async_execute_command( COMMAND_REFRESH_VENTILATION_STATE, ) - await self.async_execute_command( + await self.executor.async_execute_command( COMMAND_REFRESH_VENTILATION_CONFIGURATION_MODE, ) @property def fan_mode(self) -> Optional[str]: """Return the fan setting.""" - ventilation_mode_state = self.select_state(IO_VENTILATION_MODE_STATE) + ventilation_mode_state = self.executor.select_state(IO_VENTILATION_MODE_STATE) cooling = ventilation_mode_state.get("cooling") if cooling == "on": return FAN_BYPASS else: - return TAHOMA_TO_FAN_MODES[self.select_state(IO_AIR_DEMAND_MODE_STATE)] + return TAHOMA_TO_FAN_MODES[ + self.executor.select_state(IO_AIR_DEMAND_MODE_STATE) + ] @property def fan_modes(self) -> Optional[List[str]]: @@ -215,16 +217,18 @@ def fan_modes(self) -> Optional[List[str]]: async def async_set_fan_mode(self, fan_mode: str) -> None: """Set new target fan mode.""" if fan_mode == FAN_BYPASS: - await self.async_execute_command(COMMAND_SET_AIR_DEMAND_MODE, "auto") + await self.executor.async_execute_command( + COMMAND_SET_AIR_DEMAND_MODE, "auto" + ) else: - await self.async_execute_command( + await self.executor.async_execute_command( COMMAND_SET_AIR_DEMAND_MODE, FAN_MODES_TO_TAHOMA[fan_mode] ) - await self.async_execute_command( + await self.executor.async_execute_command( COMMAND_REFRESH_VENTILATION_STATE, ) - await self.async_execute_command( + await self.executor.async_execute_command( COMMAND_REFRESH_VENTILATION_CONFIGURATION_MODE, ) @@ -234,7 +238,7 @@ async def _set_ventilation_mode( prog=None, ): """Execute ventilation mode command with all parameters.""" - ventilation_mode_state = self.select_state(IO_VENTILATION_MODE_STATE) + ventilation_mode_state = self.executor.select_state(IO_VENTILATION_MODE_STATE) if cooling: ventilation_mode_state["cooling"] = cooling @@ -242,6 +246,6 @@ async def _set_ventilation_mode( if prog: ventilation_mode_state["prog"] = prog - await self.async_execute_command( + await self.executor.async_execute_command( COMMAND_SET_VENTILATION_MODE, ventilation_mode_state ) From 85fccd30e75df920a59d6edc2f37cb058ea9db31 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Sun, 20 Feb 2022 20:18:05 +0100 Subject: [PATCH 14/24] Bugfixes --- custom_components/tahoma/const.py | 1 + custom_components/tahoma/sensor.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/custom_components/tahoma/const.py b/custom_components/tahoma/const.py index 952ce1ba5..ce7da821e 100644 --- a/custom_components/tahoma/const.py +++ b/custom_components/tahoma/const.py @@ -41,6 +41,7 @@ OVERKIZ_DEVICE_TO_PLATFORM = { UIClass.ADJUSTABLE_SLATS_ROLLER_SHUTTER: Platform.COVER, UIClass.ALARM: Platform.ALARM_CONTROL_PANEL, + UIWidget.ATLANTIC_HEAT_RECOVERY_VENTILATION: Platform.CLIMATE, UIWidget.ATLANTIC_ELECTRICAL_HEATER: Platform.CLIMATE, # widgetName, uiClass is HeatingSystem (not supported) UIWidget.ATLANTIC_ELECTRICAL_HEATER_WITH_ADJUSTABLE_TEMPERATURE_SETPOINT: Platform.CLIMATE, # widgetName, uiClass is HeatingSystem (not supported) UIWidget.ATLANTIC_ELECTRICAL_TOWEL_DRYER: Platform.CLIMATE, # widgetName, uiClass is HeatingSystem (not supported) diff --git a/custom_components/tahoma/sensor.py b/custom_components/tahoma/sensor.py index d41ca0824..2d9b8026e 100644 --- a/custom_components/tahoma/sensor.py +++ b/custom_components/tahoma/sensor.py @@ -96,7 +96,7 @@ key=OverkizState.IO_OUTLET_ENGINE, name="Outlet Engine", icon="mdi:fan-chevron-down", - native_unit_of_measurement=VOLUME_LITERS, + native_unit_of_measurement=VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, state_class=SensorStateClass.MEASUREMENT, ), OverkizSensorDescription( From 34504c0126b266b5a603ed510bacb22eb426c061 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Sun, 20 Feb 2022 20:24:03 +0100 Subject: [PATCH 15/24] More fixes --- .../atlantic_heat_recovery_ventilation.py | 81 +++---------------- 1 file changed, 12 insertions(+), 69 deletions(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index 40d6da9c4..167467f26 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -2,6 +2,8 @@ import logging from typing import List, Optional +from pyoverkiz.enums import OverkizCommand, OverkizState + from homeassistant.components.climate import ClimateEntity from homeassistant.components.climate.const import ( FAN_AUTO, @@ -9,9 +11,7 @@ SUPPORT_FAN_MODE, SUPPORT_PRESET_MODE, ) -from homeassistant.const import EVENT_HOMEASSISTANT_START, STATE_UNKNOWN, TEMP_CELSIUS -from homeassistant.core import callback -from homeassistant.helpers.event import async_track_state_change +from homeassistant.const import TEMP_CELSIUS from ..coordinator import OverkizDataUpdateCoordinator from ..entity import OverkizEntity @@ -35,7 +35,7 @@ IO_VENTILATION_MODE_STATE = "io:VentilationModeState" IO_VENTILATION_CONFIGURATION_MODE_STATE = "io:VentilationConfigurationModeState" -TAHOMA_TO_FAN_MODES = { +OVERKIZ_TO_FAN_MODES = { "auto": FAN_AUTO, "away": FAN_BOOST, "boost": FAN_KITCHEN, @@ -43,7 +43,7 @@ None: FAN_BYPASS, } -FAN_MODES_TO_TAHOMA = {v: k for k, v in TAHOMA_TO_FAN_MODES.items()} +FAN_MODES_TO_OVERKIZ = {v: k for k, v in OVERKIZ_TO_FAN_MODES.items()} PRESET_MODES = [PRESET_AUTO, PRESET_PROG, PRESET_MANUAL] @@ -56,70 +56,12 @@ class AtlanticHeatRecoveryVentilation(OverkizEntity, ClimateEntity): def __init__(self, device_url: str, coordinator: OverkizDataUpdateCoordinator): """Init method.""" super().__init__(device_url, coordinator) - - self._temp_sensor_entity_id = None - self._current_temperature = None - - async def async_added_to_hass(self): - """Register temperature sensor after added to hass.""" - await super().async_added_to_hass() - - base_url = self.get_base_device_url() - entity_registry = await self.hass.helpers.entity_registry.async_get_registry() - self._temp_sensor_entity_id = next( - ( - entity_id - for entity_id, entry in entity_registry.entities.items() - if entry.unique_id == f"{base_url}#4" - ), - None, - ) - - if self._temp_sensor_entity_id: - async_track_state_change( - self.hass, self._temp_sensor_entity_id, self._async_temp_sensor_changed - ) - - else: - _LOGGER.warning( - "Temperature sensor could not be found for entity %s", self.name - ) - - @callback - def _async_startup(event): - """Init on startup.""" - if self._temp_sensor_entity_id: - temp_sensor_state = self.hass.states.get(self._temp_sensor_entity_id) - if temp_sensor_state and temp_sensor_state.state != STATE_UNKNOWN: - self.update_temp(temp_sensor_state) - - self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, _async_startup) - - self.schedule_update_ha_state(True) - - async def _async_temp_sensor_changed(self, entity_id, old_state, new_state) -> None: - """Handle temperature changes.""" - if new_state is None or old_state == new_state: - return - - self.update_temp(new_state) - self.schedule_update_ha_state() - - @callback - def update_temp(self, state): - """Update thermostat with latest state from sensor.""" - if state is None or state.state == STATE_UNKNOWN: - return - - try: - self._current_temperature = float(state.state) - except ValueError as ex: - _LOGGER.error("Unable to update from sensor: %s", ex) + self.temperature_device = self.executor.linked_device(4) @property def current_temperature(self) -> Optional[float]: """Return the current temperature.""" - return self._current_temperature + return self.temperature_device.states.get(OverkizState.CORE_TEMPERATURE).value @property def temperature_unit(self) -> str: @@ -143,6 +85,7 @@ def hvac_modes(self) -> List[str]: async def async_set_hvac_mode(self, hvac_mode: str) -> None: """Not implemented since there is only one hvac_mode.""" + pass @property def preset_mode(self) -> Optional[str]: @@ -173,7 +116,7 @@ async def async_set_preset_mode(self, preset_mode: str) -> None: """Set the preset mode of the fan.""" if preset_mode == PRESET_AUTO: await self.executor.async_execute_command( - COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "comfort" + OverkizCommand.SET_VENTILATION_CONFIGURATION_MODE, "comfort" ) await self._set_ventilation_mode(prog="off") @@ -205,14 +148,14 @@ def fan_mode(self) -> Optional[str]: if cooling == "on": return FAN_BYPASS else: - return TAHOMA_TO_FAN_MODES[ + return OVERKIZ_TO_FAN_MODES[ self.executor.select_state(IO_AIR_DEMAND_MODE_STATE) ] @property def fan_modes(self) -> Optional[List[str]]: """Return the list of available fan modes.""" - return [*FAN_MODES_TO_TAHOMA] + return [*FAN_MODES_TO_OVERKIZ] async def async_set_fan_mode(self, fan_mode: str) -> None: """Set new target fan mode.""" @@ -222,7 +165,7 @@ async def async_set_fan_mode(self, fan_mode: str) -> None: ) else: await self.executor.async_execute_command( - COMMAND_SET_AIR_DEMAND_MODE, FAN_MODES_TO_TAHOMA[fan_mode] + COMMAND_SET_AIR_DEMAND_MODE, FAN_MODES_TO_OVERKIZ[fan_mode] ) await self.executor.async_execute_command( From 83f55b77009cd79ff2ac0ddf62a2137c45458031 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Sun, 20 Feb 2022 20:25:31 +0100 Subject: [PATCH 16/24] Use constants --- .../atlantic_heat_recovery_ventilation.py | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index 167467f26..1013ab21c 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -25,12 +25,6 @@ PRESET_PROG = "prog" PRESET_MANUAL = "manual" -COMMAND_SET_AIR_DEMAND_MODE = "setAirDemandMode" -COMMAND_SET_VENTILATION_CONFIGURATION_MODE = "setVentilationConfigurationMode" -COMMAND_SET_VENTILATION_MODE = "setVentilationMode" -COMMAND_REFRESH_VENTILATION_STATE = "refreshVentilationState" -COMMAND_REFRESH_VENTILATION_CONFIGURATION_MODE = "refreshVentilationConfigurationMode" - IO_AIR_DEMAND_MODE_STATE = "io:AirDemandModeState" IO_VENTILATION_MODE_STATE = "io:VentilationModeState" IO_VENTILATION_CONFIGURATION_MODE_STATE = "io:VentilationConfigurationModeState" @@ -122,21 +116,21 @@ async def async_set_preset_mode(self, preset_mode: str) -> None: if preset_mode == PRESET_PROG: await self.executor.async_execute_command( - COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "standard" + OverkizCommand.SET_VENTILATION_CONFIGURATION_MODE, "standard" ) await self._set_ventilation_mode(prog="on") if preset_mode == PRESET_MANUAL: await self.executor.async_execute_command( - COMMAND_SET_VENTILATION_CONFIGURATION_MODE, "standard" + OverkizCommand.SET_VENTILATION_CONFIGURATION_MODE, "standard" ) await self._set_ventilation_mode(prog="off") await self.executor.async_execute_command( - COMMAND_REFRESH_VENTILATION_STATE, + OverkizCommand.REFRESH_VENTILATION_STATE, ) await self.executor.async_execute_command( - COMMAND_REFRESH_VENTILATION_CONFIGURATION_MODE, + OverkizCommand.REFRESH_VENTILATION_CONFIGURATION_MODE, ) @property @@ -161,18 +155,18 @@ async def async_set_fan_mode(self, fan_mode: str) -> None: """Set new target fan mode.""" if fan_mode == FAN_BYPASS: await self.executor.async_execute_command( - COMMAND_SET_AIR_DEMAND_MODE, "auto" + OverkizCommand.SET_AIR_DEMAND_MODE, "auto" ) else: await self.executor.async_execute_command( - COMMAND_SET_AIR_DEMAND_MODE, FAN_MODES_TO_OVERKIZ[fan_mode] + OverkizCommand.SET_AIR_DEMAND_MODE, FAN_MODES_TO_OVERKIZ[fan_mode] ) await self.executor.async_execute_command( - COMMAND_REFRESH_VENTILATION_STATE, + OverkizCommand.REFRESH_VENTILATION_STATE, ) await self.executor.async_execute_command( - COMMAND_REFRESH_VENTILATION_CONFIGURATION_MODE, + OverkizCommand.REFRESH_VENTILATION_CONFIGURATION_MODE, ) async def _set_ventilation_mode( @@ -181,7 +175,9 @@ async def _set_ventilation_mode( prog=None, ): """Execute ventilation mode command with all parameters.""" - ventilation_mode_state = self.executor.select_state(IO_VENTILATION_MODE_STATE) + ventilation_mode_state = self.executor.select_state( + OverkizState.IO_VENTILATION_MODE + ) if cooling: ventilation_mode_state["cooling"] = cooling @@ -190,5 +186,5 @@ async def _set_ventilation_mode( ventilation_mode_state["prog"] = prog await self.executor.async_execute_command( - COMMAND_SET_VENTILATION_MODE, ventilation_mode_state + OverkizCommand.SET_VENTILATION_MODE, ventilation_mode_state ) From 083af5216496ce2709dfbe490bd87fc342de9fc9 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Sun, 20 Feb 2022 20:36:40 +0100 Subject: [PATCH 17/24] New standards --- .../atlantic_heat_recovery_ventilation.py | 59 ++++++++++--------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index 1013ab21c..4953237ee 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -2,7 +2,7 @@ import logging from typing import List, Optional -from pyoverkiz.enums import OverkizCommand, OverkizState +from pyoverkiz.enums import OverkizCommand, OverkizCommandParam, OverkizState from homeassistant.components.climate import ClimateEntity from homeassistant.components.climate.const import ( @@ -25,15 +25,11 @@ PRESET_PROG = "prog" PRESET_MANUAL = "manual" -IO_AIR_DEMAND_MODE_STATE = "io:AirDemandModeState" -IO_VENTILATION_MODE_STATE = "io:VentilationModeState" -IO_VENTILATION_CONFIGURATION_MODE_STATE = "io:VentilationConfigurationModeState" - OVERKIZ_TO_FAN_MODES = { - "auto": FAN_AUTO, - "away": FAN_BOOST, - "boost": FAN_KITCHEN, - "high": FAN_AWAY, + OverkizCommandParam.AUTO: FAN_AUTO, + OverkizCommandParam.AWAY: FAN_BOOST, + OverkizCommandParam.BOOST: FAN_KITCHEN, + OverkizCommandParam.HIGH: FAN_AWAY, None: FAN_BYPASS, } @@ -85,18 +81,20 @@ async def async_set_hvac_mode(self, hvac_mode: str) -> None: def preset_mode(self) -> Optional[str]: """Return the current preset mode, e.g., auto, smart, interval, favorite.""" state_ventilation_configuration = self.executor.select_state( - IO_VENTILATION_CONFIGURATION_MODE_STATE + OverkizState.IO_VENTILATION_CONFIGURATION_MODE + ) + state_ventilation_mode = self.executor.select_state( + OverkizState.IO_VENTILATION_MODE ) - state_ventilation_mode = self.executor.select_state(IO_VENTILATION_MODE_STATE) - state_prog = state_ventilation_mode.get("prog") + state_prog = state_ventilation_mode.get(OverkizCommandParam.PROG) - if state_prog == "on": + if state_prog == OverkizCommandParam.PROG: return PRESET_PROG - if state_ventilation_configuration == "comfort": + if state_ventilation_configuration == OverkizCommandParam.COMFORT: return PRESET_AUTO - if state_ventilation_configuration == "standard": + if state_ventilation_configuration == OverkizCommandParam.STANDARD: return PRESET_MANUAL return None @@ -110,21 +108,24 @@ async def async_set_preset_mode(self, preset_mode: str) -> None: """Set the preset mode of the fan.""" if preset_mode == PRESET_AUTO: await self.executor.async_execute_command( - OverkizCommand.SET_VENTILATION_CONFIGURATION_MODE, "comfort" + OverkizCommand.SET_VENTILATION_CONFIGURATION_MODE, + OverkizCommandParam.COMFORT, ) - await self._set_ventilation_mode(prog="off") + await self._set_ventilation_mode(prog=OverkizCommandParam.OFF) if preset_mode == PRESET_PROG: await self.executor.async_execute_command( - OverkizCommand.SET_VENTILATION_CONFIGURATION_MODE, "standard" + OverkizCommand.SET_VENTILATION_CONFIGURATION_MODE, + OverkizCommandParam.STANDARD, ) - await self._set_ventilation_mode(prog="on") + await self._set_ventilation_mode(prog=OverkizCommandParam.ON) if preset_mode == PRESET_MANUAL: await self.executor.async_execute_command( - OverkizCommand.SET_VENTILATION_CONFIGURATION_MODE, "standard" + OverkizCommand.SET_VENTILATION_CONFIGURATION_MODE, + OverkizCommandParam.STANDARD, ) - await self._set_ventilation_mode(prog="off") + await self._set_ventilation_mode(prog=OverkizCommandParam.OFF) await self.executor.async_execute_command( OverkizCommand.REFRESH_VENTILATION_STATE, @@ -136,14 +137,16 @@ async def async_set_preset_mode(self, preset_mode: str) -> None: @property def fan_mode(self) -> Optional[str]: """Return the fan setting.""" - ventilation_mode_state = self.executor.select_state(IO_VENTILATION_MODE_STATE) - cooling = ventilation_mode_state.get("cooling") + ventilation_mode_state = self.executor.select_state( + OverkizState.IO_VENTILATION_MODE + ) + cooling = ventilation_mode_state.get(OverkizCommandParam.COOLING) - if cooling == "on": + if cooling == OverkizCommandParam.ON: return FAN_BYPASS else: return OVERKIZ_TO_FAN_MODES[ - self.executor.select_state(IO_AIR_DEMAND_MODE_STATE) + self.executor.select_state(OverkizState.IO_AIR_DEMAND_MODE) ] @property @@ -155,7 +158,7 @@ async def async_set_fan_mode(self, fan_mode: str) -> None: """Set new target fan mode.""" if fan_mode == FAN_BYPASS: await self.executor.async_execute_command( - OverkizCommand.SET_AIR_DEMAND_MODE, "auto" + OverkizCommand.SET_AIR_DEMAND_MODE, OverkizCommandParam.AUTO ) else: await self.executor.async_execute_command( @@ -180,10 +183,10 @@ async def _set_ventilation_mode( ) if cooling: - ventilation_mode_state["cooling"] = cooling + ventilation_mode_state[OverkizCommandParam.COOLING] = cooling if prog: - ventilation_mode_state["prog"] = prog + ventilation_mode_state[OverkizCommandParam.PROG] = prog await self.executor.async_execute_command( OverkizCommand.SET_VENTILATION_MODE, ventilation_mode_state From 8a1eeb022016e0bae6eaa9fe59f6aea4686db809 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Mon, 21 Feb 2022 23:39:17 +0100 Subject: [PATCH 18/24] Bugfix --- .../climate_devices/atlantic_heat_recovery_ventilation.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index 4953237ee..60dd5ed31 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -27,9 +27,9 @@ OVERKIZ_TO_FAN_MODES = { OverkizCommandParam.AUTO: FAN_AUTO, - OverkizCommandParam.AWAY: FAN_BOOST, - OverkizCommandParam.BOOST: FAN_KITCHEN, - OverkizCommandParam.HIGH: FAN_AWAY, + OverkizCommandParam.AWAY: FAN_AWAY, + OverkizCommandParam.BOOST: FAN_BOOST, + OverkizCommandParam.HIGH: FAN_KITCHEN, None: FAN_BYPASS, } From 39f77168c2ad831a10b8c8ac3e5205814e8410da Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Tue, 22 Feb 2022 14:58:43 +0100 Subject: [PATCH 19/24] Update atlantic_heat_recovery_ventilation.py --- .../atlantic_heat_recovery_ventilation.py | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index 60dd5ed31..d122217cf 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -1,5 +1,4 @@ """Support for AtlanticHeatRecoveryVentilation.""" -import logging from typing import List, Optional from pyoverkiz.enums import OverkizCommand, OverkizCommandParam, OverkizState @@ -37,8 +36,6 @@ PRESET_MODES = [PRESET_AUTO, PRESET_PROG, PRESET_MANUAL] -_LOGGER = logging.getLogger(__name__) - class AtlanticHeatRecoveryVentilation(OverkizEntity, ClimateEntity): """Representation of a AtlanticHeatRecoveryVentilation device.""" @@ -80,21 +77,22 @@ async def async_set_hvac_mode(self, hvac_mode: str) -> None: @property def preset_mode(self) -> Optional[str]: """Return the current preset mode, e.g., auto, smart, interval, favorite.""" - state_ventilation_configuration = self.executor.select_state( + ventilation_configuration = self.executor.select_state( OverkizState.IO_VENTILATION_CONFIGURATION_MODE ) - state_ventilation_mode = self.executor.select_state( + + ventilation_mode = self.executor.select_state( OverkizState.IO_VENTILATION_MODE ) - state_prog = state_ventilation_mode.get(OverkizCommandParam.PROG) + prog = ventilation_mode.get(OverkizCommandParam.PROG) - if state_prog == OverkizCommandParam.PROG: + if prog == OverkizCommandParam.PROG: return PRESET_PROG - if state_ventilation_configuration == OverkizCommandParam.COMFORT: + if ventilation_configuration == OverkizCommandParam.COMFORT: return PRESET_AUTO - if state_ventilation_configuration == OverkizCommandParam.STANDARD: + if ventilation_configuration == OverkizCommandParam.STANDARD: return PRESET_MANUAL return None @@ -137,10 +135,10 @@ async def async_set_preset_mode(self, preset_mode: str) -> None: @property def fan_mode(self) -> Optional[str]: """Return the fan setting.""" - ventilation_mode_state = self.executor.select_state( + ventilation_mode = self.executor.select_state( OverkizState.IO_VENTILATION_MODE ) - cooling = ventilation_mode_state.get(OverkizCommandParam.COOLING) + cooling = ventilation_mode.get(OverkizCommandParam.COOLING) if cooling == OverkizCommandParam.ON: return FAN_BYPASS @@ -178,16 +176,16 @@ async def _set_ventilation_mode( prog=None, ): """Execute ventilation mode command with all parameters.""" - ventilation_mode_state = self.executor.select_state( + ventilation_mode = self.executor.select_state( OverkizState.IO_VENTILATION_MODE ) if cooling: - ventilation_mode_state[OverkizCommandParam.COOLING] = cooling + ventilation_mode[OverkizCommandParam.COOLING] = cooling if prog: - ventilation_mode_state[OverkizCommandParam.PROG] = prog + ventilation_mode[OverkizCommandParam.PROG] = prog await self.executor.async_execute_command( - OverkizCommand.SET_VENTILATION_MODE, ventilation_mode_state + OverkizCommand.SET_VENTILATION_MODE, ventilation_mode ) From f392e216d78394fbe7ad7f8c6377e5d159e6c827 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Tue, 22 Feb 2022 18:09:40 +0100 Subject: [PATCH 20/24] Black fix --- .../atlantic_heat_recovery_ventilation.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index d122217cf..222cafede 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -80,10 +80,8 @@ def preset_mode(self) -> Optional[str]: ventilation_configuration = self.executor.select_state( OverkizState.IO_VENTILATION_CONFIGURATION_MODE ) - - ventilation_mode = self.executor.select_state( - OverkizState.IO_VENTILATION_MODE - ) + + ventilation_mode = self.executor.select_state(OverkizState.IO_VENTILATION_MODE) prog = ventilation_mode.get(OverkizCommandParam.PROG) if prog == OverkizCommandParam.PROG: @@ -135,9 +133,7 @@ async def async_set_preset_mode(self, preset_mode: str) -> None: @property def fan_mode(self) -> Optional[str]: """Return the fan setting.""" - ventilation_mode = self.executor.select_state( - OverkizState.IO_VENTILATION_MODE - ) + ventilation_mode = self.executor.select_state(OverkizState.IO_VENTILATION_MODE) cooling = ventilation_mode.get(OverkizCommandParam.COOLING) if cooling == OverkizCommandParam.ON: @@ -176,9 +172,7 @@ async def _set_ventilation_mode( prog=None, ): """Execute ventilation mode command with all parameters.""" - ventilation_mode = self.executor.select_state( - OverkizState.IO_VENTILATION_MODE - ) + ventilation_mode = self.executor.select_state(OverkizState.IO_VENTILATION_MODE) if cooling: ventilation_mode[OverkizCommandParam.COOLING] = cooling From 6de75b139f60b687633be9b94902f912c2b03dca Mon Sep 17 00:00:00 2001 From: Vincent Le Bourlot Date: Wed, 23 Feb 2022 13:36:19 +0100 Subject: [PATCH 21/24] Update custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py --- .../climate_devices/atlantic_heat_recovery_ventilation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index 222cafede..c6ce541c4 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -84,7 +84,7 @@ def preset_mode(self) -> Optional[str]: ventilation_mode = self.executor.select_state(OverkizState.IO_VENTILATION_MODE) prog = ventilation_mode.get(OverkizCommandParam.PROG) - if prog == OverkizCommandParam.PROG: + if prog == OverkizCommandParam.ON: return PRESET_PROG if ventilation_configuration == OverkizCommandParam.COMFORT: From c2b98a654756de9e1cb9a823c1c8e2f63dc079f8 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Wed, 23 Feb 2022 20:39:20 +0100 Subject: [PATCH 22/24] Bugfix --- .../climate_devices/atlantic_heat_recovery_ventilation.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index c6ce541c4..05f22f7a7 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -72,7 +72,6 @@ def hvac_modes(self) -> List[str]: async def async_set_hvac_mode(self, hvac_mode: str) -> None: """Not implemented since there is only one hvac_mode.""" - pass @property def preset_mode(self) -> Optional[str]: @@ -181,5 +180,5 @@ async def _set_ventilation_mode( ventilation_mode[OverkizCommandParam.PROG] = prog await self.executor.async_execute_command( - OverkizCommand.SET_VENTILATION_MODE, ventilation_mode + OverkizCommand.SET_VENTILATIN_MODE, ventilation_mode ) From afc401f0b458a921e2316a9418853a6bf0c8cd93 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Sat, 2 Apr 2022 15:46:52 +0200 Subject: [PATCH 23/24] Update custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py Co-authored-by: tillstaff --- .../climate_devices/atlantic_heat_recovery_ventilation.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index 05f22f7a7..12023105c 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -153,7 +153,9 @@ async def async_set_fan_mode(self, fan_mode: str) -> None: await self.executor.async_execute_command( OverkizCommand.SET_AIR_DEMAND_MODE, OverkizCommandParam.AUTO ) + await self._set_ventilation_mode(cooling=OverkizCommandParam.ON) else: + await self._set_ventilation_mode(cooling=OverkizCommandParam.OFF) await self.executor.async_execute_command( OverkizCommand.SET_AIR_DEMAND_MODE, FAN_MODES_TO_OVERKIZ[fan_mode] ) @@ -161,9 +163,6 @@ async def async_set_fan_mode(self, fan_mode: str) -> None: await self.executor.async_execute_command( OverkizCommand.REFRESH_VENTILATION_STATE, ) - await self.executor.async_execute_command( - OverkizCommand.REFRESH_VENTILATION_CONFIGURATION_MODE, - ) async def _set_ventilation_mode( self, From eb4621dc6f8ce9a01bf410db7555e6212849be5c Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Sat, 2 Apr 2022 18:25:06 +0200 Subject: [PATCH 24/24] Update atlantic_heat_recovery_ventilation.py --- .../atlantic_heat_recovery_ventilation.py | 81 +++++++++---------- 1 file changed, 36 insertions(+), 45 deletions(-) diff --git a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py index 12023105c..eb25b3f91 100644 --- a/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py +++ b/custom_components/tahoma/climate_devices/atlantic_heat_recovery_ventilation.py @@ -1,5 +1,7 @@ """Support for AtlanticHeatRecoveryVentilation.""" -from typing import List, Optional +from __future__ import annotations + +from typing import cast from pyoverkiz.enums import OverkizCommand, OverkizCommandParam, OverkizState @@ -24,63 +26,58 @@ PRESET_PROG = "prog" PRESET_MANUAL = "manual" -OVERKIZ_TO_FAN_MODES = { +OVERKIZ_TO_FAN_MODES: dict[str, str] = { OverkizCommandParam.AUTO: FAN_AUTO, OverkizCommandParam.AWAY: FAN_AWAY, OverkizCommandParam.BOOST: FAN_BOOST, OverkizCommandParam.HIGH: FAN_KITCHEN, - None: FAN_BYPASS, + "": FAN_BYPASS, } FAN_MODES_TO_OVERKIZ = {v: k for k, v in OVERKIZ_TO_FAN_MODES.items()} -PRESET_MODES = [PRESET_AUTO, PRESET_PROG, PRESET_MANUAL] - class AtlanticHeatRecoveryVentilation(OverkizEntity, ClimateEntity): """Representation of a AtlanticHeatRecoveryVentilation device.""" - def __init__(self, device_url: str, coordinator: OverkizDataUpdateCoordinator): + _attr_fan_modes = [*FAN_MODES_TO_OVERKIZ] + _attr_hvac_modes = [HVAC_MODE_FAN_ONLY] + _attr_preset_modes = [PRESET_AUTO, PRESET_PROG, PRESET_MANUAL] + _attr_temperature_unit = TEMP_CELSIUS + _attr_supported_features = SUPPORT_PRESET_MODE | SUPPORT_FAN_MODE + + def __init__( + self, device_url: str, coordinator: OverkizDataUpdateCoordinator + ) -> None: """Init method.""" super().__init__(device_url, coordinator) self.temperature_device = self.executor.linked_device(4) @property - def current_temperature(self) -> Optional[float]: + def current_temperature(self) -> float | None: """Return the current temperature.""" - return self.temperature_device.states.get(OverkizState.CORE_TEMPERATURE).value - - @property - def temperature_unit(self) -> str: - """Return the unit of measurement used by the platform.""" - return TEMP_CELSIUS + if temperature := self.temperature_device.states[OverkizState.CORE_TEMPERATURE]: + return cast(float, temperature.value) - @property - def supported_features(self) -> int: - """Flag supported features.""" - return SUPPORT_PRESET_MODE | SUPPORT_FAN_MODE + return None @property def hvac_mode(self) -> str: """Return hvac operation ie. heat, cool mode.""" return HVAC_MODE_FAN_ONLY - @property - def hvac_modes(self) -> List[str]: - """Return the list of available hvac operation modes.""" - return [HVAC_MODE_FAN_ONLY] - async def async_set_hvac_mode(self, hvac_mode: str) -> None: """Not implemented since there is only one hvac_mode.""" @property - def preset_mode(self) -> Optional[str]: + def preset_mode(self) -> str | None: """Return the current preset mode, e.g., auto, smart, interval, favorite.""" ventilation_configuration = self.executor.select_state( OverkizState.IO_VENTILATION_CONFIGURATION_MODE ) - - ventilation_mode = self.executor.select_state(OverkizState.IO_VENTILATION_MODE) + ventilation_mode = cast( + dict, self.executor.select_state(OverkizState.IO_VENTILATION_MODE) + ) prog = ventilation_mode.get(OverkizCommandParam.PROG) if prog == OverkizCommandParam.ON: @@ -94,11 +91,6 @@ def preset_mode(self) -> Optional[str]: return None - @property - def preset_modes(self) -> Optional[List[str]]: - """Return a list of available preset modes.""" - return PRESET_MODES - async def async_set_preset_mode(self, preset_mode: str) -> None: """Set the preset mode of the fan.""" if preset_mode == PRESET_AUTO: @@ -130,22 +122,19 @@ async def async_set_preset_mode(self, preset_mode: str) -> None: ) @property - def fan_mode(self) -> Optional[str]: + def fan_mode(self) -> str | None: """Return the fan setting.""" - ventilation_mode = self.executor.select_state(OverkizState.IO_VENTILATION_MODE) + ventilation_mode = cast( + dict, self.executor.select_state(OverkizState.IO_VENTILATION_MODE) + ) cooling = ventilation_mode.get(OverkizCommandParam.COOLING) if cooling == OverkizCommandParam.ON: return FAN_BYPASS - else: - return OVERKIZ_TO_FAN_MODES[ - self.executor.select_state(OverkizState.IO_AIR_DEMAND_MODE) - ] - @property - def fan_modes(self) -> Optional[List[str]]: - """Return the list of available fan modes.""" - return [*FAN_MODES_TO_OVERKIZ] + return OVERKIZ_TO_FAN_MODES[ + cast(str, self.executor.select_state(OverkizState.IO_AIR_DEMAND_MODE)) + ] async def async_set_fan_mode(self, fan_mode: str) -> None: """Set new target fan mode.""" @@ -166,11 +155,13 @@ async def async_set_fan_mode(self, fan_mode: str) -> None: async def _set_ventilation_mode( self, - cooling=None, - prog=None, - ): + cooling: str | None = None, + prog: str | None = None, + ) -> None: """Execute ventilation mode command with all parameters.""" - ventilation_mode = self.executor.select_state(OverkizState.IO_VENTILATION_MODE) + ventilation_mode = cast( + dict, self.executor.select_state(OverkizState.IO_VENTILATION_MODE) + ) if cooling: ventilation_mode[OverkizCommandParam.COOLING] = cooling @@ -179,5 +170,5 @@ async def _set_ventilation_mode( ventilation_mode[OverkizCommandParam.PROG] = prog await self.executor.async_execute_command( - OverkizCommand.SET_VENTILATIN_MODE, ventilation_mode + OverkizCommand.SET_VENTILATION_MODE, ventilation_mode )