Home Assistant Unofficial Reference 2024.12.1
climate.py
Go to the documentation of this file.
1 """MySensors platform that offers a Climate (MySensors-HVAC) component."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
8  ATTR_TARGET_TEMP_HIGH,
9  ATTR_TARGET_TEMP_LOW,
10  ClimateEntity,
11  ClimateEntityFeature,
12  HVACMode,
13 )
14 from homeassistant.config_entries import ConfigEntry
15 from homeassistant.const import ATTR_TEMPERATURE, Platform, UnitOfTemperature
16 from homeassistant.core import HomeAssistant, callback
17 from homeassistant.helpers.dispatcher import async_dispatcher_connect
18 from homeassistant.helpers.entity_platform import AddEntitiesCallback
19 from homeassistant.util.unit_system import METRIC_SYSTEM
20 
21 from . import setup_mysensors_platform
22 from .const import MYSENSORS_DISCOVERY, DiscoveryInfo
23 from .entity import MySensorsChildEntity
24 from .helpers import on_unload
25 
26 DICT_HA_TO_MYS = {
27  HVACMode.AUTO: "AutoChangeOver",
28  HVACMode.COOL: "CoolOn",
29  HVACMode.HEAT: "HeatOn",
30  HVACMode.OFF: "Off",
31 }
32 DICT_MYS_TO_HA = {
33  "AutoChangeOver": HVACMode.AUTO,
34  "CoolOn": HVACMode.COOL,
35  "HeatOn": HVACMode.HEAT,
36  "Off": HVACMode.OFF,
37 }
38 
39 FAN_LIST = ["Auto", "Min", "Normal", "Max"]
40 OPERATION_LIST = [HVACMode.OFF, HVACMode.AUTO, HVACMode.COOL, HVACMode.HEAT]
41 
42 
44  hass: HomeAssistant,
45  config_entry: ConfigEntry,
46  async_add_entities: AddEntitiesCallback,
47 ) -> None:
48  """Set up this platform for a specific ConfigEntry(==Gateway)."""
49 
50  async def async_discover(discovery_info: DiscoveryInfo) -> None:
51  """Discover and add a MySensors climate."""
53  hass,
54  Platform.CLIMATE,
55  discovery_info,
56  MySensorsHVAC,
57  async_add_entities=async_add_entities,
58  )
59 
60  on_unload(
61  hass,
62  config_entry.entry_id,
64  hass,
65  MYSENSORS_DISCOVERY.format(config_entry.entry_id, Platform.CLIMATE),
66  async_discover,
67  ),
68  )
69 
70 
72  """Representation of a MySensors HVAC."""
73 
74  _attr_hvac_modes = OPERATION_LIST
75  _enable_turn_on_off_backwards_compatibility = False
76 
77  @property
78  def supported_features(self) -> ClimateEntityFeature:
79  """Return the list of supported features."""
80  features = ClimateEntityFeature.TURN_OFF | ClimateEntityFeature.TURN_ON
81  set_req = self.gateway.const.SetReq
82  if set_req.V_HVAC_SPEED in self._values:
83  features = features | ClimateEntityFeature.FAN_MODE
84  if (
85  set_req.V_HVAC_SETPOINT_COOL in self._values
86  and set_req.V_HVAC_SETPOINT_HEAT in self._values
87  ):
88  features = features | ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
89  else:
90  features = features | ClimateEntityFeature.TARGET_TEMPERATURE
91  return features
92 
93  @property
94  def temperature_unit(self) -> str:
95  """Return the unit of measurement."""
96  return (
97  UnitOfTemperature.CELSIUS
98  if self.hasshass.config.units is METRIC_SYSTEM
99  else UnitOfTemperature.FAHRENHEIT
100  )
101 
102  @property
103  def current_temperature(self) -> float | None:
104  """Return the current temperature."""
105  value: str | None = self._values.get(self.gateway.const.SetReq.V_TEMP)
106  float_value: float | None = None
107 
108  if value is not None:
109  float_value = float(value)
110 
111  return float_value
112 
113  @property
114  def target_temperature(self) -> float | None:
115  """Return the temperature we try to reach."""
116  set_req = self.gateway.const.SetReq
117  if (
118  set_req.V_HVAC_SETPOINT_COOL in self._values
119  and set_req.V_HVAC_SETPOINT_HEAT in self._values
120  ):
121  return None
122  temp = self._values.get(set_req.V_HVAC_SETPOINT_COOL)
123  if temp is None:
124  temp = self._values.get(set_req.V_HVAC_SETPOINT_HEAT)
125  return float(temp) if temp is not None else None
126 
127  @property
128  def target_temperature_high(self) -> float | None:
129  """Return the highbound target temperature we try to reach."""
130  set_req = self.gateway.const.SetReq
131  if set_req.V_HVAC_SETPOINT_HEAT in self._values:
132  temp = self._values.get(set_req.V_HVAC_SETPOINT_COOL)
133  return float(temp) if temp is not None else None
134 
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  set_req = self.gateway.const.SetReq
141  if set_req.V_HVAC_SETPOINT_COOL in self._values:
142  temp = self._values.get(set_req.V_HVAC_SETPOINT_HEAT)
143  return float(temp) if temp is not None else None
144 
145  return None
146 
147  @property
148  def hvac_mode(self) -> HVACMode:
149  """Return current operation ie. heat, cool, idle."""
150  return self._values.get(self.value_type, HVACMode.HEAT) # type: ignore[no-any-return]
151 
152  @property
153  def fan_mode(self) -> str | None:
154  """Return the fan setting."""
155  return self._values.get(self.gateway.const.SetReq.V_HVAC_SPEED)
156 
157  @property
158  def fan_modes(self) -> list[str]:
159  """List of available fan modes."""
160  return FAN_LIST
161 
162  async def async_set_temperature(self, **kwargs: Any) -> None:
163  """Set new target temperature."""
164  set_req = self.gateway.const.SetReq
165  temp = kwargs.get(ATTR_TEMPERATURE)
166  low = kwargs.get(ATTR_TARGET_TEMP_LOW)
167  high = kwargs.get(ATTR_TARGET_TEMP_HIGH)
168  heat = self._values.get(set_req.V_HVAC_SETPOINT_HEAT)
169  cool = self._values.get(set_req.V_HVAC_SETPOINT_COOL)
170  updates = []
171  if temp is not None:
172  if heat is not None:
173  # Set HEAT Target temperature
174  value_type = set_req.V_HVAC_SETPOINT_HEAT
175  elif cool is not None:
176  # Set COOL Target temperature
177  value_type = set_req.V_HVAC_SETPOINT_COOL
178  if heat is not None or cool is not None:
179  updates = [(value_type, temp)]
180  elif all(val is not None for val in (low, high, heat, cool)):
181  updates = [
182  (set_req.V_HVAC_SETPOINT_HEAT, low),
183  (set_req.V_HVAC_SETPOINT_COOL, high),
184  ]
185  for value_type, value in updates:
186  self.gateway.set_child_value(
187  self.node_id, self.child_id, value_type, value, ack=1
188  )
189  if self.assumed_stateassumed_state:
190  # Optimistically assume that device has changed state
191  self._values[value_type] = value
192  self.async_write_ha_stateasync_write_ha_state()
193 
194  async def async_set_fan_mode(self, fan_mode: str) -> None:
195  """Set new target temperature."""
196  set_req = self.gateway.const.SetReq
197  self.gateway.set_child_value(
198  self.node_id, self.child_id, set_req.V_HVAC_SPEED, fan_mode, ack=1
199  )
200  if self.assumed_stateassumed_state:
201  # Optimistically assume that device has changed state
202  self._values[set_req.V_HVAC_SPEED] = fan_mode
203  self.async_write_ha_stateasync_write_ha_state()
204 
205  async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
206  """Set new target temperature."""
207  self.gateway.set_child_value(
208  self.node_id,
209  self.child_id,
210  self.value_type,
211  DICT_HA_TO_MYS[hvac_mode],
212  ack=1,
213  )
214  if self.assumed_stateassumed_state:
215  # Optimistically assume that device has changed state
216  self._values[self.value_type] = hvac_mode
217  self.async_write_ha_stateasync_write_ha_state()
218 
219  @callback
220  def _async_update(self) -> None:
221  """Update the controller with the latest value from a sensor."""
222  super()._async_update()
223  self._values[self.value_type] = DICT_MYS_TO_HA[self._values[self.value_type]]
None async_set_hvac_mode(self, HVACMode hvac_mode)
Definition: climate.py:205
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: climate.py:47
None on_unload(HomeAssistant hass, GatewayId gateway_id, Callable fnct)
Definition: helpers.py:45
None async_discover(DiscoveryInfo discovery_info)
Definition: sensor.py:217
list[MySensorsChildEntity]|None setup_mysensors_platform(HomeAssistant hass, Platform domain, DiscoveryInfo discovery_info, type[MySensorsChildEntity]|Mapping[SensorType, type[MySensorsChildEntity]] device_class,(tuple|None) device_args=None, Callable|None async_add_entities=None)
Definition: __init__.py:112
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103