Home Assistant Unofficial Reference 2024.12.1
atlantic_domestic_hot_water_production_mlb_component.py
Go to the documentation of this file.
1 """Support for AtlanticDomesticHotWaterProductionMBLComponent."""
2 
3 from typing import Any, cast
4 
5 from pyoverkiz.enums import OverkizCommand, OverkizCommandParam, OverkizState
6 
8  STATE_ECO,
9  STATE_ELECTRIC,
10  STATE_OFF,
11  STATE_PERFORMANCE,
12  WaterHeaterEntity,
13  WaterHeaterEntityFeature,
14 )
15 from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
16 from homeassistant.util import dt as dt_util
17 
18 from .. import OverkizDataUpdateCoordinator
19 from ..entity import OverkizEntity
20 
21 
23  """Representation of AtlanticDomesticHotWaterProductionMBLComponent (modbuslink)."""
24 
25  _attr_temperature_unit = UnitOfTemperature.CELSIUS
26  _attr_supported_features = (
27  WaterHeaterEntityFeature.TARGET_TEMPERATURE
28  | WaterHeaterEntityFeature.OPERATION_MODE
29  | WaterHeaterEntityFeature.AWAY_MODE
30  | WaterHeaterEntityFeature.ON_OFF
31  )
32  _attr_operation_list = [
33  STATE_ECO,
34  STATE_OFF,
35  STATE_PERFORMANCE,
36  STATE_ELECTRIC,
37  ]
38 
39  def __init__(
40  self, device_url: str, coordinator: OverkizDataUpdateCoordinator
41  ) -> None:
42  """Init method."""
43  super().__init__(device_url, coordinator)
44  self._attr_max_temp_attr_max_temp = cast(
45  float,
46  self.executorexecutor.select_state(
47  OverkizState.CORE_MAXIMAL_TEMPERATURE_MANUAL_MODE
48  ),
49  )
50  self._attr_min_temp_attr_min_temp = cast(
51  float,
52  self.executorexecutor.select_state(
53  OverkizState.CORE_MINIMAL_TEMPERATURE_MANUAL_MODE
54  ),
55  )
56 
57  @property
58  def current_temperature(self) -> float:
59  """Return the current temperature."""
60  return cast(
61  float,
62  self.executorexecutor.select_state(
63  OverkizState.MODBUSLINK_MIDDLE_WATER_TEMPERATURE
64  ),
65  )
66 
67  @property
68  def target_temperature(self) -> float:
69  """Return the temperature corresponding to the PRESET."""
70  return cast(
71  float,
72  self.executorexecutor.select_state(OverkizState.CORE_WATER_TARGET_TEMPERATURE),
73  )
74 
75  async def async_set_temperature(self, **kwargs: Any) -> None:
76  """Set new temperature."""
77  temperature = kwargs[ATTR_TEMPERATURE]
78  await self.executorexecutor.async_execute_command(
79  OverkizCommand.SET_TARGET_DHW_TEMPERATURE, temperature
80  )
81 
82  @property
83  def is_boost_mode_on(self) -> bool:
84  """Return true if boost mode is on."""
85  return self.executorexecutor.select_state(OverkizState.MODBUSLINK_DHW_BOOST_MODE) in (
86  OverkizCommandParam.ON,
87  OverkizCommandParam.PROG,
88  )
89 
90  @property
91  def is_eco_mode_on(self) -> bool:
92  """Return true if eco mode is on."""
93  return self.executorexecutor.select_state(OverkizState.MODBUSLINK_DHW_MODE) in (
94  OverkizCommandParam.MANUAL_ECO_ACTIVE,
95  OverkizCommandParam.AUTO_MODE,
96  )
97 
98  @property
99  def is_away_mode_on(self) -> bool:
100  """Return true if away mode is on."""
101  return self.executorexecutor.select_state(OverkizState.MODBUSLINK_DHW_ABSENCE_MODE) in (
102  OverkizCommandParam.ON,
103  OverkizCommandParam.PROG,
104  )
105 
106  @property
107  def current_operation(self) -> str:
108  """Return current operation."""
109  if self.is_away_mode_onis_away_mode_onis_away_mode_on:
110  return STATE_OFF
111 
112  if self.is_boost_mode_onis_boost_mode_on:
113  return STATE_PERFORMANCE
114 
115  if self.is_eco_mode_onis_eco_mode_on:
116  return STATE_ECO
117 
118  if (
119  cast(str, self.executorexecutor.select_state(OverkizState.MODBUSLINK_DHW_MODE))
120  == OverkizCommandParam.MANUAL_ECO_INACTIVE
121  ):
122  # STATE_ELECTRIC is a substitution for OverkizCommandParam.MANUAL
123  # to keep up with the conventional state usage only
124  # https://developers.home-assistant.io/docs/core/entity/water-heater/#states
125  return STATE_ELECTRIC
126 
127  return STATE_OFF
128 
129  async def async_set_operation_mode(self, operation_mode: str) -> None:
130  """Set new operation mode."""
131  if operation_mode == STATE_PERFORMANCE:
132  if self.is_away_mode_onis_away_mode_onis_away_mode_on:
133  await self.async_turn_away_mode_offasync_turn_away_mode_offasync_turn_away_mode_off()
134  await self.async_turn_boost_mode_onasync_turn_boost_mode_on()
135  elif operation_mode == STATE_ECO:
136  if self.is_away_mode_onis_away_mode_onis_away_mode_on:
137  await self.async_turn_away_mode_offasync_turn_away_mode_offasync_turn_away_mode_off()
138  if self.is_boost_mode_onis_boost_mode_on:
139  await self.async_turn_boost_mode_offasync_turn_boost_mode_off()
140  await self.executorexecutor.async_execute_command(
141  OverkizCommand.SET_DHW_MODE, OverkizCommandParam.AUTO_MODE
142  )
143  elif operation_mode == STATE_ELECTRIC:
144  if self.is_away_mode_onis_away_mode_onis_away_mode_on:
145  await self.async_turn_away_mode_offasync_turn_away_mode_offasync_turn_away_mode_off()
146  if self.is_boost_mode_onis_boost_mode_on:
147  await self.async_turn_boost_mode_offasync_turn_boost_mode_off()
148  await self.executorexecutor.async_execute_command(
149  OverkizCommand.SET_DHW_MODE, OverkizCommandParam.MANUAL_ECO_INACTIVE
150  )
151  elif operation_mode == STATE_OFF:
152  await self.async_turn_away_mode_onasync_turn_away_mode_onasync_turn_away_mode_on()
153 
154  async def async_turn_away_mode_on(self) -> None:
155  """Turn away mode on.
156 
157  This requires the start date and the end date to be also set, and those dates have to match the device datetime.
158  The API accepts setting dates in the format of the core:DateTimeState state for the DHW
159  {'day': 11, 'hour': 21, 'minute': 12, 'month': 7, 'second': 53, 'weekday': 3, 'year': 2024}
160  The dict is then passed as an actual device date, the away mode start date, and then as an end date,
161  but with the year incremented by 1, so the away mode is getting turned on for the next year.
162  The weekday number seems to have no effect so the calculation of the future date's weekday number is redundant,
163  but possible via homeassistant dt_util to form both start and end dates dictionaries from scratch
164  based on datetime.now() and datetime.timedelta into the future.
165  If you execute `setAbsenceStartDate`, `setAbsenceEndDate` and `setAbsenceMode`,
166  the API answers with "too many requests", as there's a polling update after each command execution,
167  and the device becomes unavailable until the API is available again.
168  With `refresh_afterwards=False` on the first commands, and `refresh_afterwards=True` only the last command,
169  the API is not choking and the transition is smooth without the unavailability state.
170  """
171  now = dt_util.now()
172  now_date = {
173  "month": now.month,
174  "hour": now.hour,
175  "year": now.year,
176  "weekday": now.weekday(),
177  "day": now.day,
178  "minute": now.minute,
179  "second": now.second,
180  }
181  await self.executorexecutor.async_execute_command(
182  OverkizCommand.SET_DATE_TIME,
183  now_date,
184  refresh_afterwards=False,
185  )
186  await self.executorexecutor.async_execute_command(
187  OverkizCommand.SET_ABSENCE_START_DATE, now_date, refresh_afterwards=False
188  )
189  now_date["year"] = now_date["year"] + 1
190  await self.executorexecutor.async_execute_command(
191  OverkizCommand.SET_ABSENCE_END_DATE, now_date, refresh_afterwards=False
192  )
193  await self.executorexecutor.async_execute_command(
194  OverkizCommand.SET_ABSENCE_MODE,
195  OverkizCommandParam.PROG,
196  refresh_afterwards=False,
197  )
198  await self.coordinator.async_refresh()
199 
200  async def async_turn_away_mode_off(self) -> None:
201  """Turn away mode off."""
202  await self.executorexecutor.async_execute_command(
203  OverkizCommand.SET_ABSENCE_MODE, OverkizCommandParam.OFF
204  )
205 
206  async def async_turn_boost_mode_on(self) -> None:
207  """Turn boost mode on."""
208  await self.executorexecutor.async_execute_command(
209  OverkizCommand.SET_BOOST_MODE, OverkizCommandParam.ON
210  )
211 
212  async def async_turn_boost_mode_off(self) -> None:
213  """Turn boost mode off."""
214  await self.executorexecutor.async_execute_command(
215  OverkizCommand.SET_BOOST_MODE, OverkizCommandParam.OFF
216  )