Home Assistant Unofficial Reference 2024.12.1
climate.py
Go to the documentation of this file.
1 """Support for Insteon thermostat."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 from pyinsteon.config import CELSIUS
8 from pyinsteon.constants import ThermostatMode
9 
11  ATTR_TARGET_TEMP_HIGH,
12  ATTR_TARGET_TEMP_LOW,
13  FAN_AUTO,
14  ClimateEntity,
15  ClimateEntityFeature,
16  HVACAction,
17  HVACMode,
18 )
19 from homeassistant.config_entries import ConfigEntry
20 from homeassistant.const import ATTR_TEMPERATURE, Platform, UnitOfTemperature
21 from homeassistant.core import HomeAssistant, callback
22 from homeassistant.helpers.dispatcher import async_dispatcher_connect
23 from homeassistant.helpers.entity_platform import AddEntitiesCallback
24 
25 from .const import SIGNAL_ADD_ENTITIES
26 from .entity import InsteonEntity
27 from .utils import async_add_insteon_devices, async_add_insteon_entities
28 
29 FAN_ONLY = "fan_only"
30 
31 COOLING = 1
32 HEATING = 2
33 DEHUMIDIFYING = 3
34 HUMIDIFYING = 4
35 
36 TEMPERATURE = 10
37 HUMIDITY = 11
38 SYSTEM_MODE = 12
39 FAN_MODE = 13
40 COOL_SET_POINT = 14
41 HEAT_SET_POINT = 15
42 HUMIDITY_HIGH = 16
43 HUMIDITY_LOW = 17
44 
45 
46 HVAC_MODES = {
47  0: HVACMode.OFF,
48  1: HVACMode.HEAT,
49  2: HVACMode.COOL,
50  3: HVACMode.HEAT_COOL,
51 }
52 FAN_MODES = {4: FAN_AUTO, 8: FAN_ONLY}
53 
54 
56  hass: HomeAssistant,
57  config_entry: ConfigEntry,
58  async_add_entities: AddEntitiesCallback,
59 ) -> None:
60  """Set up the Insteon climate entities from a config entry."""
61 
62  @callback
63  def async_add_insteon_climate_entities(discovery_info=None):
64  """Add the Insteon entities for the platform."""
66  hass,
67  Platform.CLIMATE,
68  InsteonClimateEntity,
69  async_add_entities,
70  discovery_info,
71  )
72 
73  signal = f"{SIGNAL_ADD_ENTITIES}_{Platform.CLIMATE}"
74  async_dispatcher_connect(hass, signal, async_add_insteon_climate_entities)
76  hass,
77  Platform.CLIMATE,
78  InsteonClimateEntity,
79  async_add_entities,
80  )
81 
82 
84  """A Class for an Insteon climate entity."""
85 
86  _attr_supported_features = (
87  ClimateEntityFeature.FAN_MODE
88  | ClimateEntityFeature.TARGET_HUMIDITY
89  | ClimateEntityFeature.TARGET_TEMPERATURE
90  | ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
91  | ClimateEntityFeature.TURN_OFF
92  | ClimateEntityFeature.TURN_ON
93  )
94  _attr_hvac_modes = list(HVAC_MODES.values())
95  _attr_fan_modes = list(FAN_MODES.values())
96  _attr_min_humidity = 1
97  _enable_turn_on_off_backwards_compatibility = False
98 
99  @property
100  def temperature_unit(self) -> str:
101  """Return the unit of measurement."""
102  if self._insteon_device_insteon_device.configuration[CELSIUS].value:
103  return UnitOfTemperature.CELSIUS
104  return UnitOfTemperature.FAHRENHEIT
105 
106  @property
107  def current_humidity(self) -> int | None:
108  """Return the current humidity."""
109  return self._insteon_device_insteon_device.groups[HUMIDITY].value
110 
111  @property
112  def hvac_mode(self) -> HVACMode:
113  """Return hvac operation ie. heat, cool mode."""
114  return HVAC_MODES[self._insteon_device_insteon_device.groups[SYSTEM_MODE].value]
115 
116  @property
117  def current_temperature(self) -> float | None:
118  """Return the current temperature."""
119  return self._insteon_device_insteon_device.groups[TEMPERATURE].value
120 
121  @property
122  def target_temperature(self) -> float | None:
123  """Return the temperature we try to reach."""
124  if self._insteon_device_insteon_device.groups[SYSTEM_MODE].value == ThermostatMode.HEAT:
125  return self._insteon_device_insteon_device.groups[HEAT_SET_POINT].value
126  if self._insteon_device_insteon_device.groups[SYSTEM_MODE].value == ThermostatMode.COOL:
127  return self._insteon_device_insteon_device.groups[COOL_SET_POINT].value
128  return None
129 
130  @property
131  def target_temperature_high(self) -> float | None:
132  """Return the highbound target temperature we try to reach."""
133  if self._insteon_device_insteon_device.groups[SYSTEM_MODE].value == ThermostatMode.AUTO:
134  return self._insteon_device_insteon_device.groups[COOL_SET_POINT].value
135  return None
136 
137  @property
138  def target_temperature_low(self) -> float | None:
139  """Return the lowbound target temperature we try to reach."""
140  if self._insteon_device_insteon_device.groups[SYSTEM_MODE].value == ThermostatMode.AUTO:
141  return self._insteon_device_insteon_device.groups[HEAT_SET_POINT].value
142  return None
143 
144  @property
145  def fan_mode(self) -> str | None:
146  """Return the fan setting."""
147  return FAN_MODES[self._insteon_device_insteon_device.groups[FAN_MODE].value]
148 
149  @property
150  def target_humidity(self) -> int | None:
151  """Return the humidity we try to reach."""
152  high = self._insteon_device_insteon_device.groups[HUMIDITY_HIGH].value
153  low = self._insteon_device_insteon_device.groups[HUMIDITY_LOW].value
154  # May not be loaded yet so return a default if required
155  return (high + low) / 2 if high and low else None
156 
157  @property
158  def hvac_action(self) -> HVACAction:
159  """Return the current running hvac operation if supported.
160 
161  Need to be one of CURRENT_HVAC_*.
162  """
163  if self._insteon_device_insteon_device.groups[COOLING].value:
164  return HVACAction.COOLING
165  if self._insteon_device_insteon_device.groups[HEATING].value:
166  return HVACAction.HEATING
167  if self._insteon_device_insteon_device.groups[FAN_MODE].value == ThermostatMode.FAN_ALWAYS_ON:
168  return HVACAction.FAN
169  return HVACAction.IDLE
170 
171  @property
173  """Provide attributes for display on device card."""
174  attr = super().extra_state_attributes
175  humidifier = "off"
176  if self._insteon_device_insteon_device.groups[DEHUMIDIFYING].value:
177  humidifier = "dehumidifying"
178  if self._insteon_device_insteon_device.groups[HUMIDIFYING].value:
179  humidifier = "humidifying"
180  attr["humidifier"] = humidifier
181  return attr
182 
183  async def async_set_temperature(self, **kwargs: Any) -> None:
184  """Set new target temperature."""
185  target_temp = kwargs.get(ATTR_TEMPERATURE)
186  target_temp_low = kwargs.get(ATTR_TARGET_TEMP_LOW)
187  target_temp_high = kwargs.get(ATTR_TARGET_TEMP_HIGH)
188  if target_temp is not None:
189  if self._insteon_device_insteon_device.groups[SYSTEM_MODE].value == ThermostatMode.HEAT:
190  await self._insteon_device_insteon_device.async_set_heat_set_point(target_temp)
191  elif self._insteon_device_insteon_device.groups[SYSTEM_MODE].value == ThermostatMode.COOL:
192  await self._insteon_device_insteon_device.async_set_cool_set_point(target_temp)
193  else:
194  await self._insteon_device_insteon_device.async_set_heat_set_point(target_temp_low)
195  await self._insteon_device_insteon_device.async_set_cool_set_point(target_temp_high)
196 
197  async def async_set_fan_mode(self, fan_mode: str) -> None:
198  """Set new target fan mode."""
199  mode = list(FAN_MODES)[list(FAN_MODES.values()).index(fan_mode)]
200  await self._insteon_device_insteon_device.async_set_mode(mode)
201 
202  async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
203  """Set new target hvac mode."""
204  mode = list(HVAC_MODES)[list(HVAC_MODES.values()).index(hvac_mode)]
205  await self._insteon_device_insteon_device.async_set_mode(mode)
206 
207  async def async_set_humidity(self, humidity: int) -> None:
208  """Set new humidity level."""
209  change = humidity - (self.target_humiditytarget_humiditytarget_humidity or 0)
210  high = self._insteon_device_insteon_device.groups[HUMIDITY_HIGH].value + change
211  low = self._insteon_device_insteon_device.groups[HUMIDITY_LOW].value + change
212  await self._insteon_device_insteon_device.async_set_humidity_low_set_point(low)
213  await self._insteon_device_insteon_device.async_set_humidity_high_set_point(high)
214 
215  async def async_added_to_hass(self) -> None:
216  """Register INSTEON update events."""
217  await super().async_added_to_hass()
218  await self._insteon_device_insteon_device.async_read_op_flags()
219  for group in (
220  COOLING,
221  HEATING,
222  DEHUMIDIFYING,
223  HUMIDIFYING,
224  HEAT_SET_POINT,
225  FAN_MODE,
226  SYSTEM_MODE,
227  TEMPERATURE,
228  HUMIDITY,
229  HUMIDITY_HIGH,
230  HUMIDITY_LOW,
231  ):
232  self._insteon_device_insteon_device.groups[group].subscribe(self.async_entity_updateasync_entity_update)
def async_entity_update(self, name, address, value, group)
Definition: entity.py:102
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: climate.py:59
None async_add_insteon_devices(HomeAssistant hass, Platform platform, type[InsteonEntity] entity_type, AddEntitiesCallback async_add_entities)
Definition: utils.py:436
None async_add_insteon_entities(HomeAssistant hass, Platform platform, type[InsteonEntity] entity_type, AddEntitiesCallback async_add_entities, dict[str, Any] discovery_info)
Definition: utils.py:420
Callable[[], None] subscribe(HomeAssistant hass, str topic, MessageCallbackType msg_callback, int qos=DEFAULT_QOS, str encoding="utf-8")
Definition: client.py:247
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103