Skip to content

Commit

Permalink
Add ability to change heating programs for heat pumps in ViCare integ…
Browse files Browse the repository at this point in the history
…ration (home-assistant#110924)

* heating programs

* fix heating program

* fix heating program

* remove commented code

* simplify

* Update types.py

* update vicare_programs in init
  • Loading branch information
CFenner authored May 14, 2024
1 parent 83f5133 commit eca67eb
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 27 deletions.
48 changes: 21 additions & 27 deletions homeassistant/components/vicare/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@
import voluptuous as vol

from homeassistant.components.climate import (
PRESET_COMFORT,
PRESET_ECO,
PRESET_HOME,
PRESET_SLEEP,
ClimateEntity,
ClimateEntityFeature,
HVACAction,
Expand Down Expand Up @@ -78,14 +74,11 @@
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(
Expand Down Expand Up @@ -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
Expand All @@ -162,6 +154,13 @@ def __init__(
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:
Expand Down Expand Up @@ -293,11 +292,13 @@ def set_temperature(self, **kwargs: Any) -> None:
@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,
Expand All @@ -308,12 +309,10 @@ def set_preset_mode(self, preset_mode: str) -> None:
)

_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)
Expand All @@ -327,12 +326,7 @@ def set_preset_mode(self, preset_mode: str) -> None:
) 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)
Expand Down
39 changes: 39 additions & 0 deletions homeassistant/components/vicare/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@
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.
Expand All @@ -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:
Expand Down

0 comments on commit eca67eb

Please sign in to comment.