Home Assistant Unofficial Reference 2024.12.1
water_heater.py
Go to the documentation of this file.
1 """Support for WaterHeater entities of the Evohome integration."""
2 
3 from __future__ import annotations
4 
5 import logging
6 from typing import TYPE_CHECKING, Any
7 
8 import evohomeasync2 as evo
9 from evohomeasync2.schema.const import (
10  SZ_ACTIVE_FAULTS,
11  SZ_DHW_ID,
12  SZ_OFF,
13  SZ_ON,
14  SZ_STATE_STATUS,
15  SZ_TEMPERATURE_STATUS,
16 )
17 
19  WaterHeaterEntity,
20  WaterHeaterEntityFeature,
21 )
22 from homeassistant.const import (
23  PRECISION_TENTHS,
24  PRECISION_WHOLE,
25  STATE_OFF,
26  STATE_ON,
27  UnitOfTemperature,
28 )
29 from homeassistant.core import HomeAssistant
30 from homeassistant.helpers.entity_platform import AddEntitiesCallback
31 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
32 import homeassistant.util.dt as dt_util
33 
34 from .const import DOMAIN, EVO_FOLLOW, EVO_PERMOVER
35 from .entity import EvoChild
36 
37 if TYPE_CHECKING:
38  from . import EvoBroker
39 
40 
41 _LOGGER = logging.getLogger(__name__)
42 
43 STATE_AUTO = "auto"
44 
45 HA_STATE_TO_EVO = {STATE_AUTO: "", STATE_ON: SZ_ON, STATE_OFF: SZ_OFF}
46 EVO_STATE_TO_HA = {v: k for k, v in HA_STATE_TO_EVO.items() if k != ""}
47 
48 STATE_ATTRS_DHW = [SZ_DHW_ID, SZ_ACTIVE_FAULTS, SZ_STATE_STATUS, SZ_TEMPERATURE_STATUS]
49 
50 
52  hass: HomeAssistant,
53  config: ConfigType,
54  async_add_entities: AddEntitiesCallback,
55  discovery_info: DiscoveryInfoType | None = None,
56 ) -> None:
57  """Create a DHW controller."""
58  if discovery_info is None:
59  return
60 
61  broker: EvoBroker = hass.data[DOMAIN]["broker"]
62 
63  assert broker.tcs.hotwater is not None # mypy check
64 
65  _LOGGER.debug(
66  "Adding: DhwController (%s), id=%s",
67  broker.tcs.hotwater.TYPE,
68  broker.tcs.hotwater.dhwId,
69  )
70 
71  new_entity = EvoDHW(broker, broker.tcs.hotwater)
72 
73  async_add_entities([new_entity], update_before_add=True)
74 
75 
77  """Base for any evohome-compatible DHW controller."""
78 
79  _attr_name = "DHW controller"
80  _attr_icon = "mdi:thermometer-lines"
81  _attr_operation_list = list(HA_STATE_TO_EVO)
82  _attr_temperature_unit = UnitOfTemperature.CELSIUS
83 
84  _evo_device: evo.HotWater # mypy hint
85 
86  def __init__(self, evo_broker: EvoBroker, evo_device: evo.HotWater) -> None:
87  """Initialize an evohome-compatible DHW controller."""
88 
89  super().__init__(evo_broker, evo_device)
90  self._evo_id_evo_id = evo_device.dhwId
91 
92  self._attr_unique_id_attr_unique_id = evo_device.dhwId
93  self._attr_name_attr_name_attr_name = evo_device.name # is static
94 
95  self._attr_precision_attr_precision = (
96  PRECISION_TENTHS if evo_broker.client_v1 else PRECISION_WHOLE
97  )
98  self._attr_supported_features_attr_supported_features = (
99  WaterHeaterEntityFeature.AWAY_MODE | WaterHeaterEntityFeature.OPERATION_MODE
100  )
101 
102  @property
103  def current_operation(self) -> str | None:
104  """Return the current operating mode (Auto, On, or Off)."""
105  if self._evo_device_evo_device.mode == EVO_FOLLOW:
106  return STATE_AUTO
107  if (device_state := self._evo_device_evo_device.state) is None:
108  return None
109  return EVO_STATE_TO_HA[device_state]
110 
111  @property
112  def is_away_mode_on(self) -> bool | None:
113  """Return True if away mode is on."""
114  if self._evo_device_evo_device.state is None:
115  return None
116  is_off = EVO_STATE_TO_HA[self._evo_device_evo_device.state] == STATE_OFF
117  is_permanent = self._evo_device_evo_device.mode == EVO_PERMOVER
118  return is_off and is_permanent
119 
120  async def async_set_operation_mode(self, operation_mode: str) -> None:
121  """Set new operation mode for a DHW controller.
122 
123  Except for Auto, the mode is only until the next SetPoint.
124  """
125  if operation_mode == STATE_AUTO:
126  await self._evo_broker_evo_broker.call_client_api(self._evo_device_evo_device.reset_mode())
127  else:
128  await self._update_schedule_update_schedule()
129  until = dt_util.parse_datetime(self.setpointssetpoints.get("next_sp_from", ""))
130  until = dt_util.as_utc(until) if until else None
131 
132  if operation_mode == STATE_ON:
133  await self._evo_broker_evo_broker.call_client_api(
134  self._evo_device_evo_device.set_on(until=until)
135  )
136  else: # STATE_OFF
137  await self._evo_broker_evo_broker.call_client_api(
138  self._evo_device_evo_device.set_off(until=until)
139  )
140 
141  async def async_turn_away_mode_on(self) -> None:
142  """Turn away mode on."""
143  await self._evo_broker_evo_broker.call_client_api(self._evo_device_evo_device.set_off())
144 
145  async def async_turn_away_mode_off(self) -> None:
146  """Turn away mode off."""
147  await self._evo_broker_evo_broker.call_client_api(self._evo_device_evo_device.reset_mode())
148 
149  async def async_turn_on(self, **kwargs: Any) -> None:
150  """Turn on."""
151  await self._evo_broker_evo_broker.call_client_api(self._evo_device_evo_device.set_on())
152 
153  async def async_turn_off(self, **kwargs: Any) -> None:
154  """Turn off."""
155  await self._evo_broker_evo_broker.call_client_api(self._evo_device_evo_device.set_off())
156 
157  async def async_update(self) -> None:
158  """Get the latest state data for a DHW controller."""
159  await super().async_update()
160 
161  for attr in STATE_ATTRS_DHW:
162  self._device_state_attrs_device_state_attrs[attr] = getattr(self._evo_device_evo_device, attr)
None __init__(self, EvoBroker evo_broker, evo.HotWater evo_device)
Definition: water_heater.py:86
None async_set_operation_mode(self, str operation_mode)
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: water_heater.py:56