Home Assistant Unofficial Reference 2024.12.1
number.py
Go to the documentation of this file.
1 """Platform for Kostal Plenticore numbers."""
2 
3 from __future__ import annotations
4 
5 from dataclasses import dataclass
6 from datetime import timedelta
7 import logging
8 
9 from pykoplenti import SettingsData
10 
12  NumberDeviceClass,
13  NumberEntity,
14  NumberEntityDescription,
15  NumberMode,
16 )
17 from homeassistant.config_entries import ConfigEntry
18 from homeassistant.const import PERCENTAGE, EntityCategory, UnitOfPower
19 from homeassistant.core import HomeAssistant
20 from homeassistant.helpers.device_registry import DeviceInfo
21 from homeassistant.helpers.entity_platform import AddEntitiesCallback
22 from homeassistant.helpers.update_coordinator import CoordinatorEntity
23 
24 from .const import DOMAIN
25 from .coordinator import SettingDataUpdateCoordinator
26 from .helper import PlenticoreDataFormatter
27 
28 _LOGGER = logging.getLogger(__name__)
29 
30 
31 @dataclass(frozen=True, kw_only=True)
33  """Describes a Plenticore number entity."""
34 
35  module_id: str
36  data_id: str
37  fmt_from: str
38  fmt_to: str
39 
40 
41 NUMBER_SETTINGS_DATA = [
43  key="battery_min_soc",
44  entity_category=EntityCategory.CONFIG,
45  entity_registry_enabled_default=False,
46  icon="mdi:battery-negative",
47  name="Battery min SoC",
48  native_unit_of_measurement=PERCENTAGE,
49  native_max_value=100,
50  native_min_value=5,
51  native_step=5,
52  module_id="devices:local",
53  data_id="Battery:MinSoc",
54  fmt_from="format_round",
55  fmt_to="format_round_back",
56  ),
58  key="battery_min_home_consumption",
59  device_class=NumberDeviceClass.POWER,
60  entity_category=EntityCategory.CONFIG,
61  entity_registry_enabled_default=False,
62  name="Battery min Home Consumption",
63  native_unit_of_measurement=UnitOfPower.WATT,
64  native_max_value=38000,
65  native_min_value=50,
66  native_step=1,
67  module_id="devices:local",
68  data_id="Battery:MinHomeComsumption",
69  fmt_from="format_round",
70  fmt_to="format_round_back",
71  ),
72 ]
73 
74 
76  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
77 ) -> None:
78  """Add Kostal Plenticore Number entities."""
79  plenticore = hass.data[DOMAIN][entry.entry_id]
80 
81  entities = []
82 
83  available_settings_data = await plenticore.client.get_settings()
84  settings_data_update_coordinator = SettingDataUpdateCoordinator(
85  hass,
86  _LOGGER,
87  "Settings Data",
88  timedelta(seconds=30),
89  plenticore,
90  )
91 
92  for description in NUMBER_SETTINGS_DATA:
93  if (
94  description.module_id not in available_settings_data
95  or description.data_id
96  not in (
97  setting.id for setting in available_settings_data[description.module_id]
98  )
99  ):
100  _LOGGER.debug(
101  "Skipping non existing setting data %s/%s",
102  description.module_id,
103  description.data_id,
104  )
105  continue
106 
107  setting_data = next(
108  sd
109  for sd in available_settings_data[description.module_id]
110  if description.data_id == sd.id
111  )
112 
113  entities.append(
115  settings_data_update_coordinator,
116  entry.entry_id,
117  entry.title,
118  plenticore.device_info,
119  description,
120  setting_data,
121  )
122  )
123 
124  async_add_entities(entities)
125 
126 
128  CoordinatorEntity[SettingDataUpdateCoordinator], NumberEntity
129 ):
130  """Representation of a Kostal Plenticore Number entity."""
131 
132  entity_description: PlenticoreNumberEntityDescription
133 
134  def __init__(
135  self,
136  coordinator: SettingDataUpdateCoordinator,
137  entry_id: str,
138  platform_name: str,
139  device_info: DeviceInfo,
140  description: PlenticoreNumberEntityDescription,
141  setting_data: SettingsData,
142  ) -> None:
143  """Initialize the Plenticore Number entity."""
144  super().__init__(coordinator)
145 
146  self.entity_descriptionentity_description = description
147  self.entry_identry_id = entry_id
148 
149  self._attr_device_info_attr_device_info = device_info
150  self._attr_unique_id_attr_unique_id = f"{self.entry_id}_{self.module_id}_{self.data_id}"
151  self._attr_name_attr_name = f"{platform_name} {description.name}"
152  self._attr_mode_attr_mode = NumberMode.BOX
153 
154  self._formatter_formatter = PlenticoreDataFormatter.get_method(description.fmt_from)
155  self._formatter_back_formatter_back = PlenticoreDataFormatter.get_method(description.fmt_to)
156 
157  # overwrite from retrieved setting data
158  if setting_data.min is not None:
159  self._attr_native_min_value_attr_native_min_value = self._formatter_formatter(setting_data.min)
160  if setting_data.max is not None:
161  self._attr_native_max_value_attr_native_max_value = self._formatter_formatter(setting_data.max)
162 
163  @property
164  def module_id(self) -> str:
165  """Return the plenticore module id of this entity."""
166  return self.entity_descriptionentity_description.module_id
167 
168  @property
169  def data_id(self) -> str:
170  """Return the plenticore data id for this entity."""
171  return self.entity_descriptionentity_description.data_id
172 
173  @property
174  def available(self) -> bool:
175  """Return if entity is available."""
176  return (
177  super().available
178  and self.coordinator.data is not None
179  and self.module_idmodule_id in self.coordinator.data
180  and self.data_iddata_id in self.coordinator.data[self.module_idmodule_id]
181  )
182 
183  async def async_added_to_hass(self) -> None:
184  """Register this entity on the Update Coordinator."""
185  await super().async_added_to_hass()
186  self.async_on_removeasync_on_remove(
187  self.coordinator.start_fetch_data(self.module_idmodule_id, self.data_iddata_id)
188  )
189 
190  async def async_will_remove_from_hass(self) -> None:
191  """Unregister this entity from the Update Coordinator."""
192  self.coordinator.stop_fetch_data(self.module_idmodule_id, self.data_iddata_id)
193  await super().async_will_remove_from_hass()
194 
195  @property
196  def native_value(self) -> float | None:
197  """Return the current value."""
198  if self.availableavailableavailableavailable:
199  raw_value = self.coordinator.data[self.module_idmodule_id][self.data_iddata_id]
200  return self._formatter_formatter(raw_value)
201 
202  return None
203 
204  async def async_set_native_value(self, value: float) -> None:
205  """Set a new value."""
206  str_value = self._formatter_back_formatter_back(value)
207  await self.coordinator.async_write_data(
208  self.module_idmodule_id, {self.data_iddata_id: str_value}
209  )
210  await self.coordinator.async_refresh()
None __init__(self, SettingDataUpdateCoordinator coordinator, str entry_id, str platform_name, DeviceInfo device_info, PlenticoreNumberEntityDescription description, SettingsData setting_data)
Definition: number.py:142
None async_on_remove(self, CALLBACK_TYPE func)
Definition: entity.py:1331
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: number.py:77