146 lines
4.7 KiB
Python
146 lines
4.7 KiB
Python
"""Support for WaterHeater entities of the Evohome integration."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
import evohomeasync2 as evo
|
|
from evohomeasync2.const import SZ_STATE_STATUS, SZ_TEMPERATURE_STATUS
|
|
from evohomeasync2.schemas.const import DhwState as EvoDhwState, ZoneMode as EvoZoneMode
|
|
|
|
from homeassistant.components.water_heater import (
|
|
WaterHeaterEntity,
|
|
WaterHeaterEntityFeature,
|
|
)
|
|
from homeassistant.const import (
|
|
PRECISION_TENTHS,
|
|
PRECISION_WHOLE,
|
|
STATE_OFF,
|
|
STATE_ON,
|
|
UnitOfTemperature,
|
|
)
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
|
from homeassistant.util import dt as dt_util
|
|
|
|
from . import EVOHOME_KEY
|
|
from .coordinator import EvoDataUpdateCoordinator
|
|
from .entity import EvoChild
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
STATE_AUTO = "auto"
|
|
|
|
HA_STATE_TO_EVO = {STATE_AUTO: "", STATE_ON: EvoDhwState.ON, STATE_OFF: EvoDhwState.OFF}
|
|
EVO_STATE_TO_HA = {v: k for k, v in HA_STATE_TO_EVO.items() if k != ""}
|
|
|
|
|
|
async def async_setup_platform(
|
|
hass: HomeAssistant,
|
|
config: ConfigType,
|
|
async_add_entities: AddEntitiesCallback,
|
|
discovery_info: DiscoveryInfoType | None = None,
|
|
) -> None:
|
|
"""Create a DHW controller."""
|
|
if discovery_info is None:
|
|
return
|
|
|
|
coordinator = hass.data[EVOHOME_KEY].coordinator
|
|
tcs = hass.data[EVOHOME_KEY].tcs
|
|
|
|
assert tcs.hotwater is not None # mypy check
|
|
|
|
_LOGGER.debug(
|
|
"Adding: DhwController (%s), id=%s",
|
|
tcs.hotwater.type,
|
|
tcs.hotwater.id,
|
|
)
|
|
|
|
entity = EvoDHW(coordinator, tcs.hotwater)
|
|
|
|
async_add_entities([entity])
|
|
|
|
await entity.update_attrs()
|
|
|
|
|
|
class EvoDHW(EvoChild, WaterHeaterEntity):
|
|
"""Base for any evohome-compatible DHW controller."""
|
|
|
|
_attr_name = "DHW controller"
|
|
_attr_icon = "mdi:thermometer-lines"
|
|
_attr_operation_list = list(HA_STATE_TO_EVO)
|
|
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
|
|
|
_evo_device: evo.HotWater
|
|
_evo_id_attr = "dhw_id"
|
|
_evo_state_attr_names = (SZ_STATE_STATUS, SZ_TEMPERATURE_STATUS)
|
|
|
|
def __init__(
|
|
self, coordinator: EvoDataUpdateCoordinator, evo_device: evo.HotWater
|
|
) -> None:
|
|
"""Initialize an evohome-compatible DHW controller."""
|
|
|
|
super().__init__(coordinator, evo_device)
|
|
self._evo_id = evo_device.id
|
|
|
|
self._attr_unique_id = evo_device.id
|
|
self._attr_name = evo_device.name # is static
|
|
|
|
self._attr_precision = (
|
|
PRECISION_TENTHS if coordinator.client_v1 else PRECISION_WHOLE
|
|
)
|
|
self._attr_supported_features = (
|
|
WaterHeaterEntityFeature.AWAY_MODE | WaterHeaterEntityFeature.OPERATION_MODE
|
|
)
|
|
|
|
@property
|
|
def current_operation(self) -> str | None:
|
|
"""Return the current operating mode (Auto, On, or Off)."""
|
|
if self._evo_device.mode == EvoZoneMode.FOLLOW_SCHEDULE:
|
|
return STATE_AUTO
|
|
return EVO_STATE_TO_HA[self._evo_device.state]
|
|
|
|
@property
|
|
def is_away_mode_on(self) -> bool | None:
|
|
"""Return True if away mode is on."""
|
|
is_off = EVO_STATE_TO_HA[self._evo_device.state] == STATE_OFF
|
|
is_permanent = self._evo_device.mode == EvoZoneMode.PERMANENT_OVERRIDE
|
|
return is_off and is_permanent
|
|
|
|
async def async_set_operation_mode(self, operation_mode: str) -> None:
|
|
"""Set new operation mode for a DHW controller.
|
|
|
|
Except for Auto, the mode is only until the next SetPoint.
|
|
"""
|
|
if operation_mode == STATE_AUTO:
|
|
await self.coordinator.call_client_api(self._evo_device.reset())
|
|
else:
|
|
await self._update_schedule()
|
|
until = self.setpoints.get("next_sp_from")
|
|
until = dt_util.as_utc(until) if until else None
|
|
|
|
if operation_mode == STATE_ON:
|
|
await self.coordinator.call_client_api(self._evo_device.on(until=until))
|
|
else: # STATE_OFF
|
|
await self.coordinator.call_client_api(
|
|
self._evo_device.off(until=until)
|
|
)
|
|
|
|
async def async_turn_away_mode_on(self) -> None:
|
|
"""Turn away mode on."""
|
|
await self.coordinator.call_client_api(self._evo_device.off())
|
|
|
|
async def async_turn_away_mode_off(self) -> None:
|
|
"""Turn away mode off."""
|
|
await self.coordinator.call_client_api(self._evo_device.reset())
|
|
|
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
|
"""Turn on."""
|
|
await self.coordinator.call_client_api(self._evo_device.on())
|
|
|
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
|
"""Turn off."""
|
|
await self.coordinator.call_client_api(self._evo_device.off())
|