Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """SFR Box sensor platform."""
2 
3 from collections.abc import Callable
4 from dataclasses import dataclass
5 from typing import TYPE_CHECKING
6 
7 from sfrbox_api.models import DslInfo, SystemInfo, WanInfo
8 
10  SensorDeviceClass,
11  SensorEntity,
12  SensorEntityDescription,
13  SensorStateClass,
14 )
15 from homeassistant.config_entries import ConfigEntry
16 from homeassistant.const import (
17  SIGNAL_STRENGTH_DECIBELS,
18  EntityCategory,
19  UnitOfDataRate,
20  UnitOfElectricPotential,
21  UnitOfTemperature,
22 )
23 from homeassistant.core import HomeAssistant
24 from homeassistant.helpers.device_registry import DeviceInfo
25 from homeassistant.helpers.entity_platform import AddEntitiesCallback
26 from homeassistant.helpers.typing import StateType
27 from homeassistant.helpers.update_coordinator import CoordinatorEntity
28 
29 from .const import DOMAIN
30 from .coordinator import SFRDataUpdateCoordinator
31 from .models import DomainData
32 
33 
34 @dataclass(frozen=True, kw_only=True)
35 class SFRBoxSensorEntityDescription[_T](SensorEntityDescription):
36  """Description for SFR Box sensors."""
37 
38  value_fn: Callable[[_T], StateType]
39 
40 
41 DSL_SENSOR_TYPES: tuple[SFRBoxSensorEntityDescription[DslInfo], ...] = (
42  SFRBoxSensorEntityDescription[DslInfo](
43  key="linemode",
44  entity_category=EntityCategory.DIAGNOSTIC,
45  entity_registry_enabled_default=False,
46  translation_key="dsl_linemode",
47  value_fn=lambda x: x.linemode,
48  ),
49  SFRBoxSensorEntityDescription[DslInfo](
50  key="counter",
51  entity_category=EntityCategory.DIAGNOSTIC,
52  entity_registry_enabled_default=False,
53  translation_key="dsl_counter",
54  value_fn=lambda x: x.counter,
55  ),
56  SFRBoxSensorEntityDescription[DslInfo](
57  key="crc",
58  entity_category=EntityCategory.DIAGNOSTIC,
59  entity_registry_enabled_default=False,
60  translation_key="dsl_crc",
61  value_fn=lambda x: x.crc,
62  ),
63  SFRBoxSensorEntityDescription[DslInfo](
64  key="noise_down",
65  device_class=SensorDeviceClass.SIGNAL_STRENGTH,
66  entity_category=EntityCategory.DIAGNOSTIC,
67  entity_registry_enabled_default=False,
68  native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS,
69  state_class=SensorStateClass.MEASUREMENT,
70  translation_key="dsl_noise_down",
71  value_fn=lambda x: x.noise_down,
72  ),
73  SFRBoxSensorEntityDescription[DslInfo](
74  key="noise_up",
75  device_class=SensorDeviceClass.SIGNAL_STRENGTH,
76  entity_category=EntityCategory.DIAGNOSTIC,
77  entity_registry_enabled_default=False,
78  native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS,
79  state_class=SensorStateClass.MEASUREMENT,
80  translation_key="dsl_noise_up",
81  value_fn=lambda x: x.noise_up,
82  ),
83  SFRBoxSensorEntityDescription[DslInfo](
84  key="attenuation_down",
85  device_class=SensorDeviceClass.SIGNAL_STRENGTH,
86  entity_category=EntityCategory.DIAGNOSTIC,
87  entity_registry_enabled_default=False,
88  native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS,
89  state_class=SensorStateClass.MEASUREMENT,
90  translation_key="dsl_attenuation_down",
91  value_fn=lambda x: x.attenuation_down,
92  ),
93  SFRBoxSensorEntityDescription[DslInfo](
94  key="attenuation_up",
95  device_class=SensorDeviceClass.SIGNAL_STRENGTH,
96  entity_category=EntityCategory.DIAGNOSTIC,
97  entity_registry_enabled_default=False,
98  native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS,
99  state_class=SensorStateClass.MEASUREMENT,
100  translation_key="dsl_attenuation_up",
101  value_fn=lambda x: x.attenuation_up,
102  ),
103  SFRBoxSensorEntityDescription[DslInfo](
104  key="rate_down",
105  device_class=SensorDeviceClass.DATA_RATE,
106  native_unit_of_measurement=UnitOfDataRate.KILOBITS_PER_SECOND,
107  state_class=SensorStateClass.MEASUREMENT,
108  translation_key="dsl_rate_down",
109  value_fn=lambda x: x.rate_down,
110  ),
111  SFRBoxSensorEntityDescription[DslInfo](
112  key="rate_up",
113  device_class=SensorDeviceClass.DATA_RATE,
114  native_unit_of_measurement=UnitOfDataRate.KILOBITS_PER_SECOND,
115  state_class=SensorStateClass.MEASUREMENT,
116  translation_key="dsl_rate_up",
117  value_fn=lambda x: x.rate_up,
118  ),
119  SFRBoxSensorEntityDescription[DslInfo](
120  key="line_status",
121  device_class=SensorDeviceClass.ENUM,
122  entity_category=EntityCategory.DIAGNOSTIC,
123  entity_registry_enabled_default=False,
124  options=[
125  "no_defect",
126  "of_frame",
127  "loss_of_signal",
128  "loss_of_power",
129  "loss_of_signal_quality",
130  "unknown",
131  ],
132  translation_key="dsl_line_status",
133  value_fn=lambda x: _value_to_option(x.line_status),
134  ),
135  SFRBoxSensorEntityDescription[DslInfo](
136  key="training",
137  device_class=SensorDeviceClass.ENUM,
138  entity_category=EntityCategory.DIAGNOSTIC,
139  entity_registry_enabled_default=False,
140  options=[
141  "idle",
142  "g_994_training",
143  "g_992_started",
144  "g_922_channel_analysis",
145  "g_992_message_exchange",
146  "g_993_started",
147  "g_993_channel_analysis",
148  "g_993_message_exchange",
149  "showtime",
150  "unknown",
151  ],
152  translation_key="dsl_training",
153  value_fn=lambda x: _value_to_option(x.training),
154  ),
155 )
156 SYSTEM_SENSOR_TYPES: tuple[SFRBoxSensorEntityDescription[SystemInfo], ...] = (
157  SFRBoxSensorEntityDescription[SystemInfo](
158  key="net_infra",
159  device_class=SensorDeviceClass.ENUM,
160  entity_category=EntityCategory.DIAGNOSTIC,
161  entity_registry_enabled_default=False,
162  options=[
163  "adsl",
164  "ftth",
165  "gprs",
166  "unknown",
167  ],
168  translation_key="net_infra",
169  value_fn=lambda x: x.net_infra,
170  ),
171  SFRBoxSensorEntityDescription[SystemInfo](
172  key="alimvoltage",
173  device_class=SensorDeviceClass.VOLTAGE,
174  entity_category=EntityCategory.DIAGNOSTIC,
175  entity_registry_enabled_default=False,
176  native_unit_of_measurement=UnitOfElectricPotential.MILLIVOLT,
177  value_fn=lambda x: x.alimvoltage,
178  ),
179  SFRBoxSensorEntityDescription[SystemInfo](
180  key="temperature",
181  device_class=SensorDeviceClass.TEMPERATURE,
182  entity_category=EntityCategory.DIAGNOSTIC,
183  entity_registry_enabled_default=False,
184  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
185  value_fn=lambda x: _get_temperature(x.temperature),
186  ),
187 )
188 WAN_SENSOR_TYPES: tuple[SFRBoxSensorEntityDescription[WanInfo], ...] = (
189  SFRBoxSensorEntityDescription[WanInfo](
190  key="mode",
191  device_class=SensorDeviceClass.ENUM,
192  entity_category=EntityCategory.DIAGNOSTIC,
193  entity_registry_enabled_default=False,
194  options=[
195  "adsl_ppp",
196  "adsl_routed",
197  "ftth_routed",
198  "grps_ppp",
199  "unknown",
200  ],
201  translation_key="wan_mode",
202  value_fn=lambda x: x.mode.replace("/", "_"),
203  ),
204 )
205 
206 
207 def _value_to_option(value: str | None) -> str | None:
208  if value is None:
209  return value
210  return value.lower().replace(" ", "_").replace(".", "_")
211 
212 
213 def _get_temperature(value: float | None) -> float | None:
214  if value is None or value < 1000:
215  return value
216  return value / 1000
217 
218 
220  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
221 ) -> None:
222  """Set up the sensors."""
223  data: DomainData = hass.data[DOMAIN][entry.entry_id]
224  system_info = data.system.data
225  if TYPE_CHECKING:
226  assert system_info is not None
227 
228  entities: list[SFRBoxSensor] = [
229  SFRBoxSensor(data.system, description, system_info)
230  for description in SYSTEM_SENSOR_TYPES
231  ]
232  entities.extend(
233  SFRBoxSensor(data.wan, description, system_info)
234  for description in WAN_SENSOR_TYPES
235  )
236  if system_info.net_infra == "adsl":
237  entities.extend(
238  SFRBoxSensor(data.dsl, description, system_info)
239  for description in DSL_SENSOR_TYPES
240  )
241 
242  async_add_entities(entities)
243 
244 
245 class SFRBoxSensor[_T](CoordinatorEntity[SFRDataUpdateCoordinator[_T]], SensorEntity):
246  """SFR Box sensor."""
247 
248  entity_description: SFRBoxSensorEntityDescription[_T]
249  _attr_has_entity_name = True
250 
251  def __init__(
252  self,
253  coordinator: SFRDataUpdateCoordinator[_T],
254  description: SFRBoxSensorEntityDescription,
255  system_info: SystemInfo,
256  ) -> None:
257  """Initialize the sensor."""
258  super().__init__(coordinator)
259  self.entity_descriptionentity_description = description
260  self._attr_unique_id_attr_unique_id = (
261  f"{system_info.mac_addr}_{coordinator.name}_{description.key}"
262  )
263  self._attr_device_info_attr_device_info = DeviceInfo(
264  identifiers={(DOMAIN, system_info.mac_addr)},
265  )
266 
267  @property
268  def native_value(self) -> StateType:
269  """Return the native value of the device."""
270  if self.coordinator.data is None:
271  return None
272  return self.entity_descriptionentity_description.value_fn(self.coordinator.data)
None __init__(self, SFRDataUpdateCoordinator[_T] coordinator, SFRBoxSensorEntityDescription description, SystemInfo system_info)
Definition: sensor.py:256
str|None _value_to_option(str|None value)
Definition: sensor.py:207
float|None _get_temperature(float|None value)
Definition: sensor.py:213
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:221