Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support gathering system information of hosts which are running glances."""
2 
3 from __future__ import annotations
4 
5 from dataclasses import dataclass
6 
8  SensorDeviceClass,
9  SensorEntity,
10  SensorEntityDescription,
11  SensorStateClass,
12 )
13 from homeassistant.const import (
14  PERCENTAGE,
15  REVOLUTIONS_PER_MINUTE,
16  UnitOfDataRate,
17  UnitOfInformation,
18  UnitOfTemperature,
19 )
20 from homeassistant.core import HomeAssistant, callback
21 from homeassistant.helpers.device_registry import DeviceInfo
22 from homeassistant.helpers.entity_platform import AddEntitiesCallback
23 from homeassistant.helpers.update_coordinator import CoordinatorEntity
24 
25 from . import GlancesConfigEntry, GlancesDataUpdateCoordinator
26 from .const import CPU_ICON, DOMAIN
27 
28 
29 @dataclass(frozen=True, kw_only=True)
31  """Describe Glances sensor entity."""
32 
33  type: str
34 
35 
36 SENSOR_TYPES = {
37  ("fs", "disk_use_percent"): GlancesSensorEntityDescription(
38  key="disk_use_percent",
39  type="fs",
40  translation_key="disk_usage",
41  native_unit_of_measurement=PERCENTAGE,
42  state_class=SensorStateClass.MEASUREMENT,
43  ),
44  ("fs", "disk_use"): GlancesSensorEntityDescription(
45  key="disk_use",
46  type="fs",
47  translation_key="disk_used",
48  native_unit_of_measurement=UnitOfInformation.GIBIBYTES,
49  device_class=SensorDeviceClass.DATA_SIZE,
50  state_class=SensorStateClass.MEASUREMENT,
51  ),
52  ("fs", "disk_free"): GlancesSensorEntityDescription(
53  key="disk_free",
54  type="fs",
55  translation_key="disk_free",
56  native_unit_of_measurement=UnitOfInformation.GIBIBYTES,
57  device_class=SensorDeviceClass.DATA_SIZE,
58  state_class=SensorStateClass.MEASUREMENT,
59  ),
60  ("diskio", "read"): GlancesSensorEntityDescription(
61  key="read",
62  type="diskio",
63  translation_key="diskio_read",
64  native_unit_of_measurement=UnitOfDataRate.BYTES_PER_SECOND,
65  suggested_unit_of_measurement=UnitOfDataRate.MEGABYTES_PER_SECOND,
66  device_class=SensorDeviceClass.DATA_RATE,
67  state_class=SensorStateClass.MEASUREMENT,
68  ),
69  ("diskio", "write"): GlancesSensorEntityDescription(
70  key="write",
71  type="diskio",
72  translation_key="diskio_write",
73  native_unit_of_measurement=UnitOfDataRate.BYTES_PER_SECOND,
74  suggested_unit_of_measurement=UnitOfDataRate.MEGABYTES_PER_SECOND,
75  device_class=SensorDeviceClass.DATA_RATE,
76  state_class=SensorStateClass.MEASUREMENT,
77  ),
78  ("mem", "memory_use_percent"): GlancesSensorEntityDescription(
79  key="memory_use_percent",
80  type="mem",
81  translation_key="memory_usage",
82  native_unit_of_measurement=PERCENTAGE,
83  state_class=SensorStateClass.MEASUREMENT,
84  ),
85  ("mem", "memory_use"): GlancesSensorEntityDescription(
86  key="memory_use",
87  type="mem",
88  translation_key="memory_use",
89  native_unit_of_measurement=UnitOfInformation.MEBIBYTES,
90  device_class=SensorDeviceClass.DATA_SIZE,
91  state_class=SensorStateClass.MEASUREMENT,
92  ),
93  ("mem", "memory_free"): GlancesSensorEntityDescription(
94  key="memory_free",
95  type="mem",
96  translation_key="memory_free",
97  native_unit_of_measurement=UnitOfInformation.MEBIBYTES,
98  device_class=SensorDeviceClass.DATA_SIZE,
99  state_class=SensorStateClass.MEASUREMENT,
100  ),
101  ("memswap", "swap_use_percent"): GlancesSensorEntityDescription(
102  key="swap_use_percent",
103  type="memswap",
104  translation_key="swap_usage",
105  native_unit_of_measurement=PERCENTAGE,
106  state_class=SensorStateClass.MEASUREMENT,
107  ),
108  ("memswap", "swap_use"): GlancesSensorEntityDescription(
109  key="swap_use",
110  type="memswap",
111  translation_key="swap_use",
112  native_unit_of_measurement=UnitOfInformation.GIBIBYTES,
113  device_class=SensorDeviceClass.DATA_SIZE,
114  state_class=SensorStateClass.MEASUREMENT,
115  ),
116  ("memswap", "swap_free"): GlancesSensorEntityDescription(
117  key="swap_free",
118  type="memswap",
119  translation_key="swap_free",
120  native_unit_of_measurement=UnitOfInformation.GIBIBYTES,
121  device_class=SensorDeviceClass.DATA_SIZE,
122  state_class=SensorStateClass.MEASUREMENT,
123  ),
124  ("load", "processor_load"): GlancesSensorEntityDescription(
125  key="processor_load",
126  type="load",
127  translation_key="processor_load",
128  icon=CPU_ICON,
129  state_class=SensorStateClass.MEASUREMENT,
130  ),
131  ("processcount", "process_running"): GlancesSensorEntityDescription(
132  key="process_running",
133  type="processcount",
134  translation_key="process_running",
135  icon=CPU_ICON,
136  state_class=SensorStateClass.MEASUREMENT,
137  ),
138  ("processcount", "process_total"): GlancesSensorEntityDescription(
139  key="process_total",
140  type="processcount",
141  translation_key="process_total",
142  icon=CPU_ICON,
143  state_class=SensorStateClass.MEASUREMENT,
144  ),
145  ("processcount", "process_thread"): GlancesSensorEntityDescription(
146  key="process_thread",
147  type="processcount",
148  translation_key="process_threads",
149  icon=CPU_ICON,
150  state_class=SensorStateClass.MEASUREMENT,
151  ),
152  ("processcount", "process_sleeping"): GlancesSensorEntityDescription(
153  key="process_sleeping",
154  type="processcount",
155  translation_key="process_sleeping",
156  icon=CPU_ICON,
157  state_class=SensorStateClass.MEASUREMENT,
158  ),
159  ("cpu", "cpu_use_percent"): GlancesSensorEntityDescription(
160  key="cpu_use_percent",
161  type="cpu",
162  translation_key="cpu_usage",
163  native_unit_of_measurement=PERCENTAGE,
164  icon=CPU_ICON,
165  state_class=SensorStateClass.MEASUREMENT,
166  ),
167  ("sensors", "temperature_core"): GlancesSensorEntityDescription(
168  key="temperature_core",
169  type="sensors",
170  translation_key="temperature",
171  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
172  device_class=SensorDeviceClass.TEMPERATURE,
173  state_class=SensorStateClass.MEASUREMENT,
174  ),
175  ("sensors", "temperature_hdd"): GlancesSensorEntityDescription(
176  key="temperature_hdd",
177  type="sensors",
178  translation_key="temperature",
179  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
180  device_class=SensorDeviceClass.TEMPERATURE,
181  state_class=SensorStateClass.MEASUREMENT,
182  ),
183  ("sensors", "fan_speed"): GlancesSensorEntityDescription(
184  key="fan_speed",
185  type="sensors",
186  translation_key="fan_speed",
187  native_unit_of_measurement=REVOLUTIONS_PER_MINUTE,
188  state_class=SensorStateClass.MEASUREMENT,
189  ),
190  ("sensors", "battery"): GlancesSensorEntityDescription(
191  key="battery",
192  type="sensors",
193  translation_key="charge",
194  native_unit_of_measurement=PERCENTAGE,
195  device_class=SensorDeviceClass.BATTERY,
196  state_class=SensorStateClass.MEASUREMENT,
197  ),
198  ("docker", "docker_active"): GlancesSensorEntityDescription(
199  key="docker_active",
200  type="docker",
201  translation_key="container_active",
202  state_class=SensorStateClass.MEASUREMENT,
203  ),
204  ("docker", "docker_cpu_use"): GlancesSensorEntityDescription(
205  key="docker_cpu_use",
206  type="docker",
207  translation_key="container_cpu_usage",
208  native_unit_of_measurement=PERCENTAGE,
209  state_class=SensorStateClass.MEASUREMENT,
210  ),
211  ("docker", "docker_memory_use"): GlancesSensorEntityDescription(
212  key="docker_memory_use",
213  type="docker",
214  translation_key="container_memory_used",
215  native_unit_of_measurement=UnitOfInformation.MEBIBYTES,
216  device_class=SensorDeviceClass.DATA_SIZE,
217  state_class=SensorStateClass.MEASUREMENT,
218  ),
219  ("raid", "available"): GlancesSensorEntityDescription(
220  key="available",
221  type="raid",
222  translation_key="raid_available",
223  state_class=SensorStateClass.MEASUREMENT,
224  ),
225  ("raid", "used"): GlancesSensorEntityDescription(
226  key="used",
227  type="raid",
228  translation_key="raid_used",
229  state_class=SensorStateClass.MEASUREMENT,
230  ),
231  ("computed", "uptime"): GlancesSensorEntityDescription(
232  key="uptime",
233  type="computed",
234  translation_key="uptime",
235  device_class=SensorDeviceClass.TIMESTAMP,
236  ),
237  ("gpu", "mem"): GlancesSensorEntityDescription(
238  key="mem",
239  type="gpu",
240  translation_key="gpu_memory_usage",
241  native_unit_of_measurement=PERCENTAGE,
242  state_class=SensorStateClass.MEASUREMENT,
243  ),
244  ("gpu", "proc"): GlancesSensorEntityDescription(
245  key="proc",
246  type="gpu",
247  translation_key="gpu_processor_usage",
248  native_unit_of_measurement=PERCENTAGE,
249  state_class=SensorStateClass.MEASUREMENT,
250  suggested_display_precision=1,
251  ),
252  ("gpu", "temperature"): GlancesSensorEntityDescription(
253  key="temperature",
254  type="gpu",
255  translation_key="temperature",
256  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
257  device_class=SensorDeviceClass.TEMPERATURE,
258  state_class=SensorStateClass.MEASUREMENT,
259  ),
260  ("gpu", "fan_speed"): GlancesSensorEntityDescription(
261  key="fan_speed",
262  type="gpu",
263  translation_key="fan_speed",
264  native_unit_of_measurement=PERCENTAGE,
265  state_class=SensorStateClass.MEASUREMENT,
266  ),
267  ("network", "rx"): GlancesSensorEntityDescription(
268  key="rx",
269  type="network",
270  translation_key="network_rx",
271  native_unit_of_measurement=UnitOfDataRate.BYTES_PER_SECOND,
272  suggested_unit_of_measurement=UnitOfDataRate.MEGABITS_PER_SECOND,
273  device_class=SensorDeviceClass.DATA_RATE,
274  state_class=SensorStateClass.MEASUREMENT,
275  ),
276  ("network", "tx"): GlancesSensorEntityDescription(
277  key="tx",
278  type="network",
279  translation_key="network_tx",
280  native_unit_of_measurement=UnitOfDataRate.BYTES_PER_SECOND,
281  suggested_unit_of_measurement=UnitOfDataRate.MEGABITS_PER_SECOND,
282  device_class=SensorDeviceClass.DATA_RATE,
283  state_class=SensorStateClass.MEASUREMENT,
284  ),
285 }
286 
287 
289  hass: HomeAssistant,
290  config_entry: GlancesConfigEntry,
291  async_add_entities: AddEntitiesCallback,
292 ) -> None:
293  """Set up the Glances sensors."""
294 
295  coordinator = config_entry.runtime_data
296  entities: list[GlancesSensor] = []
297 
298  for sensor_type, sensors in coordinator.data.items():
299  if sensor_type in ["fs", "diskio", "sensors", "raid", "gpu", "network"]:
300  entities.extend(
302  coordinator,
303  sensor_description,
304  sensor_label,
305  )
306  for sensor_label, params in sensors.items()
307  for param in params
308  if (sensor_description := SENSOR_TYPES.get((sensor_type, param)))
309  )
310  else:
311  entities.extend(
313  coordinator,
314  sensor_description,
315  )
316  for sensor in sensors
317  if (sensor_description := SENSOR_TYPES.get((sensor_type, sensor)))
318  )
319 
320  async_add_entities(entities)
321 
322 
323 class GlancesSensor(CoordinatorEntity[GlancesDataUpdateCoordinator], SensorEntity):
324  """Implementation of a Glances sensor."""
325 
326  entity_description: GlancesSensorEntityDescription
327  _attr_has_entity_name = True
328  _data_valid: bool = False
329 
330  def __init__(
331  self,
332  coordinator: GlancesDataUpdateCoordinator,
333  description: GlancesSensorEntityDescription,
334  sensor_label: str = "",
335  ) -> None:
336  """Initialize the sensor."""
337  super().__init__(coordinator)
338  self._sensor_label_sensor_label = sensor_label
339  self.entity_descriptionentity_description = description
340  if sensor_label:
341  self._attr_translation_placeholders_attr_translation_placeholders = {"sensor_label": sensor_label}
342  self._attr_device_info_attr_device_info = DeviceInfo(
343  identifiers={(DOMAIN, coordinator.config_entry.entry_id)},
344  manufacturer="Glances",
345  name=coordinator.host,
346  )
347  self._attr_unique_id_attr_unique_id = (
348  f"{coordinator.config_entry.entry_id}-{sensor_label}-{description.key}"
349  )
350  self._update_native_value_update_native_value()
351 
352  @property
353  def available(self) -> bool:
354  """Set sensor unavailable when native value is invalid."""
355  return super().available and self._data_valid_data_valid
356 
357  @callback
358  def _handle_coordinator_update(self) -> None:
359  """Handle updated data from the coordinator."""
360  self._update_native_value_update_native_value()
362 
363  def _update_native_value(self) -> None:
364  """Update sensor native value from coordinator data."""
365  data = self.coordinator.data.get(self.entity_descriptionentity_description.type)
366  if data and (dict_val := data.get(self._sensor_label_sensor_label)):
367  self._attr_native_value_attr_native_value = dict_val.get(self.entity_descriptionentity_description.key)
368  elif data and (self.entity_descriptionentity_description.key in data):
369  self._attr_native_value_attr_native_value = data.get(self.entity_descriptionentity_description.key)
370  else:
371  self._attr_native_value_attr_native_value = None
372  self._update_data_valid_update_data_valid()
373 
374  def _update_data_valid(self) -> None:
375  self._data_valid_data_valid = self._attr_native_value_attr_native_value is not None and (
376  not self._numeric_state_expected_numeric_state_expected
377  or isinstance(self._attr_native_value_attr_native_value, (int, float))
378  or isinstance(self._attr_native_value_attr_native_value, str)
379  and self._attr_native_value_attr_native_value.isnumeric()
380  )
None __init__(self, GlancesDataUpdateCoordinator coordinator, GlancesSensorEntityDescription description, str sensor_label="")
Definition: sensor.py:335
None async_setup_entry(HomeAssistant hass, GlancesConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:292