From 829d3bf62164d9a00b52ffba1301299b0bd03bd7 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Fri, 17 Jan 2025 17:13:25 +0100 Subject: [PATCH] Add support for EvoHomeController in Overkiz (#133777) --- .../components/overkiz/climate/__init__.py | 2 + .../overkiz/climate/evo_home_controller.py | 101 ++++++++++++++++++ homeassistant/components/overkiz/const.py | 1 + 3 files changed, 104 insertions(+) create mode 100644 homeassistant/components/overkiz/climate/evo_home_controller.py diff --git a/homeassistant/components/overkiz/climate/__init__.py b/homeassistant/components/overkiz/climate/__init__.py index 1398bb7c25a..3276a1979cc 100644 --- a/homeassistant/components/overkiz/climate/__init__.py +++ b/homeassistant/components/overkiz/climate/__init__.py @@ -25,6 +25,7 @@ from .atlantic_pass_apc_heat_pump_main_component import ( from .atlantic_pass_apc_heating_zone import AtlanticPassAPCHeatingZone from .atlantic_pass_apc_zone_control import AtlanticPassAPCZoneControl from .atlantic_pass_apc_zone_control_zone import AtlanticPassAPCZoneControlZone +from .evo_home_controller import EvoHomeController from .hitachi_air_to_air_heat_pump_hlrrwifi import HitachiAirToAirHeatPumpHLRRWIFI from .hitachi_air_to_air_heat_pump_ovp import HitachiAirToAirHeatPumpOVP from .hitachi_air_to_water_heating_zone import HitachiAirToWaterHeatingZone @@ -53,6 +54,7 @@ WIDGET_TO_CLIMATE_ENTITY = { UIWidget.ATLANTIC_PASS_APC_HEATING_ZONE: AtlanticPassAPCHeatingZone, UIWidget.ATLANTIC_PASS_APC_ZONE_CONTROL: AtlanticPassAPCZoneControl, UIWidget.HITACHI_AIR_TO_WATER_HEATING_ZONE: HitachiAirToWaterHeatingZone, + UIWidget.EVO_HOME_CONTROLLER: EvoHomeController, UIWidget.SOMFY_HEATING_TEMPERATURE_INTERFACE: SomfyHeatingTemperatureInterface, UIWidget.SOMFY_THERMOSTAT: SomfyThermostat, UIWidget.VALVE_HEATING_TEMPERATURE_INTERFACE: ValveHeatingTemperatureInterface, diff --git a/homeassistant/components/overkiz/climate/evo_home_controller.py b/homeassistant/components/overkiz/climate/evo_home_controller.py new file mode 100644 index 00000000000..272acbb13b9 --- /dev/null +++ b/homeassistant/components/overkiz/climate/evo_home_controller.py @@ -0,0 +1,101 @@ +"""Support for EvoHomeController.""" + +from datetime import timedelta + +from pyoverkiz.enums import OverkizCommand, OverkizCommandParam, OverkizState + +from homeassistant.components.climate import ( + PRESET_NONE, + ClimateEntity, + ClimateEntityFeature, + HVACMode, +) +from homeassistant.const import UnitOfTemperature +import homeassistant.util.dt as dt_util + +from ..entity import OverkizDataUpdateCoordinator, OverkizEntity + +PRESET_DAY_OFF = "day-off" +PRESET_HOLIDAYS = "holidays" + +OVERKIZ_TO_HVAC_MODES: dict[str, HVACMode] = { + OverkizCommandParam.AUTO: HVACMode.AUTO, + OverkizCommandParam.OFF: HVACMode.OFF, +} +HVAC_MODES_TO_OVERKIZ = {v: k for k, v in OVERKIZ_TO_HVAC_MODES.items()} + +OVERKIZ_TO_PRESET_MODES: dict[str, str] = { + OverkizCommandParam.DAY_OFF: PRESET_DAY_OFF, + OverkizCommandParam.HOLIDAYS: PRESET_HOLIDAYS, +} +PRESET_MODES_TO_OVERKIZ = {v: k for k, v in OVERKIZ_TO_PRESET_MODES.items()} + + +class EvoHomeController(OverkizEntity, ClimateEntity): + """Representation of EvoHomeController device.""" + + _attr_hvac_modes = [*HVAC_MODES_TO_OVERKIZ] + _attr_preset_modes = [*PRESET_MODES_TO_OVERKIZ] + _attr_supported_features = ( + ClimateEntityFeature.PRESET_MODE | ClimateEntityFeature.TURN_OFF + ) + _attr_temperature_unit = UnitOfTemperature.CELSIUS + + def __init__( + self, device_url: str, coordinator: OverkizDataUpdateCoordinator + ) -> None: + """Init method.""" + super().__init__(device_url, coordinator) + + if self._attr_device_info: + self._attr_device_info["manufacturer"] = "EvoHome" + + @property + def hvac_mode(self) -> HVACMode: + """Return hvac operation ie. heat, cool mode.""" + if state := self.device.states.get(OverkizState.RAMSES_RAMSES_OPERATING_MODE): + operating_mode = state.value_as_str + + if operating_mode in OVERKIZ_TO_HVAC_MODES: + return OVERKIZ_TO_HVAC_MODES[operating_mode] + + if operating_mode in OVERKIZ_TO_PRESET_MODES: + return HVACMode.OFF + + return HVACMode.OFF + + async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: + """Set new target hvac mode.""" + await self.executor.async_execute_command( + OverkizCommand.SET_OPERATING_MODE, HVAC_MODES_TO_OVERKIZ[hvac_mode] + ) + + @property + def preset_mode(self) -> str | None: + """Return the current preset mode, e.g., home, away, temp.""" + if ( + state := self.device.states[OverkizState.RAMSES_RAMSES_OPERATING_MODE] + ) and state.value_as_str in OVERKIZ_TO_PRESET_MODES: + return OVERKIZ_TO_PRESET_MODES[state.value_as_str] + + return PRESET_NONE + + async def async_set_preset_mode(self, preset_mode: str) -> None: + """Set new preset mode.""" + if preset_mode == PRESET_DAY_OFF: + today_end_of_day = dt_util.now().replace( + hour=0, minute=0, second=0, microsecond=0 + ) + timedelta(days=1) + time_interval = today_end_of_day + + if preset_mode == PRESET_HOLIDAYS: + one_week_from_now = dt_util.now().replace( + hour=0, minute=0, second=0, microsecond=0 + ) + timedelta(days=7) + time_interval = one_week_from_now + + await self.executor.async_execute_command( + OverkizCommand.SET_OPERATING_MODE, + PRESET_MODES_TO_OVERKIZ[preset_mode], + time_interval.strftime("%Y/%m/%d %H:%M"), + ) diff --git a/homeassistant/components/overkiz/const.py b/homeassistant/components/overkiz/const.py index 41b567500a9..7f5f4ad85bd 100644 --- a/homeassistant/components/overkiz/const.py +++ b/homeassistant/components/overkiz/const.py @@ -102,6 +102,7 @@ OVERKIZ_DEVICE_TO_PLATFORM: dict[UIClass | UIWidget, Platform | None] = { UIWidget.ATLANTIC_PASS_APC_ZONE_CONTROL: Platform.CLIMATE, # widgetName, uiClass is HeatingSystem (not supported) UIWidget.DOMESTIC_HOT_WATER_PRODUCTION: Platform.WATER_HEATER, # widgetName, uiClass is WaterHeatingSystem (not supported) UIWidget.DOMESTIC_HOT_WATER_TANK: Platform.SWITCH, # widgetName, uiClass is WaterHeatingSystem (not supported) + UIWidget.EVO_HOME_CONTROLLER: Platform.CLIMATE, # widgetName, uiClass is EvoHome (not supported) UIWidget.HITACHI_AIR_TO_AIR_HEAT_PUMP: Platform.CLIMATE, # widgetName, uiClass is HeatingSystem (not supported) UIWidget.HITACHI_AIR_TO_WATER_HEATING_ZONE: Platform.CLIMATE, # widgetName, uiClass is HeatingSystem (not supported) UIWidget.HITACHI_DHW: Platform.WATER_HEATER, # widgetName, uiClass is HitachiHeatingSystem (not supported)