"""Viessmann ViCare water_heater device.""" from __future__ import annotations from contextlib import suppress import logging from typing import Any from PyViCare.PyViCareDevice import Device as PyViCareDevice from PyViCare.PyViCareDeviceConfig import PyViCareDeviceConfig from PyViCare.PyViCareHeatingDevice import HeatingCircuit as PyViCareHeatingCircuit from PyViCare.PyViCareUtils import ( PyViCareInvalidDataError, PyViCareNotSupportedFeatureError, PyViCareRateLimitError, ) import requests from homeassistant.components.water_heater import ( WaterHeaterEntity, WaterHeaterEntityFeature, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_TEMPERATURE, PRECISION_TENTHS, UnitOfTemperature from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import DOMAIN, VICARE_API, VICARE_DEVICE_CONFIG from .entity import ViCareEntity from .utils import get_circuits _LOGGER = logging.getLogger(__name__) VICARE_MODE_DHW = "dhw" VICARE_MODE_HEATING = "heating" VICARE_MODE_DHWANDHEATING = "dhwAndHeating" VICARE_MODE_DHWANDHEATINGCOOLING = "dhwAndHeatingCooling" VICARE_MODE_FORCEDREDUCED = "forcedReduced" VICARE_MODE_FORCEDNORMAL = "forcedNormal" VICARE_MODE_OFF = "standby" VICARE_TEMP_WATER_MIN = 10 VICARE_TEMP_WATER_MAX = 60 OPERATION_MODE_ON = "on" OPERATION_MODE_OFF = "off" VICARE_TO_HA_HVAC_DHW = { VICARE_MODE_DHW: OPERATION_MODE_ON, VICARE_MODE_DHWANDHEATING: OPERATION_MODE_ON, VICARE_MODE_DHWANDHEATINGCOOLING: OPERATION_MODE_ON, VICARE_MODE_HEATING: OPERATION_MODE_OFF, VICARE_MODE_FORCEDREDUCED: OPERATION_MODE_OFF, VICARE_MODE_FORCEDNORMAL: OPERATION_MODE_ON, VICARE_MODE_OFF: OPERATION_MODE_OFF, } HA_TO_VICARE_HVAC_DHW = { OPERATION_MODE_OFF: VICARE_MODE_OFF, OPERATION_MODE_ON: VICARE_MODE_DHW, } def _build_entities( api: PyViCareDevice, device_config: PyViCareDeviceConfig, ) -> list[ViCareWater]: """Create ViCare domestic hot water entities for a device.""" return [ ViCareWater( api, circuit, device_config, "domestic_hot_water", ) for circuit in get_circuits(api) ] async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up the ViCare water heater platform.""" api = hass.data[DOMAIN][config_entry.entry_id][VICARE_API] device_config = hass.data[DOMAIN][config_entry.entry_id][VICARE_DEVICE_CONFIG] async_add_entities( await hass.async_add_executor_job( _build_entities, api, device_config, ) ) class ViCareWater(ViCareEntity, WaterHeaterEntity): """Representation of the ViCare domestic hot water device.""" _attr_precision = PRECISION_TENTHS _attr_supported_features = WaterHeaterEntityFeature.TARGET_TEMPERATURE _attr_temperature_unit = UnitOfTemperature.CELSIUS _attr_min_temp = VICARE_TEMP_WATER_MIN _attr_max_temp = VICARE_TEMP_WATER_MAX _attr_operation_list = list(HA_TO_VICARE_HVAC_DHW) def __init__( self, api: PyViCareDevice, circuit: PyViCareHeatingCircuit, device_config: PyViCareDeviceConfig, translation_key: str, ) -> None: """Initialize the DHW water_heater device.""" super().__init__(device_config, api, circuit.id) self._circuit = circuit self._attributes: dict[str, Any] = {} self._current_mode = None self._attr_translation_key = translation_key def update(self) -> None: """Let HA know there has been an update from the ViCare API.""" try: with suppress(PyViCareNotSupportedFeatureError): self._attr_current_temperature = ( self._api.getDomesticHotWaterStorageTemperature() ) with suppress(PyViCareNotSupportedFeatureError): self._attr_target_temperature = ( self._api.getDomesticHotWaterDesiredTemperature() ) with suppress(PyViCareNotSupportedFeatureError): self._current_mode = self._circuit.getActiveMode() except requests.exceptions.ConnectionError: _LOGGER.error("Unable to retrieve data from ViCare server") except PyViCareRateLimitError as limit_exception: _LOGGER.error("Vicare API rate limit exceeded: %s", limit_exception) except ValueError: _LOGGER.error("Unable to decode data from ViCare server") except PyViCareInvalidDataError as invalid_data_exception: _LOGGER.error("Invalid data from Vicare server: %s", invalid_data_exception) def set_temperature(self, **kwargs: Any) -> None: """Set new target temperatures.""" if (temp := kwargs.get(ATTR_TEMPERATURE)) is not None: self._api.setDomesticHotWaterTemperature(temp) self._attr_target_temperature = temp @property def current_operation(self): """Return current operation ie. heat, cool, idle.""" return VICARE_TO_HA_HVAC_DHW.get(self._current_mode)