From f3ae76bd76863db1289945ab4047cb567f2537bd Mon Sep 17 00:00:00 2001 From: Philipp Date: Wed, 21 Feb 2024 23:29:04 +0100 Subject: [PATCH] new mode and preset map for vrc700 --- custom_components/mypyllant/climate.py | 114 +++++++++++++++---------- tests/test_climate.py | 4 +- 2 files changed, 73 insertions(+), 45 deletions(-) diff --git a/custom_components/mypyllant/climate.py b/custom_components/mypyllant/climate.py index 2b96da2..e7dd3fe 100644 --- a/custom_components/mypyllant/climate.py +++ b/custom_components/mypyllant/climate.py @@ -11,6 +11,7 @@ ClimateEntityFeature, HVACMode, HVACAction, + PRESET_COMFORT, ) from homeassistant.components.climate.const import ( FAN_AUTO, @@ -97,6 +98,13 @@ PRESET_SLEEP: ZoneCurrentSpecialFunction.SYSTEM_OFF, } +ZONE_PRESET_MAP_VRC700 = { + ZoneHeatingOperatingModeVRC700.OFF: PRESET_NONE, + ZoneHeatingOperatingModeVRC700.DAY: PRESET_COMFORT, + ZoneHeatingOperatingModeVRC700.AUTO: PRESET_NONE, + ZoneHeatingOperatingModeVRC700.SET_BACK: PRESET_ECO, +} + ZONE_HVAC_ACTION_MAP = { CircuitState.STANDBY: HVACAction.IDLE, CircuitState.HEATING: HVACAction.HEATING, @@ -285,7 +293,6 @@ class ZoneClimate(CoordinatorEntity, ClimateEntity): coordinator: SystemCoordinator _attr_temperature_unit = UnitOfTemperature.CELSIUS - _attr_preset_modes = [str(k) for k in ZONE_PRESET_MAP.keys()] def __init__( self, @@ -308,8 +315,8 @@ def hvac_mode_map(self): if self.zone.control_identifier.is_vrc700: return { ZoneHeatingOperatingModeVRC700.OFF: HVACMode.OFF, - ZoneHeatingOperatingModeVRC700.DAY: HVACMode.HEAT_COOL, ZoneHeatingOperatingModeVRC700.AUTO: HVACMode.AUTO, + ZoneHeatingOperatingModeVRC700.DAY: HVACMode.AUTO, ZoneHeatingOperatingModeVRC700.SET_BACK: HVACMode.AUTO, } else: @@ -547,15 +554,25 @@ async def async_set_temperature(self, **kwargs: Any) -> None: await self.set_quick_veto(temperature=temperature) await self.coordinator.async_request_refresh_delayed() + @property + def preset_modes(self) -> list[str]: + if self.zone.control_identifier.is_vrc700: + return [k for k in ZONE_PRESET_MAP_VRC700.values()] + else: + return [k for k in ZONE_PRESET_MAP.keys()] + @property def preset_mode(self) -> str: - if self.zone.is_eco_mode: - return PRESET_ECO - return [ - k - for k, v in ZONE_PRESET_MAP.items() - if v == self.zone.current_special_function - ][0] + if self.zone.control_identifier.is_vrc700: + return ZONE_PRESET_MAP_VRC700[self.zone.heating.operation_mode_heating] # type: ignore + else: + if self.zone.is_eco_mode: + return PRESET_ECO + return [ + k + for k, v in ZONE_PRESET_MAP.items() + if v == self.zone.current_special_function + ][0] async def async_set_preset_mode(self, preset_mode): """ @@ -564,43 +581,54 @@ async def async_set_preset_mode(self, preset_mode): Parameters: preset_mode (str): The new preset mode to set """ - if preset_mode not in ZONE_PRESET_MAP: - raise ValueError( - f'Invalid preset mode, use one of {", ".join(ZONE_PRESET_MAP.keys())}' - ) - requested_mode = ZONE_PRESET_MAP[preset_mode] - if requested_mode != self.zone.current_special_function: - if requested_mode == ZoneCurrentSpecialFunction.NONE: - if ( - self.zone.current_special_function - == ZoneCurrentSpecialFunction.QUICK_VETO - ): - # If quick veto is set, we cancel that - await self.coordinator.api.cancel_quick_veto_zone_temperature( - self.zone - ) - elif ( - self.zone.current_special_function - == ZoneCurrentSpecialFunction.HOLIDAY - ): - # If holiday mode is set, we cancel that instead - await self.cancel_holiday() - if requested_mode == ZoneCurrentSpecialFunction.QUICK_VETO: - await self.coordinator.api.quick_veto_zone_temperature( - self.zone, - self.zone.heating.manual_mode_setpoint_heating, - default_duration=self.default_quick_veto_duration, + if self.zone.control_identifier.is_vrc700: + try: + requested_mode = [ + k for k, v in ZONE_PRESET_MAP_VRC700.items() if v == preset_mode + ][0] + await self.set_zone_operating_mode(requested_mode) + except IndexError: + raise ValueError( + f'Invalid preset mode, use one of {", ".join(set(ZONE_PRESET_MAP_VRC700.values()))}' + ) + else: + if preset_mode not in ZONE_PRESET_MAP: + raise ValueError( + f'Invalid preset mode, use one of {", ".join(ZONE_PRESET_MAP.keys())}' ) - if requested_mode == ZoneCurrentSpecialFunction.HOLIDAY: - await self.set_holiday() + requested_mode = ZONE_PRESET_MAP[preset_mode] + if requested_mode != self.zone.current_special_function: + if requested_mode == ZoneCurrentSpecialFunction.NONE: + if ( + self.zone.current_special_function + == ZoneCurrentSpecialFunction.QUICK_VETO + ): + # If quick veto is set, we cancel that + await self.coordinator.api.cancel_quick_veto_zone_temperature( + self.zone + ) + elif ( + self.zone.current_special_function + == ZoneCurrentSpecialFunction.HOLIDAY + ): + # If holiday mode is set, we cancel that instead + await self.cancel_holiday() + if requested_mode == ZoneCurrentSpecialFunction.QUICK_VETO: + await self.coordinator.api.quick_veto_zone_temperature( + self.zone, + self.zone.heating.manual_mode_setpoint_heating, + default_duration=self.default_quick_veto_duration, + ) + if requested_mode == ZoneCurrentSpecialFunction.HOLIDAY: + await self.set_holiday() - if requested_mode == ZoneCurrentSpecialFunction.SYSTEM_OFF: - # SYSTEM_OFF is a valid special function, but since there's no API endpoint we - # just turn off the system though the zone heating mode API. - # See https://github.com/signalkraft/mypyllant-component/issues/27#issuecomment-1746568372 - await self.async_set_hvac_mode(HVACMode.OFF) + if requested_mode == ZoneCurrentSpecialFunction.SYSTEM_OFF: + # SYSTEM_OFF is a valid special function, but since there's no API endpoint we + # just turn off the system though the zone heating mode API. + # See https://github.com/signalkraft/mypyllant-component/issues/27#issuecomment-1746568372 + await self.async_set_hvac_mode(HVACMode.OFF) - await self.coordinator.async_request_refresh_delayed() + await self.coordinator.async_request_refresh_delayed() class VentilationClimate(CoordinatorEntity, ClimateEntity): diff --git a/tests/test_climate.py b/tests/test_climate.py index 2db1bb0..1706c9f 100644 --- a/tests/test_climate.py +++ b/tests/test_climate.py @@ -2,7 +2,7 @@ import pytest as pytest from homeassistant.components.climate import HVACMode -from homeassistant.components.climate.const import FAN_OFF, PRESET_AWAY +from homeassistant.components.climate.const import FAN_OFF, PRESET_ECO from homeassistant.const import ATTR_TEMPERATURE from homeassistant.helpers.entity_registry import DATA_REGISTRY, EntityRegistry from homeassistant.loader import DATA_COMPONENTS, DATA_INTEGRATIONS @@ -85,7 +85,7 @@ async def test_zone_climate( await climate.async_set_hvac_mode(HVACMode.AUTO) await climate.async_set_temperature(**{ATTR_TEMPERATURE: 20}) # TODO: Test logic of different calls depending on current new preset mode - await climate.async_set_preset_mode(preset_mode=PRESET_AWAY) + await climate.async_set_preset_mode(preset_mode=PRESET_ECO) system_coordinator_mock._debounced_refresh.async_cancel() print(system_coordinator_mock.data[0].state["zones"])