Home Assistant Unofficial Reference 2024.12.1
number.py
Go to the documentation of this file.
1 """Support for Overkiz (virtual) numbers."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from collections.abc import Awaitable, Callable
7 from dataclasses import dataclass
8 from typing import cast
9 
10 from pyoverkiz.enums import OverkizCommand, OverkizCommandParam, OverkizState
11 
13  NumberDeviceClass,
14  NumberEntity,
15  NumberEntityDescription,
16 )
17 from homeassistant.config_entries import ConfigEntry
18 from homeassistant.const import EntityCategory, UnitOfTemperature
19 from homeassistant.core import HomeAssistant
20 from homeassistant.helpers.entity_platform import AddEntitiesCallback
21 
22 from . import HomeAssistantOverkizData
23 from .const import DOMAIN, IGNORED_OVERKIZ_DEVICES
24 from .coordinator import OverkizDataUpdateCoordinator
25 from .entity import OverkizDescriptiveEntity
26 
27 BOOST_MODE_DURATION_DELAY = 1
28 OPERATING_MODE_DELAY = 3
29 
30 
31 @dataclass(frozen=True, kw_only=True)
33  """Class to describe an Overkiz number."""
34 
35  command: str
36 
37  min_value_state_name: str | None = None
38  max_value_state_name: str | None = None
39  inverted: bool = False
40  set_native_value: (
41  Callable[[float, Callable[..., Awaitable[None]]], Awaitable[None]] | None
42  ) = None
43 
44 
46  value: float, execute_command: Callable[..., Awaitable[None]]
47 ) -> None:
48  """Update the boost duration value."""
49 
50  if value > 0:
51  await execute_command(OverkizCommand.SET_BOOST_MODE_DURATION, value)
52  await asyncio.sleep(
53  BOOST_MODE_DURATION_DELAY
54  ) # wait one second to not overload the device
55  await execute_command(
56  OverkizCommand.SET_CURRENT_OPERATING_MODE,
57  {
58  OverkizCommandParam.RELAUNCH: OverkizCommandParam.ON,
59  OverkizCommandParam.ABSENCE: OverkizCommandParam.OFF,
60  },
61  )
62  else:
63  await execute_command(
64  OverkizCommand.SET_CURRENT_OPERATING_MODE,
65  {
66  OverkizCommandParam.RELAUNCH: OverkizCommandParam.OFF,
67  OverkizCommandParam.ABSENCE: OverkizCommandParam.OFF,
68  },
69  )
70 
71  await asyncio.sleep(
72  OPERATING_MODE_DELAY
73  ) # wait 3 seconds to have the new duration in
74  await execute_command(OverkizCommand.REFRESH_BOOST_MODE_DURATION)
75 
76 
77 NUMBER_DESCRIPTIONS: list[OverkizNumberDescription] = [
78  # Cover: My Position (0 - 100)
80  key=OverkizState.CORE_MEMORIZED_1_POSITION,
81  name="My position",
82  icon="mdi:content-save-cog",
83  command=OverkizCommand.SET_MEMORIZED_1_POSITION,
84  native_min_value=0,
85  native_max_value=100,
86  entity_category=EntityCategory.CONFIG,
87  ),
88  # WaterHeater: Expected Number Of Shower (2 - 4)
90  key=OverkizState.CORE_EXPECTED_NUMBER_OF_SHOWER,
91  name="Expected number of shower",
92  icon="mdi:shower-head",
93  command=OverkizCommand.SET_EXPECTED_NUMBER_OF_SHOWER,
94  native_min_value=2,
95  native_max_value=4,
96  min_value_state_name=OverkizState.CORE_MINIMAL_SHOWER_MANUAL_MODE,
97  max_value_state_name=OverkizState.CORE_MAXIMAL_SHOWER_MANUAL_MODE,
98  entity_category=EntityCategory.CONFIG,
99  ),
101  key=OverkizState.CORE_TARGET_DWH_TEMPERATURE,
102  name="Target temperature",
103  device_class=NumberDeviceClass.TEMPERATURE,
104  command=OverkizCommand.SET_TARGET_DHW_TEMPERATURE,
105  native_min_value=50,
106  native_max_value=65,
107  min_value_state_name=OverkizState.CORE_MINIMAL_TEMPERATURE_MANUAL_MODE,
108  max_value_state_name=OverkizState.CORE_MAXIMAL_TEMPERATURE_MANUAL_MODE,
109  entity_category=EntityCategory.CONFIG,
110  ),
112  key=OverkizState.CORE_WATER_TARGET_TEMPERATURE,
113  name="Water target temperature",
114  device_class=NumberDeviceClass.TEMPERATURE,
115  command=OverkizCommand.SET_WATER_TARGET_TEMPERATURE,
116  native_min_value=50,
117  native_max_value=65,
118  min_value_state_name=OverkizState.CORE_MINIMAL_TEMPERATURE_MANUAL_MODE,
119  max_value_state_name=OverkizState.CORE_MAXIMAL_TEMPERATURE_MANUAL_MODE,
120  entity_category=EntityCategory.CONFIG,
121  ),
122  # SomfyHeatingTemperatureInterface
124  key=OverkizState.CORE_ECO_ROOM_TEMPERATURE,
125  name="Eco room temperature",
126  icon="mdi:thermometer",
127  command=OverkizCommand.SET_ECO_TEMPERATURE,
128  device_class=NumberDeviceClass.TEMPERATURE,
129  native_min_value=6,
130  native_max_value=29,
131  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
132  entity_category=EntityCategory.CONFIG,
133  ),
135  key=OverkizState.CORE_COMFORT_ROOM_TEMPERATURE,
136  name="Comfort room temperature",
137  icon="mdi:home-thermometer-outline",
138  command=OverkizCommand.SET_COMFORT_TEMPERATURE,
139  device_class=NumberDeviceClass.TEMPERATURE,
140  native_min_value=7,
141  native_max_value=30,
142  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
143  entity_category=EntityCategory.CONFIG,
144  ),
146  key=OverkizState.CORE_SECURED_POSITION_TEMPERATURE,
147  name="Freeze protection temperature",
148  icon="mdi:sun-thermometer-outline",
149  command=OverkizCommand.SET_SECURED_POSITION_TEMPERATURE,
150  device_class=NumberDeviceClass.TEMPERATURE,
151  native_min_value=5,
152  native_max_value=15,
153  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
154  entity_category=EntityCategory.CONFIG,
155  ),
156  # DimmerExteriorHeating (Somfy Terrace Heater) (0 - 100)
157  # Needs to be inverted since 100 = off, 0 = on
159  key=OverkizState.CORE_LEVEL,
160  icon="mdi:patio-heater",
161  command=OverkizCommand.SET_LEVEL,
162  native_min_value=0,
163  native_max_value=100,
164  inverted=True,
165  ),
166  # DomesticHotWaterProduction - boost mode duration in days (0 - 7)
168  key=OverkizState.CORE_BOOST_MODE_DURATION,
169  name="Boost mode duration",
170  icon="mdi:water-boiler",
171  command=OverkizCommand.SET_BOOST_MODE_DURATION,
172  native_min_value=0,
173  native_max_value=7,
174  set_native_value=_async_set_native_value_boost_mode_duration,
175  entity_category=EntityCategory.CONFIG,
176  ),
177  # DomesticHotWaterProduction - away mode in days (0 - 6)
179  key=OverkizState.IO_AWAY_MODE_DURATION,
180  name="Away mode duration",
181  icon="mdi:water-boiler-off",
182  command=OverkizCommand.SET_AWAY_MODE_DURATION,
183  native_min_value=0,
184  native_max_value=6,
185  entity_category=EntityCategory.CONFIG,
186  ),
187 ]
188 
189 SUPPORTED_STATES = {description.key: description for description in NUMBER_DESCRIPTIONS}
190 
191 
193  hass: HomeAssistant,
194  entry: ConfigEntry,
195  async_add_entities: AddEntitiesCallback,
196 ) -> None:
197  """Set up the Overkiz number from a config entry."""
198  data: HomeAssistantOverkizData = hass.data[DOMAIN][entry.entry_id]
199  entities: list[OverkizNumber] = []
200 
201  for device in data.coordinator.data.values():
202  if (
203  device.widget in IGNORED_OVERKIZ_DEVICES
204  or device.ui_class in IGNORED_OVERKIZ_DEVICES
205  ):
206  continue
207 
208  entities.extend(
210  device.device_url,
211  data.coordinator,
212  description,
213  )
214  for state in device.definition.states
215  if (description := SUPPORTED_STATES.get(state.qualified_name))
216  )
217 
218  async_add_entities(entities)
219 
220 
222  """Representation of an Overkiz Number."""
223 
224  entity_description: OverkizNumberDescription
225 
226  def __init__(
227  self,
228  device_url: str,
229  coordinator: OverkizDataUpdateCoordinator,
230  description: OverkizNumberDescription,
231  ) -> None:
232  """Initialize a device."""
233  super().__init__(device_url, coordinator, description)
234 
235  if self.entity_descriptionentity_description.min_value_state_name and (
236  state := self.devicedevice.states.get(
237  self.entity_descriptionentity_description.min_value_state_name
238  )
239  ):
240  self._attr_native_min_value_attr_native_min_value = cast(float, state.value)
241 
242  if self.entity_descriptionentity_description.max_value_state_name and (
243  state := self.devicedevice.states.get(
244  self.entity_descriptionentity_description.max_value_state_name
245  )
246  ):
247  self._attr_native_max_value_attr_native_max_value = cast(float, state.value)
248 
249  @property
250  def native_value(self) -> float | None:
251  """Return the entity value to represent the entity state."""
252  if state := self.devicedevice.states.get(self.entity_descriptionentity_description.key):
253  if self.entity_descriptionentity_description.inverted:
254  return self.native_max_valuenative_max_value - cast(float, state.value)
255 
256  return cast(float, state.value)
257 
258  return None
259 
260  async def async_set_native_value(self, value: float) -> None:
261  """Set new value."""
262  if self.entity_descriptionentity_description.inverted:
263  value = self.native_max_valuenative_max_value - value
264 
265  if self.entity_descriptionentity_description.set_native_value:
266  await self.entity_descriptionentity_description.set_native_value(
267  value, self.executorexecutor.async_execute_command
268  )
269  return
270 
271  await self.executorexecutor.async_execute_command(
272  self.entity_descriptionentity_description.command, value
273  )
None set_native_value(self, float value)
Definition: __init__.py:414
None __init__(self, str device_url, OverkizDataUpdateCoordinator coordinator, OverkizNumberDescription description)
Definition: number.py:231
None _async_set_native_value_boost_mode_duration(float value, Callable[..., Awaitable[None]] execute_command)
Definition: number.py:47
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: number.py:196