diff --git a/homeassistant/components/vicare/climate.py b/homeassistant/components/vicare/climate.py index 490048190fa..1333327609d 100644 --- a/homeassistant/components/vicare/climate.py +++ b/homeassistant/components/vicare/climate.py @@ -19,10 +19,6 @@ import requests import voluptuous as vol from homeassistant.components.climate import ( - PRESET_COMFORT, - PRESET_ECO, - PRESET_HOME, - PRESET_SLEEP, ClimateEntity, ClimateEntityFeature, HVACAction, @@ -78,14 +74,11 @@ VICARE_TO_HA_HVAC_HEATING: dict[str, HVACMode] = { VICARE_MODE_FORCEDNORMAL: HVACMode.HEAT, } -VICARE_TO_HA_PRESET_HEATING = { - HeatingProgram.COMFORT: PRESET_COMFORT, - HeatingProgram.ECO: PRESET_ECO, - HeatingProgram.NORMAL: PRESET_HOME, - HeatingProgram.REDUCED: PRESET_SLEEP, -} - -HA_TO_VICARE_PRESET_HEATING = {v: k for k, v in VICARE_TO_HA_PRESET_HEATING.items()} +CHANGABLE_HEATING_PROGRAMS = [ + HeatingProgram.COMFORT, + HeatingProgram.COMFORT_HEATING, + HeatingProgram.ECO, +] def _build_entities( @@ -143,7 +136,6 @@ class ViCareClimate(ViCareEntity, ClimateEntity): _attr_min_temp = VICARE_TEMP_HEATING_MIN _attr_max_temp = VICARE_TEMP_HEATING_MAX _attr_target_temperature_step = PRECISION_WHOLE - _attr_preset_modes = list(HA_TO_VICARE_PRESET_HEATING) _current_action: bool | None = None _current_mode: str | None = None _enable_turn_on_off_backwards_compatibility = False @@ -162,6 +154,13 @@ class ViCareClimate(ViCareEntity, ClimateEntity): self._current_program = None self._attr_translation_key = translation_key + self._attributes["vicare_programs"] = self._circuit.getPrograms() + self._attr_preset_modes = [ + preset + for heating_program in self._attributes["vicare_programs"] + if (preset := HeatingProgram.to_ha_preset(heating_program)) is not None + ] + def update(self) -> None: """Let HA know there has been an update from the ViCare API.""" try: @@ -293,11 +292,13 @@ class ViCareClimate(ViCareEntity, ClimateEntity): @property def preset_mode(self): """Return the current preset mode, e.g., home, away, temp.""" - return VICARE_TO_HA_PRESET_HEATING.get(self._current_program) + return HeatingProgram.to_ha_preset(self._current_program) def set_preset_mode(self, preset_mode: str) -> None: """Set new preset mode and deactivate any existing programs.""" - target_program = HA_TO_VICARE_PRESET_HEATING.get(preset_mode) + target_program = HeatingProgram.from_ha_preset( + preset_mode, self._attributes["vicare_programs"] + ) if target_program is None: raise ServiceValidationError( translation_domain=DOMAIN, @@ -308,12 +309,10 @@ class ViCareClimate(ViCareEntity, ClimateEntity): ) _LOGGER.debug("Current preset %s", self._current_program) - if self._current_program and self._current_program not in [ - HeatingProgram.NORMAL, - HeatingProgram.REDUCED, - HeatingProgram.STANDBY, - ]: - # We can't deactivate "normal", "reduced" or "standby" + if ( + self._current_program + and self._current_program in CHANGABLE_HEATING_PROGRAMS + ): _LOGGER.debug("deactivating %s", self._current_program) try: self._circuit.deactivateProgram(self._current_program) @@ -327,12 +326,7 @@ class ViCareClimate(ViCareEntity, ClimateEntity): ) from err _LOGGER.debug("Setting preset to %s / %s", preset_mode, target_program) - if target_program not in [ - HeatingProgram.NORMAL, - HeatingProgram.REDUCED, - HeatingProgram.STANDBY, - ]: - # And we can't explicitly activate "normal", "reduced" or "standby", either + if target_program in CHANGABLE_HEATING_PROGRAMS: _LOGGER.debug("activating %s", target_program) try: self._circuit.activateProgram(target_program) diff --git a/homeassistant/components/vicare/types.py b/homeassistant/components/vicare/types.py index 2bed638bfb9..7e1ec7f8bee 100644 --- a/homeassistant/components/vicare/types.py +++ b/homeassistant/components/vicare/types.py @@ -8,6 +8,13 @@ from typing import Any from PyViCare.PyViCareDevice import Device as PyViCareDevice from PyViCare.PyViCareDeviceConfig import PyViCareDeviceConfig +from homeassistant.components.climate import ( + PRESET_COMFORT, + PRESET_ECO, + PRESET_HOME, + PRESET_SLEEP, +) + class HeatingProgram(enum.StrEnum): """ViCare preset heating programs. @@ -24,6 +31,38 @@ class HeatingProgram(enum.StrEnum): REDUCED_HEATING = "reducedHeating" STANDBY = "standby" + @staticmethod + def to_ha_preset(program: str) -> str | None: + """Return the mapped Home Assistant preset for the ViCare heating program.""" + + try: + heating_program = HeatingProgram(program) + except ValueError: + # ignore unsupported / unmapped programs + return None + return VICARE_TO_HA_PRESET_HEATING.get(heating_program) if program else None + + @staticmethod + def from_ha_preset( + ha_preset: str, supported_heating_programs: list[str] + ) -> str | None: + """Return the mapped ViCare heating program for the Home Assistant preset.""" + for program in supported_heating_programs: + if VICARE_TO_HA_PRESET_HEATING.get(HeatingProgram(program)) == ha_preset: + return program + return None + + +VICARE_TO_HA_PRESET_HEATING = { + HeatingProgram.COMFORT: PRESET_COMFORT, + HeatingProgram.COMFORT_HEATING: PRESET_COMFORT, + HeatingProgram.ECO: PRESET_ECO, + HeatingProgram.NORMAL: PRESET_HOME, + HeatingProgram.NORMAL_HEATING: PRESET_HOME, + HeatingProgram.REDUCED: PRESET_SLEEP, + HeatingProgram.REDUCED_HEATING: PRESET_SLEEP, +} + @dataclass(frozen=True) class ViCareDevice: