Home Assistant Unofficial Reference 2024.12.1
climate.py
Go to the documentation of this file.
1 """Support for ZhongHong HVAC Controller."""
2 
3 from __future__ import annotations
4 
5 import logging
6 from typing import Any
7 
8 import voluptuous as vol
9 from zhong_hong_hvac.hub import ZhongHongGateway
10 from zhong_hong_hvac.hvac import HVAC as ZhongHongHVAC
11 
13  ATTR_HVAC_MODE,
14  PLATFORM_SCHEMA as CLIMATE_PLATFORM_SCHEMA,
15  ClimateEntity,
16  ClimateEntityFeature,
17  HVACMode,
18 )
19 from homeassistant.const import (
20  ATTR_TEMPERATURE,
21  CONF_HOST,
22  CONF_PORT,
23  EVENT_HOMEASSISTANT_STOP,
24  UnitOfTemperature,
25 )
26 from homeassistant.core import HomeAssistant
29  async_dispatcher_connect,
30  async_dispatcher_send,
31 )
32 from homeassistant.helpers.entity_platform import AddEntitiesCallback
33 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
34 
35 _LOGGER = logging.getLogger(__name__)
36 
37 CONF_GATEWAY_ADDRRESS = "gateway_address"
38 
39 DEFAULT_PORT = 9999
40 DEFAULT_GATEWAY_ADDRRESS = 1
41 
42 SIGNAL_DEVICE_ADDED = "zhong_hong_device_added"
43 SIGNAL_ZHONG_HONG_HUB_START = "zhong_hong_hub_start"
44 
45 PLATFORM_SCHEMA = CLIMATE_PLATFORM_SCHEMA.extend(
46  {
47  vol.Required(CONF_HOST): cv.string,
48  vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
49  vol.Optional(
50  CONF_GATEWAY_ADDRRESS, default=DEFAULT_GATEWAY_ADDRRESS
51  ): cv.positive_int,
52  }
53 )
54 
55 ZHONG_HONG_MODE_COOL = "cool"
56 ZHONG_HONG_MODE_HEAT = "heat"
57 ZHONG_HONG_MODE_DRY = "dry"
58 ZHONG_HONG_MODE_FAN_ONLY = "fan_only"
59 
60 
61 MODE_TO_STATE = {
62  ZHONG_HONG_MODE_COOL: HVACMode.COOL,
63  ZHONG_HONG_MODE_HEAT: HVACMode.HEAT,
64  ZHONG_HONG_MODE_DRY: HVACMode.DRY,
65  ZHONG_HONG_MODE_FAN_ONLY: HVACMode.FAN_ONLY,
66 }
67 
68 
70  hass: HomeAssistant,
71  config: ConfigType,
72  add_entities: AddEntitiesCallback,
73  discovery_info: DiscoveryInfoType | None = None,
74 ) -> None:
75  """Set up the ZhongHong HVAC platform."""
76 
77  host = config.get(CONF_HOST)
78  port = config.get(CONF_PORT)
79  gw_addr = config.get(CONF_GATEWAY_ADDRRESS)
80  hub = ZhongHongGateway(host, port, gw_addr)
81  devices = [
82  ZhongHongClimate(hub, addr_out, addr_in)
83  for (addr_out, addr_in) in hub.discovery_ac()
84  ]
85 
86  _LOGGER.debug("We got %s zhong_hong climate devices", len(devices))
87 
88  hub_is_initialized = False
89 
90  def _start_hub():
91  """Start the hub socket and query status of all devices."""
92  hub.start_listen()
93  hub.query_all_status()
94 
95  async def startup():
96  """Start hub socket after all climate entity is set up."""
97  nonlocal hub_is_initialized
98  if not all(device.is_initialized for device in devices):
99  return
100 
101  if hub_is_initialized:
102  return
103 
104  _LOGGER.debug("zhong_hong hub start listen event")
105  await hass.async_add_executor_job(_start_hub)
106  hub_is_initialized = True
107 
108  async_dispatcher_connect(hass, SIGNAL_DEVICE_ADDED, startup)
109 
110  # add devices after SIGNAL_DEVICE_SETTED_UP event is listened
111  add_entities(devices)
112 
113  def stop_listen(event):
114  """Stop ZhongHongHub socket."""
115  hub.stop_listen()
116 
117  hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_listen)
118 
119 
121  """Representation of a ZhongHong controller support HVAC."""
122 
123  _attr_hvac_modes = [
124  HVACMode.COOL,
125  HVACMode.HEAT,
126  HVACMode.DRY,
127  HVACMode.FAN_ONLY,
128  HVACMode.OFF,
129  ]
130  _attr_should_poll = False
131  _attr_supported_features = (
132  ClimateEntityFeature.TARGET_TEMPERATURE
133  | ClimateEntityFeature.FAN_MODE
134  | ClimateEntityFeature.TURN_OFF
135  | ClimateEntityFeature.TURN_ON
136  )
137  _attr_temperature_unit = UnitOfTemperature.CELSIUS
138  _enable_turn_on_off_backwards_compatibility = False
139 
140  def __init__(self, hub, addr_out, addr_in):
141  """Set up the ZhongHong climate devices."""
142 
143  self._device_device = ZhongHongHVAC(hub, addr_out, addr_in)
144  self._hub_hub = hub
145  self._current_operation_current_operation = None
146  self._current_temperature_current_temperature = None
147  self._target_temperature_target_temperature = None
148  self._current_fan_mode_current_fan_mode = None
149  self.is_initializedis_initialized = False
150 
151  async def async_added_to_hass(self) -> None:
152  """Register callbacks."""
153  self._device_device.register_update_callback(self._after_update_after_update)
154  self.is_initializedis_initialized = True
155  async_dispatcher_send(self.hasshass, SIGNAL_DEVICE_ADDED)
156 
157  def _after_update(self, climate):
158  """Handle state update."""
159  _LOGGER.debug("async update ha state")
160  if self._device_device.current_operation:
161  self._current_operation_current_operation = MODE_TO_STATE[
162  self._device_device.current_operation.lower()
163  ]
164  if self._device_device.current_temperature:
165  self._current_temperature_current_temperature = self._device_device.current_temperature
166  if self._device_device.current_fan_mode:
167  self._current_fan_mode_current_fan_mode = self._device_device.current_fan_mode
168  if self._device_device.target_temperature:
169  self._target_temperature_target_temperature = self._device_device.target_temperature
170  self.schedule_update_ha_stateschedule_update_ha_state()
171 
172  @property
173  def name(self):
174  """Return the name of the thermostat, if any."""
175  return self.unique_idunique_idunique_id
176 
177  @property
178  def unique_id(self):
179  """Return the unique ID of the HVAC."""
180  return f"zhong_hong_hvac_{self._device.addr_out}_{self._device.addr_in}"
181 
182  @property
183  def hvac_mode(self) -> HVACMode:
184  """Return current operation ie. heat, cool, idle."""
185  if self.is_onis_on:
186  return self._current_operation_current_operation
187  return HVACMode.OFF
188 
189  @property
191  """Return the current temperature."""
192  return self._current_temperature_current_temperature
193 
194  @property
196  """Return the temperature we try to reach."""
197  return self._target_temperature_target_temperature
198 
199  @property
201  """Return the supported step of target temperature."""
202  return 1
203 
204  @property
205  def is_on(self):
206  """Return true if on."""
207  return self._device_device.is_on
208 
209  @property
210  def fan_mode(self):
211  """Return the fan setting."""
212  return self._current_fan_mode_current_fan_mode
213 
214  @property
215  def fan_modes(self):
216  """Return the list of available fan modes."""
217  return self._device_device.fan_list
218 
219  @property
220  def min_temp(self):
221  """Return the minimum temperature."""
222  return self._device_device.min_temp
223 
224  @property
225  def max_temp(self):
226  """Return the maximum temperature."""
227  return self._device_device.max_temp
228 
229  def turn_on(self) -> None:
230  """Turn on ac."""
231  return self._device_device.turn_on()
232 
233  def turn_off(self) -> None:
234  """Turn off ac."""
235  return self._device_device.turn_off()
236 
237  def set_temperature(self, **kwargs: Any) -> None:
238  """Set new target temperature."""
239  if (temperature := kwargs.get(ATTR_TEMPERATURE)) is not None:
240  self._device_device.set_temperature(temperature)
241 
242  if (operation_mode := kwargs.get(ATTR_HVAC_MODE)) is not None:
243  self.set_hvac_modeset_hvac_modeset_hvac_mode(operation_mode)
244 
245  def set_hvac_mode(self, hvac_mode: HVACMode) -> None:
246  """Set new target operation mode."""
247  if hvac_mode == HVACMode.OFF:
248  if self.is_onis_on:
249  self.turn_offturn_offturn_off()
250  return
251 
252  if not self.is_onis_on:
253  self.turn_onturn_onturn_on()
254 
255  self._device_device.set_operation_mode(hvac_mode.upper())
256 
257  def set_fan_mode(self, fan_mode: str) -> None:
258  """Set new target fan mode."""
259  self._device_device.set_fan_mode(fan_mode)
None set_hvac_mode(self, HVACMode hvac_mode)
Definition: __init__.py:809
None schedule_update_ha_state(self, bool force_refresh=False)
Definition: entity.py:1244
None add_entities(AsusWrtRouter router, AddEntitiesCallback async_add_entities, set[str] tracked)
None setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: climate.py:74
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)
Definition: dispatcher.py:193