Home Assistant Unofficial Reference 2024.12.1
binary_sensor.py
Go to the documentation of this file.
1 """Binary sensors for System Monitor."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable
6 from dataclasses import dataclass
7 from functools import lru_cache
8 import logging
9 import sys
10 from typing import Literal
11 
12 from psutil import NoSuchProcess
13 
15  DOMAIN as BINARY_SENSOR_DOMAIN,
16  BinarySensorDeviceClass,
17  BinarySensorEntity,
18  BinarySensorEntityDescription,
19 )
20 from homeassistant.const import EntityCategory
21 from homeassistant.core import HomeAssistant
22 from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
23 from homeassistant.helpers.entity_platform import AddEntitiesCallback
24 from homeassistant.helpers.update_coordinator import CoordinatorEntity
25 from homeassistant.util import slugify
26 
27 from . import SystemMonitorConfigEntry
28 from .const import CONF_PROCESS, DOMAIN
29 from .coordinator import SystemMonitorCoordinator
30 
31 _LOGGER = logging.getLogger(__name__)
32 
33 CONF_ARG = "arg"
34 
35 
36 SENSOR_TYPE_NAME = 0
37 SENSOR_TYPE_UOM = 1
38 SENSOR_TYPE_ICON = 2
39 SENSOR_TYPE_DEVICE_CLASS = 3
40 SENSOR_TYPE_MANDATORY_ARG = 4
41 
42 SIGNAL_SYSTEMMONITOR_UPDATE = "systemmonitor_update"
43 
44 
45 @lru_cache
46 def get_cpu_icon() -> Literal["mdi:cpu-64-bit", "mdi:cpu-32-bit"]:
47  """Return cpu icon."""
48  if sys.maxsize > 2**32:
49  return "mdi:cpu-64-bit"
50  return "mdi:cpu-32-bit"
51 
52 
53 def get_process(entity: SystemMonitorSensor) -> bool:
54  """Return process."""
55  state = False
56  for proc in entity.coordinator.data.processes:
57  try:
58  _LOGGER.debug("process %s for argument %s", proc.name(), entity.argument)
59  if entity.argument == proc.name():
60  state = True
61  break
62  except NoSuchProcess as err:
63  _LOGGER.warning(
64  "Failed to load process with ID: %s, old name: %s",
65  err.pid,
66  err.name,
67  )
68  return state
69 
70 
71 @dataclass(frozen=True, kw_only=True)
73  """Describes System Monitor binary sensor entities."""
74 
75  value_fn: Callable[[SystemMonitorSensor], bool]
76  add_to_update: Callable[[SystemMonitorSensor], tuple[str, str]]
77 
78 
79 SENSOR_TYPES: tuple[SysMonitorBinarySensorEntityDescription, ...] = (
81  key="binary_process",
82  translation_key="process",
83  icon=get_cpu_icon(),
84  value_fn=get_process,
85  device_class=BinarySensorDeviceClass.RUNNING,
86  add_to_update=lambda entity: ("processes", ""),
87  ),
88 )
89 
90 
92  hass: HomeAssistant,
93  entry: SystemMonitorConfigEntry,
94  async_add_entities: AddEntitiesCallback,
95 ) -> None:
96  """Set up System Monitor binary sensors based on a config entry."""
97  coordinator = entry.runtime_data.coordinator
98 
101  coordinator,
102  sensor_description,
103  entry.entry_id,
104  argument,
105  )
106  for sensor_description in SENSOR_TYPES
107  for argument in entry.options.get(BINARY_SENSOR_DOMAIN, {}).get(
108  CONF_PROCESS, []
109  )
110  )
111 
112 
114  CoordinatorEntity[SystemMonitorCoordinator], BinarySensorEntity
115 ):
116  """Implementation of a system monitor binary sensor."""
117 
118  _attr_has_entity_name = True
119  _attr_entity_category = EntityCategory.DIAGNOSTIC
120  entity_description: SysMonitorBinarySensorEntityDescription
121 
122  def __init__(
123  self,
124  coordinator: SystemMonitorCoordinator,
125  sensor_description: SysMonitorBinarySensorEntityDescription,
126  entry_id: str,
127  argument: str,
128  ) -> None:
129  """Initialize the binary sensor."""
130  super().__init__(coordinator)
131  self.entity_descriptionentity_description = sensor_description
132  self._attr_translation_placeholders_attr_translation_placeholders = {"process": argument}
133  self._attr_unique_id: str = slugify(f"{sensor_description.key}_{argument}")
134  self._attr_device_info_attr_device_info = DeviceInfo(
135  entry_type=DeviceEntryType.SERVICE,
136  identifiers={(DOMAIN, entry_id)},
137  manufacturer="System Monitor",
138  name="System Monitor",
139  )
140  self.argumentargument = argument
141 
142  async def async_added_to_hass(self) -> None:
143  """When added to hass."""
144  self.coordinator.update_subscribers[
145  self.entity_descriptionentity_description.add_to_update(self)
146  ].add(self.entity_identity_id)
147  return await super().async_added_to_hass()
148 
149  async def async_will_remove_from_hass(self) -> None:
150  """When removed from hass."""
151  self.coordinator.update_subscribers[
152  self.entity_descriptionentity_description.add_to_update(self)
153  ].remove(self.entity_identity_id)
154  return await super().async_will_remove_from_hass()
155 
156  @property
157  def is_on(self) -> bool | None:
158  """Return true if the binary sensor is on."""
159  return self.entity_descriptionentity_description.value_fn(self)
None __init__(self, SystemMonitorCoordinator coordinator, SysMonitorBinarySensorEntityDescription sensor_description, str entry_id, str argument)
bool add(self, _T matcher)
Definition: match.py:185
bool remove(self, _T matcher)
Definition: match.py:214
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
None async_setup_entry(HomeAssistant hass, SystemMonitorConfigEntry entry, AddEntitiesCallback async_add_entities)
bool get_process(SystemMonitorSensor entity)
Literal["mdi:cpu-64-bit", "mdi:cpu-32-bit"] get_cpu_icon()