Home Assistant Unofficial Reference 2024.12.1
somfy_thermostat.py
Go to the documentation of this file.
1 """Support for Somfy Smart Thermostat."""
2 
3 from __future__ import annotations
4 
5 from typing import Any, cast
6 
7 from pyoverkiz.enums import OverkizCommand, OverkizCommandParam, OverkizState
8 
10  PRESET_AWAY,
11  PRESET_HOME,
12  PRESET_NONE,
13  ClimateEntity,
14  ClimateEntityFeature,
15  HVACMode,
16 )
17 from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
18 
19 from ..const import DOMAIN
20 from ..coordinator import OverkizDataUpdateCoordinator
21 from ..entity import OverkizEntity
22 
23 PRESET_FREEZE = "freeze"
24 PRESET_NIGHT = "night"
25 
26 
27 OVERKIZ_TO_HVAC_MODES: dict[str, HVACMode] = {
28  OverkizCommandParam.ACTIVE: HVACMode.HEAT,
29  OverkizCommandParam.INACTIVE: HVACMode.AUTO,
30 }
31 HVAC_MODES_TO_OVERKIZ = {v: k for k, v in OVERKIZ_TO_HVAC_MODES.items()}
32 
33 OVERKIZ_TO_PRESET_MODES: dict[OverkizCommandParam, str] = {
34  OverkizCommandParam.AT_HOME_MODE: PRESET_HOME,
35  OverkizCommandParam.AWAY_MODE: PRESET_AWAY,
36  OverkizCommandParam.FREEZE_MODE: PRESET_FREEZE,
37  OverkizCommandParam.GEOFENCING_MODE: PRESET_NONE,
38  OverkizCommandParam.MANUAL_MODE: PRESET_NONE,
39  OverkizCommandParam.SLEEPING_MODE: PRESET_NIGHT,
40  OverkizCommandParam.SUDDEN_DROP_MODE: PRESET_NONE,
41 }
42 
43 PRESET_MODES_TO_OVERKIZ = {v: k for k, v in OVERKIZ_TO_PRESET_MODES.items()}
44 TARGET_TEMP_TO_OVERKIZ = {
45  PRESET_HOME: OverkizState.SOMFY_THERMOSTAT_AT_HOME_TARGET_TEMPERATURE,
46  PRESET_AWAY: OverkizState.SOMFY_THERMOSTAT_AWAY_MODE_TARGET_TEMPERATURE,
47  PRESET_FREEZE: OverkizState.SOMFY_THERMOSTAT_FREEZE_MODE_TARGET_TEMPERATURE,
48  PRESET_NIGHT: OverkizState.SOMFY_THERMOSTAT_SLEEPING_MODE_TARGET_TEMPERATURE,
49 }
50 
51 # controllableName is somfythermostat:SomfyThermostatTemperatureSensor
52 TEMPERATURE_SENSOR_DEVICE_INDEX = 2
53 
54 
56  """Representation of Somfy Smart Thermostat."""
57 
58  _attr_temperature_unit = UnitOfTemperature.CELSIUS
59  _attr_supported_features = (
60  ClimateEntityFeature.PRESET_MODE
61  | ClimateEntityFeature.TARGET_TEMPERATURE
62  | ClimateEntityFeature.TURN_OFF
63  | ClimateEntityFeature.TURN_ON
64  )
65  _attr_hvac_modes = [*HVAC_MODES_TO_OVERKIZ]
66  _attr_preset_modes = [*PRESET_MODES_TO_OVERKIZ]
67  _attr_translation_key = DOMAIN
68  _enable_turn_on_off_backwards_compatibility = False
69 
70  # Both min and max temp values have been retrieved from the Somfy Application.
71  _attr_min_temp = 15.0
72  _attr_max_temp = 26.0
73 
74  def __init__(
75  self, device_url: str, coordinator: OverkizDataUpdateCoordinator
76  ) -> None:
77  """Init method."""
78  super().__init__(device_url, coordinator)
79  self.temperature_devicetemperature_device = self.executorexecutor.linked_device(
80  TEMPERATURE_SENSOR_DEVICE_INDEX
81  )
82 
83  @property
84  def hvac_mode(self) -> HVACMode:
85  """Return hvac operation ie. heat, cool mode."""
86  return OVERKIZ_TO_HVAC_MODES[
87  cast(
88  str, self.executorexecutor.select_state(OverkizState.CORE_DEROGATION_ACTIVATION)
89  )
90  ]
91 
92  @property
93  def preset_mode(self) -> str:
94  """Return the current preset mode, e.g., home, away, temp."""
95  if self.hvac_modehvac_modehvac_modehvac_modehvac_mode == HVACMode.AUTO:
96  state_key = OverkizState.SOMFY_THERMOSTAT_HEATING_MODE
97  else:
98  state_key = OverkizState.SOMFY_THERMOSTAT_DEROGATION_HEATING_MODE
99 
100  state = cast(str, self.executorexecutor.select_state(state_key))
101 
102  return OVERKIZ_TO_PRESET_MODES[OverkizCommandParam(state)]
103 
104  @property
105  def current_temperature(self) -> float | None:
106  """Return the current temperature."""
107  if self.temperature_devicetemperature_device is not None and (
108  temperature := self.temperature_devicetemperature_device.states[OverkizState.CORE_TEMPERATURE]
109  ):
110  return cast(float, temperature.value)
111  return None
112 
113  @property
114  def target_temperature(self) -> float | None:
115  """Return the temperature we try to reach."""
116  if self.hvac_modehvac_modehvac_modehvac_modehvac_mode == HVACMode.AUTO:
117  if self.preset_modepreset_modepreset_modepreset_mode == PRESET_NONE:
118  return None
119  return cast(
120  float,
121  self.executorexecutor.select_state(TARGET_TEMP_TO_OVERKIZ[self.preset_modepreset_modepreset_modepreset_mode]),
122  )
123  return cast(
124  float,
125  self.executorexecutor.select_state(OverkizState.CORE_DEROGATED_TARGET_TEMPERATURE),
126  )
127 
128  async def async_set_temperature(self, **kwargs: Any) -> None:
129  """Set new target temperature."""
130  temperature = kwargs[ATTR_TEMPERATURE]
131 
132  await self.executorexecutor.async_execute_command(
133  OverkizCommand.SET_DEROGATION,
134  temperature,
135  OverkizCommandParam.FURTHER_NOTICE,
136  )
137  await self.executorexecutor.async_execute_command(
138  OverkizCommand.SET_MODE_TEMPERATURE,
139  OverkizCommandParam.MANUAL_MODE,
140  temperature,
141  )
142  await self.executorexecutor.async_execute_command(OverkizCommand.REFRESH_STATE)
143 
144  async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
145  """Set new target hvac mode."""
146  if hvac_mode == HVACMode.AUTO:
147  await self.executorexecutor.async_execute_command(OverkizCommand.EXIT_DEROGATION)
148  await self.executorexecutor.async_execute_command(OverkizCommand.REFRESH_STATE)
149  else:
150  await self.async_set_preset_modeasync_set_preset_modeasync_set_preset_mode(PRESET_NONE)
151 
152  async def async_set_preset_mode(self, preset_mode: str) -> None:
153  """Set new preset mode."""
154  if preset_mode in [PRESET_FREEZE, PRESET_NIGHT, PRESET_AWAY, PRESET_HOME]:
155  await self.executorexecutor.async_execute_command(
156  OverkizCommand.SET_DEROGATION,
157  PRESET_MODES_TO_OVERKIZ[preset_mode],
158  OverkizCommandParam.FURTHER_NOTICE,
159  )
160  elif preset_mode == PRESET_NONE:
161  await self.executorexecutor.async_execute_command(
162  OverkizCommand.SET_DEROGATION,
163  self.target_temperaturetarget_temperaturetarget_temperature,
164  OverkizCommandParam.FURTHER_NOTICE,
165  )
166  await self.executorexecutor.async_execute_command(
167  OverkizCommand.SET_MODE_TEMPERATURE,
168  OverkizCommandParam.MANUAL_MODE,
169  self.target_temperaturetarget_temperaturetarget_temperature,
170  )
171  await self.executorexecutor.async_execute_command(OverkizCommand.REFRESH_STATE)
None async_set_preset_mode(self, str preset_mode)
Definition: __init__.py:861
None __init__(self, str device_url, OverkizDataUpdateCoordinator coordinator)