Home Assistant Unofficial Reference 2024.12.1
somfy_heating_temperature_interface.py
Go to the documentation of this file.
1 """Support for Somfy Heating Temperature Interface."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 from pyoverkiz.enums import OverkizCommand, OverkizCommandParam, OverkizState
8 
10  PRESET_AWAY,
11  PRESET_COMFORT,
12  PRESET_ECO,
13  PRESET_NONE,
14  ClimateEntity,
15  ClimateEntityFeature,
16  HVACAction,
17  HVACMode,
18 )
19 from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
20 
21 from ..coordinator import OverkizDataUpdateCoordinator
22 from ..entity import OverkizEntity
23 
24 OVERKIZ_TO_PRESET_MODES: dict[str, str] = {
25  OverkizCommandParam.SECURED: PRESET_AWAY,
26  OverkizCommandParam.ECO: PRESET_ECO,
27  OverkizCommandParam.COMFORT: PRESET_COMFORT,
28  OverkizCommandParam.FREE: PRESET_NONE,
29 }
30 
31 PRESET_MODES_TO_OVERKIZ = {v: k for k, v in OVERKIZ_TO_PRESET_MODES.items()}
32 
33 OVERKIZ_TO_HVAC_MODES: dict[str, HVACMode] = {
34  OverkizCommandParam.AUTO: HVACMode.AUTO,
35  OverkizCommandParam.MANU: HVACMode.HEAT_COOL,
36 }
37 
38 HVAC_MODES_TO_OVERKIZ = {v: k for k, v in OVERKIZ_TO_HVAC_MODES.items()}
39 
40 OVERKIZ_TO_HVAC_ACTION: dict[str, HVACAction] = {
41  OverkizCommandParam.COOLING: HVACAction.COOLING,
42  OverkizCommandParam.HEATING: HVACAction.HEATING,
43 }
44 
45 MAP_PRESET_TEMPERATURES: dict[str, str] = {
46  PRESET_COMFORT: OverkizState.CORE_COMFORT_ROOM_TEMPERATURE,
47  PRESET_ECO: OverkizState.CORE_ECO_ROOM_TEMPERATURE,
48  PRESET_AWAY: OverkizState.CORE_SECURED_POSITION_TEMPERATURE,
49 }
50 
51 SETPOINT_MODE_TO_OVERKIZ_COMMAND: dict[str, str] = {
52  OverkizCommandParam.COMFORT: OverkizCommand.SET_COMFORT_TEMPERATURE,
53  OverkizCommandParam.ECO: OverkizCommand.SET_ECO_TEMPERATURE,
54  OverkizCommandParam.SECURED: OverkizCommand.SET_SECURED_POSITION_TEMPERATURE,
55 }
56 
57 TEMPERATURE_SENSOR_DEVICE_INDEX = 2
58 
59 
61  """Representation of Somfy Heating Temperature Interface.
62 
63  The thermostat has 3 ways of working:
64  - Auto: Switch to eco/comfort temperature on a schedule (day/hour of the day)
65  - Manual comfort: The thermostat use the temperature of the comfort setting (19°C degree by default)
66  - Manual eco: The thermostat use the temperature of the eco setting (17°C by default)
67  - Freeze protection: The thermostat use the temperature of the freeze protection (7°C by default)
68 
69  There's also the possibility to change the working mode, this can be used to change from a heated
70  floor to a cooling floor in the summer.
71  """
72 
73  _attr_temperature_unit = UnitOfTemperature.CELSIUS
74  _attr_supported_features = (
75  ClimateEntityFeature.PRESET_MODE
76  | ClimateEntityFeature.TARGET_TEMPERATURE
77  | ClimateEntityFeature.TURN_OFF
78  | ClimateEntityFeature.TURN_ON
79  )
80  _attr_hvac_modes = [*HVAC_MODES_TO_OVERKIZ]
81  _attr_preset_modes = [*PRESET_MODES_TO_OVERKIZ]
82  # Both min and max temp values have been retrieved from the Somfy Application.
83  _attr_min_temp = 15.0
84  _attr_max_temp = 26.0
85  _enable_turn_on_off_backwards_compatibility = False
86 
87  def __init__(
88  self, device_url: str, coordinator: OverkizDataUpdateCoordinator
89  ) -> None:
90  """Init method."""
91  super().__init__(device_url, coordinator)
92  self.temperature_devicetemperature_device = self.executorexecutor.linked_device(
93  TEMPERATURE_SENSOR_DEVICE_INDEX
94  )
95 
96  @property
97  def hvac_mode(self) -> HVACMode:
98  """Return hvac operation i.e. heat, cool mode."""
99  state = self.devicedevice.states[OverkizState.CORE_ON_OFF]
100  if state and state.value_as_str == OverkizCommandParam.OFF:
101  return HVACMode.OFF
102 
103  if (
104  state := self.devicedevice.states[
105  OverkizState.OVP_HEATING_TEMPERATURE_INTERFACE_ACTIVE_MODE
106  ]
107  ) and state.value_as_str:
108  return OVERKIZ_TO_HVAC_MODES[state.value_as_str]
109 
110  return HVACMode.OFF
111 
112  async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
113  """Set new target hvac mode."""
114  await self.executorexecutor.async_execute_command(
115  OverkizCommand.SET_ACTIVE_MODE, HVAC_MODES_TO_OVERKIZ[hvac_mode]
116  )
117 
118  @property
119  def preset_mode(self) -> str | None:
120  """Return the current preset mode, e.g., home, away, temp."""
121  if (
122  state := self.devicedevice.states[
123  OverkizState.OVP_HEATING_TEMPERATURE_INTERFACE_SETPOINT_MODE
124  ]
125  ) and state.value_as_str:
126  return OVERKIZ_TO_PRESET_MODES[state.value_as_str]
127  return None
128 
129  async def async_set_preset_mode(self, preset_mode: str) -> None:
130  """Set new preset mode."""
131  await self.executorexecutor.async_execute_command(
132  OverkizCommand.SET_MANU_AND_SET_POINT_MODES,
133  PRESET_MODES_TO_OVERKIZ[preset_mode],
134  )
135 
136  @property
137  def hvac_action(self) -> HVACAction | None:
138  """Return the current running hvac operation if supported."""
139  if (
140  current_operation := self.devicedevice.states[
141  OverkizState.OVP_HEATING_TEMPERATURE_INTERFACE_OPERATING_MODE
142  ]
143  ) and current_operation.value_as_str:
144  return OVERKIZ_TO_HVAC_ACTION[current_operation.value_as_str]
145 
146  return None
147 
148  @property
149  def target_temperature(self) -> float | None:
150  """Return the target temperature."""
151 
152  # Allow to get the current target temperature for the current preset
153  # The preset can be switched manually or on a schedule (auto).
154  # This allows to reflect the current target temperature automatically
155  if not self.preset_modepreset_modepreset_mode:
156  return None
157 
158  mode = PRESET_MODES_TO_OVERKIZ[self.preset_modepreset_modepreset_mode]
159  if mode not in MAP_PRESET_TEMPERATURES:
160  return None
161 
162  if state := self.devicedevice.states[MAP_PRESET_TEMPERATURES[mode]]:
163  return state.value_as_float
164  return None
165 
166  @property
167  def current_temperature(self) -> float | None:
168  """Return the current temperature."""
169  if self.temperature_devicetemperature_device is not None and (
170  temperature := self.temperature_devicetemperature_device.states[OverkizState.CORE_TEMPERATURE]
171  ):
172  return temperature.value_as_float
173  return None
174 
175  async def async_set_temperature(self, **kwargs: Any) -> None:
176  """Set new temperature."""
177  temperature = kwargs[ATTR_TEMPERATURE]
178 
179  if (
180  mode := self.devicedevice.states[
181  OverkizState.OVP_HEATING_TEMPERATURE_INTERFACE_SETPOINT_MODE
182  ]
183  ) and mode.value_as_str:
184  await self.executorexecutor.async_execute_command(
185  SETPOINT_MODE_TO_OVERKIZ_COMMAND[mode.value_as_str], temperature
186  )
187  return