Home Assistant Unofficial Reference 2024.12.1
climate.py
Go to the documentation of this file.
1 """Climate platform for Advantage Air integration."""
2 
3 from __future__ import annotations
4 
5 import logging
6 from typing import Any
7 
9  ATTR_TARGET_TEMP_HIGH,
10  ATTR_TARGET_TEMP_LOW,
11  FAN_AUTO,
12  FAN_HIGH,
13  FAN_LOW,
14  FAN_MEDIUM,
15  ClimateEntity,
16  ClimateEntityFeature,
17  HVACMode,
18 )
19 from homeassistant.const import ATTR_TEMPERATURE, PRECISION_WHOLE, UnitOfTemperature
20 from homeassistant.core import HomeAssistant, callback
21 from homeassistant.exceptions import ServiceValidationError
22 from homeassistant.helpers.entity_platform import AddEntitiesCallback
23 
24 from . import AdvantageAirDataConfigEntry
25 from .const import (
26  ADVANTAGE_AIR_AUTOFAN_ENABLED,
27  ADVANTAGE_AIR_STATE_CLOSE,
28  ADVANTAGE_AIR_STATE_OFF,
29  ADVANTAGE_AIR_STATE_ON,
30  ADVANTAGE_AIR_STATE_OPEN,
31 )
32 from .entity import AdvantageAirAcEntity, AdvantageAirZoneEntity
33 from .models import AdvantageAirData
34 
35 ADVANTAGE_AIR_HVAC_MODES = {
36  "heat": HVACMode.HEAT,
37  "cool": HVACMode.COOL,
38  "vent": HVACMode.FAN_ONLY,
39  "dry": HVACMode.DRY,
40  "myauto": HVACMode.HEAT_COOL,
41 }
42 HASS_HVAC_MODES = {v: k for k, v in ADVANTAGE_AIR_HVAC_MODES.items()}
43 
44 ADVANTAGE_AIR_MYZONE = "MyZone"
45 ADVANTAGE_AIR_MYAUTO = "MyAuto"
46 ADVANTAGE_AIR_MYAUTO_ENABLED = "myAutoModeEnabled"
47 ADVANTAGE_AIR_MYTEMP = "MyTemp"
48 ADVANTAGE_AIR_MYTEMP_ENABLED = "climateControlModeEnabled"
49 ADVANTAGE_AIR_HEAT_TARGET = "myAutoHeatTargetTemp"
50 ADVANTAGE_AIR_COOL_TARGET = "myAutoCoolTargetTemp"
51 ADVANTAGE_AIR_MYFAN = "autoAA"
52 
53 HVAC_MODES = [
54  HVACMode.OFF,
55  HVACMode.COOL,
56  HVACMode.HEAT,
57  HVACMode.FAN_ONLY,
58  HVACMode.DRY,
59 ]
60 HVAC_MODES_MYAUTO = [*HVAC_MODES, HVACMode.HEAT_COOL]
61 SUPPORTED_FEATURES = (
62  ClimateEntityFeature.FAN_MODE
63  | ClimateEntityFeature.TURN_OFF
64  | ClimateEntityFeature.TURN_ON
65 )
66 SUPPORTED_FEATURES_MYZONE = SUPPORTED_FEATURES | ClimateEntityFeature.TARGET_TEMPERATURE
67 SUPPORTED_FEATURES_MYAUTO = (
68  SUPPORTED_FEATURES | ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
69 )
70 
71 PARALLEL_UPDATES = 0
72 
73 _LOGGER = logging.getLogger(__name__)
74 
75 
77  hass: HomeAssistant,
78  config_entry: AdvantageAirDataConfigEntry,
79  async_add_entities: AddEntitiesCallback,
80 ) -> None:
81  """Set up AdvantageAir climate platform."""
82 
83  instance = config_entry.runtime_data
84 
85  entities: list[ClimateEntity] = []
86  if aircons := instance.coordinator.data.get("aircons"):
87  for ac_key, ac_device in aircons.items():
88  entities.append(AdvantageAirAC(instance, ac_key))
89  for zone_key, zone in ac_device["zones"].items():
90  # Only add zone climate control when zone is in temperature control
91  if zone["type"] > 0:
92  entities.append(AdvantageAirZone(instance, ac_key, zone_key))
93  async_add_entities(entities)
94 
95 
97  """AdvantageAir AC unit."""
98 
99  _attr_fan_modes = [FAN_LOW, FAN_MEDIUM, FAN_HIGH, FAN_AUTO]
100  _attr_temperature_unit = UnitOfTemperature.CELSIUS
101  _attr_target_temperature_step = PRECISION_WHOLE
102  _attr_max_temp = 32
103  _attr_min_temp = 16
104  _attr_name = None
105  _enable_turn_on_off_backwards_compatibility = False
106  _support_preset = ClimateEntityFeature(0)
107 
108  def __init__(self, instance: AdvantageAirData, ac_key: str) -> None:
109  """Initialize an AdvantageAir AC unit."""
110  super().__init__(instance, ac_key)
111 
112  self._attr_preset_modes_attr_preset_modes = [ADVANTAGE_AIR_MYZONE]
113 
114  # Add "MyTemp" preset if available
115  if ADVANTAGE_AIR_MYTEMP_ENABLED in self._ac_ac:
116  self._attr_preset_modes_attr_preset_modes += [ADVANTAGE_AIR_MYTEMP]
117  self._support_preset_support_preset = ClimateEntityFeature.PRESET_MODE
118 
119  # Add "MyAuto" preset if available
120  if ADVANTAGE_AIR_MYAUTO_ENABLED in self._ac_ac:
121  self._attr_preset_modes_attr_preset_modes += [ADVANTAGE_AIR_MYAUTO]
122  self._support_preset_support_preset = ClimateEntityFeature.PRESET_MODE
123 
124  # Setup attributes based on current preset
125  self._async_configure_preset_async_configure_preset()
126 
127  def _async_configure_preset(self) -> None:
128  """Configure attributes based on preset."""
129 
130  # Preset Changes
131  if self._ac_ac.get(ADVANTAGE_AIR_MYAUTO_ENABLED):
132  # MyAuto
133  self._attr_preset_mode_attr_preset_mode = ADVANTAGE_AIR_MYAUTO
134  self._attr_hvac_modes_attr_hvac_modes = HVAC_MODES_MYAUTO
135  self._attr_supported_features_attr_supported_features = (
136  SUPPORTED_FEATURES_MYAUTO | self._support_preset_support_preset
137  )
138  elif self._ac_ac.get(ADVANTAGE_AIR_MYTEMP_ENABLED):
139  # MyTemp
140  self._attr_preset_mode_attr_preset_mode = ADVANTAGE_AIR_MYTEMP
141  self._attr_hvac_modes_attr_hvac_modes = HVAC_MODES
142  self._attr_supported_features_attr_supported_features = SUPPORTED_FEATURES | self._support_preset_support_preset
143  else:
144  # MyZone
145  self._attr_preset_mode_attr_preset_mode = ADVANTAGE_AIR_MYZONE
146  self._attr_hvac_modes_attr_hvac_modes = HVAC_MODES
147  self._attr_supported_features_attr_supported_features = (
148  SUPPORTED_FEATURES_MYZONE | self._support_preset_support_preset
149  )
150 
151  @callback
152  def _handle_coordinator_update(self) -> None:
153  """Handle updated data from the coordinator."""
154  self._async_configure_preset_async_configure_preset()
156 
157  @property
158  def current_temperature(self) -> float | None:
159  """Return the selected zones current temperature."""
160  if self._myzone_myzone:
161  return self._myzone_myzone["measuredTemp"]
162  return None
163 
164  @property
165  def target_temperature(self) -> float | None:
166  """Return the current target temperature."""
167  # If the system is in MyZone mode, and a zone is set, return that temperature instead.
168  if self._myzone_myzone and self.preset_modepreset_modepreset_mode == ADVANTAGE_AIR_MYZONE:
169  return self._myzone_myzone["setTemp"]
170  return self._ac_ac["setTemp"]
171 
172  @property
173  def hvac_mode(self) -> HVACMode | None:
174  """Return the current HVAC modes."""
175  if self._ac_ac["state"] == ADVANTAGE_AIR_STATE_ON:
176  return ADVANTAGE_AIR_HVAC_MODES.get(self._ac_ac["mode"])
177  return HVACMode.OFF
178 
179  @property
180  def fan_mode(self) -> str | None:
181  """Return the current fan modes."""
182  return FAN_AUTO if self._ac_ac["fan"] == ADVANTAGE_AIR_MYFAN else self._ac_ac["fan"]
183 
184  @property
185  def target_temperature_high(self) -> float | None:
186  """Return the temperature cool mode is enabled."""
187  return self._ac_ac.get(ADVANTAGE_AIR_COOL_TARGET)
188 
189  @property
190  def target_temperature_low(self) -> float | None:
191  """Return the temperature heat mode is enabled."""
192  return self._ac_ac.get(ADVANTAGE_AIR_HEAT_TARGET)
193 
194  async def async_turn_on(self) -> None:
195  """Set the HVAC State to on."""
196  await self.async_update_acasync_update_ac({"state": ADVANTAGE_AIR_STATE_ON})
197 
198  async def async_turn_off(self) -> None:
199  """Set the HVAC State to off."""
200  await self.async_update_acasync_update_ac(
201  {
202  "state": ADVANTAGE_AIR_STATE_OFF,
203  }
204  )
205 
206  async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
207  """Set the HVAC Mode and State."""
208  if hvac_mode == HVACMode.OFF:
209  await self.async_turn_offasync_turn_offasync_turn_off()
210  return
211  if hvac_mode == HVACMode.HEAT_COOL and self.preset_modepreset_modepreset_mode != ADVANTAGE_AIR_MYAUTO:
212  raise ServiceValidationError("Heat/Cool is not supported in this mode")
213  await self.async_update_acasync_update_ac(
214  {
215  "state": ADVANTAGE_AIR_STATE_ON,
216  "mode": HASS_HVAC_MODES.get(hvac_mode),
217  }
218  )
219 
220  async def async_set_fan_mode(self, fan_mode: str) -> None:
221  """Set the Fan Mode."""
222  if fan_mode == FAN_AUTO and self._ac_ac.get(ADVANTAGE_AIR_AUTOFAN_ENABLED):
223  mode = ADVANTAGE_AIR_MYFAN
224  else:
225  mode = fan_mode
226  await self.async_update_acasync_update_ac({"fan": mode})
227 
228  async def async_set_temperature(self, **kwargs: Any) -> None:
229  """Set the Temperature."""
230  if ATTR_TEMPERATURE in kwargs:
231  await self.async_update_acasync_update_ac({"setTemp": kwargs[ATTR_TEMPERATURE]})
232  if ATTR_TARGET_TEMP_LOW in kwargs and ATTR_TARGET_TEMP_HIGH in kwargs:
233  await self.async_update_acasync_update_ac(
234  {
235  ADVANTAGE_AIR_COOL_TARGET: kwargs[ATTR_TARGET_TEMP_HIGH],
236  ADVANTAGE_AIR_HEAT_TARGET: kwargs[ATTR_TARGET_TEMP_LOW],
237  }
238  )
239 
240  async def async_set_preset_mode(self, preset_mode: str) -> None:
241  """Set the preset mode."""
242  change = {}
243  if ADVANTAGE_AIR_MYTEMP_ENABLED in self._ac_ac:
244  change[ADVANTAGE_AIR_MYTEMP_ENABLED] = preset_mode == ADVANTAGE_AIR_MYTEMP
245  if ADVANTAGE_AIR_MYAUTO_ENABLED in self._ac_ac:
246  change[ADVANTAGE_AIR_MYAUTO_ENABLED] = preset_mode == ADVANTAGE_AIR_MYAUTO
247  if change:
248  await self.async_update_acasync_update_ac(change)
249 
250 
252  """AdvantageAir MyTemp Zone control."""
253 
254  _attr_hvac_modes = [HVACMode.OFF, HVACMode.HEAT_COOL]
255  _attr_supported_features = (
256  ClimateEntityFeature.TARGET_TEMPERATURE
257  | ClimateEntityFeature.TURN_OFF
258  | ClimateEntityFeature.TURN_ON
259  )
260  _attr_temperature_unit = UnitOfTemperature.CELSIUS
261  _attr_target_temperature_step = PRECISION_WHOLE
262  _attr_max_temp = 32
263  _attr_min_temp = 16
264  _enable_turn_on_off_backwards_compatibility = False
265 
266  def __init__(self, instance: AdvantageAirData, ac_key: str, zone_key: str) -> None:
267  """Initialize an AdvantageAir Zone control."""
268  super().__init__(instance, ac_key, zone_key)
269  self._attr_name_attr_name = self._zone_zone["name"]
270 
271  @property
272  def hvac_mode(self) -> HVACMode:
273  """Return the current state as HVAC mode."""
274  if self._zone_zone["state"] == ADVANTAGE_AIR_STATE_OPEN:
275  return HVACMode.HEAT_COOL
276  return HVACMode.OFF
277 
278  @property
279  def current_temperature(self) -> float | None:
280  """Return the current temperature."""
281  return self._zone_zone["measuredTemp"]
282 
283  @property
284  def target_temperature(self) -> float:
285  """Return the target temperature."""
286  return self._zone_zone["setTemp"]
287 
288  async def async_turn_on(self) -> None:
289  """Set the HVAC State to on."""
290  await self.async_update_zoneasync_update_zone({"state": ADVANTAGE_AIR_STATE_OPEN})
291 
292  async def async_turn_off(self) -> None:
293  """Set the HVAC State to off."""
294  await self.async_update_zoneasync_update_zone({"state": ADVANTAGE_AIR_STATE_CLOSE})
295 
296  async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
297  """Set the HVAC Mode and State."""
298  if hvac_mode == HVACMode.OFF:
299  await self.async_turn_offasync_turn_offasync_turn_off()
300  else:
301  await self.async_turn_onasync_turn_onasync_turn_on()
302 
303  async def async_set_temperature(self, **kwargs: Any) -> None:
304  """Set the Temperature."""
305  temp = kwargs.get(ATTR_TEMPERATURE)
306  await self.async_update_zoneasync_update_zone({"setTemp": temp})
None __init__(self, AdvantageAirData instance, str ac_key)
Definition: climate.py:108
None __init__(self, AdvantageAirData instance, str ac_key, str zone_key)
Definition: climate.py:266
None async_setup_entry(HomeAssistant hass, AdvantageAirDataConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: climate.py:80
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88