Home Assistant Unofficial Reference 2024.12.1
number.py
Go to the documentation of this file.
1 """Creates the number entities for the mower."""
2 
3 from collections.abc import Awaitable, Callable
4 from dataclasses import dataclass
5 import logging
6 from typing import TYPE_CHECKING, Any
7 
8 from aioautomower.model import MowerAttributes, WorkArea
9 from aioautomower.session import AutomowerSession
10 
11 from homeassistant.components.number import NumberEntity, NumberEntityDescription
12 from homeassistant.const import PERCENTAGE, EntityCategory
13 from homeassistant.core import HomeAssistant, callback
14 from homeassistant.helpers.entity_platform import AddEntitiesCallback
15 
16 from . import AutomowerConfigEntry, remove_work_area_entities
17 from .coordinator import AutomowerDataUpdateCoordinator
18 from .entity import (
19  AutomowerControlEntity,
20  WorkAreaControlEntity,
21  _work_area_translation_key,
22  handle_sending_exception,
23 )
24 
25 _LOGGER = logging.getLogger(__name__)
26 
27 PARALLEL_UPDATES = 1
28 
29 
30 @callback
31 def _async_get_cutting_height(data: MowerAttributes) -> int:
32  """Return the cutting height."""
33  if TYPE_CHECKING:
34  # Sensor does not get created if it is None
35  assert data.settings.cutting_height is not None
36  return data.settings.cutting_height
37 
38 
40  coordinator: AutomowerDataUpdateCoordinator,
41  mower_id: str,
42  cheight: float,
43  work_area_id: int,
44 ) -> None:
45  """Set cutting height for work area."""
46  await coordinator.api.commands.workarea_settings(
47  mower_id, int(cheight), work_area_id
48  )
49 
50 
52  session: AutomowerSession,
53  mower_id: str,
54  cheight: float,
55 ) -> None:
56  """Set cutting height."""
57  await session.commands.set_cutting_height(mower_id, int(cheight))
58 
59 
60 @dataclass(frozen=True, kw_only=True)
62  """Describes Automower number entity."""
63 
64  exists_fn: Callable[[MowerAttributes], bool] = lambda _: True
65  value_fn: Callable[[MowerAttributes], int]
66  set_value_fn: Callable[[AutomowerSession, str, float], Awaitable[Any]]
67 
68 
69 MOWER_NUMBER_TYPES: tuple[AutomowerNumberEntityDescription, ...] = (
71  key="cutting_height",
72  translation_key="cutting_height",
73  entity_registry_enabled_default=False,
74  entity_category=EntityCategory.CONFIG,
75  native_min_value=1,
76  native_max_value=9,
77  exists_fn=lambda data: data.settings.cutting_height is not None,
78  value_fn=_async_get_cutting_height,
79  set_value_fn=async_set_cutting_height,
80  ),
81 )
82 
83 
84 @dataclass(frozen=True, kw_only=True)
86  """Describes Automower work area number entity."""
87 
88  value_fn: Callable[[WorkArea], int]
89  translation_key_fn: Callable[[int, str], str]
90  set_value_fn: Callable[
91  [AutomowerDataUpdateCoordinator, str, float, int], Awaitable[Any]
92  ]
93 
94 
95 WORK_AREA_NUMBER_TYPES: tuple[WorkAreaNumberEntityDescription, ...] = (
97  key="cutting_height_work_area",
98  translation_key_fn=_work_area_translation_key,
99  entity_category=EntityCategory.CONFIG,
100  native_unit_of_measurement=PERCENTAGE,
101  value_fn=lambda data: data.cutting_height,
102  set_value_fn=async_set_work_area_cutting_height,
103  ),
104 )
105 
106 
108  hass: HomeAssistant,
109  entry: AutomowerConfigEntry,
110  async_add_entities: AddEntitiesCallback,
111 ) -> None:
112  """Set up number platform."""
113  coordinator = entry.runtime_data
114  current_work_areas: dict[str, set[int]] = {}
115 
117  AutomowerNumberEntity(mower_id, coordinator, description)
118  for mower_id in coordinator.data
119  for description in MOWER_NUMBER_TYPES
120  if description.exists_fn(coordinator.data[mower_id])
121  )
122 
123  def _async_work_area_listener() -> None:
124  """Listen for new work areas and add/remove entities as needed."""
125  for mower_id in coordinator.data:
126  if (
127  coordinator.data[mower_id].capabilities.work_areas
128  and (_work_areas := coordinator.data[mower_id].work_areas) is not None
129  ):
130  received_work_areas = set(_work_areas.keys())
131  current_work_area_set = current_work_areas.setdefault(mower_id, set())
132 
133  new_work_areas = received_work_areas - current_work_area_set
134  removed_work_areas = current_work_area_set - received_work_areas
135 
136  if new_work_areas:
137  current_work_area_set.update(new_work_areas)
140  mower_id, coordinator, description, work_area_id
141  )
142  for description in WORK_AREA_NUMBER_TYPES
143  for work_area_id in new_work_areas
144  )
145 
146  if removed_work_areas:
147  remove_work_area_entities(hass, entry, removed_work_areas, mower_id)
148  current_work_area_set.difference_update(removed_work_areas)
149 
150  coordinator.async_add_listener(_async_work_area_listener)
151  _async_work_area_listener()
152 
153 
155  """Defining the AutomowerNumberEntity with AutomowerNumberEntityDescription."""
156 
157  entity_description: AutomowerNumberEntityDescription
158 
159  def __init__(
160  self,
161  mower_id: str,
162  coordinator: AutomowerDataUpdateCoordinator,
163  description: AutomowerNumberEntityDescription,
164  ) -> None:
165  """Set up AutomowerNumberEntity."""
166  super().__init__(mower_id, coordinator)
167  self.entity_descriptionentity_description = description
168  self._attr_unique_id_attr_unique_id = f"{mower_id}_{description.key}"
169 
170  @property
171  def native_value(self) -> float:
172  """Return the state of the number."""
173  return self.entity_descriptionentity_description.value_fn(self.mower_attributesmower_attributes)
174 
175  @handle_sending_exception()
176  async def async_set_native_value(self, value: float) -> None:
177  """Change to new number value."""
178  await self.entity_descriptionentity_description.set_value_fn(
179  self.coordinator.api, self.mower_idmower_id, value
180  )
181 
182 
184  """Defining the WorkAreaNumberEntity with WorkAreaNumberEntityDescription."""
185 
186  entity_description: WorkAreaNumberEntityDescription
187 
188  def __init__(
189  self,
190  mower_id: str,
191  coordinator: AutomowerDataUpdateCoordinator,
192  description: WorkAreaNumberEntityDescription,
193  work_area_id: int,
194  ) -> None:
195  """Set up AutomowerNumberEntity."""
196  super().__init__(mower_id, coordinator, work_area_id)
197  self.entity_descriptionentity_description = description
198  self._attr_unique_id_attr_unique_id = f"{mower_id}_{work_area_id}_{description.key}"
199  self._attr_translation_placeholders_attr_translation_placeholders = {
200  "work_area": self.work_area_attributeswork_area_attributes.name
201  }
202 
203  @property
204  def translation_key(self) -> str:
205  """Return the translation key of the work area."""
206  return self.entity_descriptionentity_description.translation_key_fn(
207  self.work_area_idwork_area_id, self.entity_descriptionentity_description.key
208  )
209 
210  @property
211  def native_value(self) -> float:
212  """Return the state of the number."""
213  return self.entity_descriptionentity_description.value_fn(self.work_area_attributeswork_area_attributes)
214 
215  @handle_sending_exception(poll_after_sending=True)
216  async def async_set_native_value(self, value: float) -> None:
217  """Change to new number value."""
218  await self.entity_descriptionentity_description.set_value_fn(
219  self.coordinator, self.mower_idmower_id, value, self.work_area_idwork_area_id
220  )
None __init__(self, str mower_id, AutomowerDataUpdateCoordinator coordinator, AutomowerNumberEntityDescription description)
Definition: number.py:164
None __init__(self, str mower_id, AutomowerDataUpdateCoordinator coordinator, WorkAreaNumberEntityDescription description, int work_area_id)
Definition: number.py:194
int _async_get_cutting_height(MowerAttributes data)
Definition: number.py:31
None async_set_cutting_height(AutomowerSession session, str mower_id, float cheight)
Definition: number.py:55
None async_setup_entry(HomeAssistant hass, AutomowerConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: number.py:111
None async_set_work_area_cutting_height(AutomowerDataUpdateCoordinator coordinator, str mower_id, float cheight, int work_area_id)
Definition: number.py:44
None remove_work_area_entities(HomeAssistant hass, ConfigEntry config_entry, set[int] removed_work_areas, str mower_id)
Definition: __init__.py:110