Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Sensor entities for the madVR integration."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable
6 from dataclasses import dataclass
7 
9  SensorDeviceClass,
10  SensorEntity,
11  SensorEntityDescription,
12  SensorStateClass,
13 )
14 from homeassistant.const import UnitOfTemperature
15 from homeassistant.core import HomeAssistant
16 from homeassistant.helpers.entity_platform import AddEntitiesCallback
17 from homeassistant.helpers.typing import StateType
18 
19 from . import MadVRConfigEntry
20 from .const import (
21  ASPECT_DEC,
22  ASPECT_INT,
23  ASPECT_NAME,
24  ASPECT_RES,
25  INCOMING_ASPECT_RATIO,
26  INCOMING_BIT_DEPTH,
27  INCOMING_BLACK_LEVELS,
28  INCOMING_COLOR_SPACE,
29  INCOMING_COLORIMETRY,
30  INCOMING_FRAME_RATE,
31  INCOMING_RES,
32  INCOMING_SIGNAL_TYPE,
33  MASKING_DEC,
34  MASKING_INT,
35  MASKING_RES,
36  OUTGOING_BIT_DEPTH,
37  OUTGOING_BLACK_LEVELS,
38  OUTGOING_COLOR_SPACE,
39  OUTGOING_COLORIMETRY,
40  OUTGOING_FRAME_RATE,
41  OUTGOING_RES,
42  OUTGOING_SIGNAL_TYPE,
43  TEMP_CPU,
44  TEMP_GPU,
45  TEMP_HDMI,
46  TEMP_MAINBOARD,
47 )
48 from .coordinator import MadVRCoordinator
49 from .entity import MadVREntity
50 
51 
52 def is_valid_temperature(value: float | None) -> bool:
53  """Check if the temperature value is valid."""
54  return value is not None and value > 0
55 
56 
57 def get_temperature(coordinator: MadVRCoordinator, key: str) -> float | None:
58  """Get temperature value if valid, otherwise return None."""
59  try:
60  temp = float(coordinator.data.get(key, 0))
61  except (AttributeError, ValueError):
62  return None
63  else:
64  return temp if is_valid_temperature(temp) else None
65 
66 
67 @dataclass(frozen=True, kw_only=True)
69  """Describe madVR sensor entity."""
70 
71  value_fn: Callable[[MadVRCoordinator], StateType]
72 
73 
74 SENSORS: tuple[MadvrSensorEntityDescription, ...] = (
76  key=TEMP_GPU,
77  device_class=SensorDeviceClass.TEMPERATURE,
78  state_class=SensorStateClass.MEASUREMENT,
79  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
80  value_fn=lambda coordinator: get_temperature(coordinator, TEMP_GPU),
81  translation_key=TEMP_GPU,
82  entity_registry_enabled_default=False,
83  ),
85  key=TEMP_HDMI,
86  device_class=SensorDeviceClass.TEMPERATURE,
87  state_class=SensorStateClass.MEASUREMENT,
88  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
89  value_fn=lambda coordinator: get_temperature(coordinator, TEMP_HDMI),
90  translation_key=TEMP_HDMI,
91  entity_registry_enabled_default=False,
92  ),
94  key=TEMP_CPU,
95  device_class=SensorDeviceClass.TEMPERATURE,
96  state_class=SensorStateClass.MEASUREMENT,
97  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
98  value_fn=lambda coordinator: get_temperature(coordinator, TEMP_CPU),
99  translation_key=TEMP_CPU,
100  entity_registry_enabled_default=False,
101  ),
103  key=TEMP_MAINBOARD,
104  device_class=SensorDeviceClass.TEMPERATURE,
105  state_class=SensorStateClass.MEASUREMENT,
106  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
107  value_fn=lambda coordinator: get_temperature(coordinator, TEMP_MAINBOARD),
108  translation_key=TEMP_MAINBOARD,
109  entity_registry_enabled_default=False,
110  ),
112  key=INCOMING_RES,
113  value_fn=lambda coordinator: coordinator.data.get(INCOMING_RES),
114  translation_key=INCOMING_RES,
115  ),
117  key=INCOMING_SIGNAL_TYPE,
118  value_fn=lambda coordinator: coordinator.data.get(INCOMING_SIGNAL_TYPE),
119  translation_key=INCOMING_SIGNAL_TYPE,
120  device_class=SensorDeviceClass.ENUM,
121  options=["2D", "3D"],
122  entity_registry_enabled_default=False,
123  ),
125  key=INCOMING_FRAME_RATE,
126  value_fn=lambda coordinator: coordinator.data.get(INCOMING_FRAME_RATE),
127  translation_key=INCOMING_FRAME_RATE,
128  ),
130  key=INCOMING_COLOR_SPACE,
131  value_fn=lambda coordinator: coordinator.data.get(INCOMING_COLOR_SPACE),
132  translation_key=INCOMING_COLOR_SPACE,
133  device_class=SensorDeviceClass.ENUM,
134  options=["RGB", "444", "422", "420"],
135  ),
137  key=INCOMING_BIT_DEPTH,
138  value_fn=lambda coordinator: coordinator.data.get(INCOMING_BIT_DEPTH),
139  translation_key=INCOMING_BIT_DEPTH,
140  device_class=SensorDeviceClass.ENUM,
141  options=["8bit", "10bit", "12bit"],
142  ),
144  key=INCOMING_COLORIMETRY,
145  value_fn=lambda coordinator: coordinator.data.get(INCOMING_COLORIMETRY),
146  translation_key=INCOMING_COLORIMETRY,
147  device_class=SensorDeviceClass.ENUM,
148  options=["SDR", "HDR10", "HLG 601", "PAL", "709", "DCI", "2020"],
149  ),
151  key=INCOMING_BLACK_LEVELS,
152  value_fn=lambda coordinator: coordinator.data.get(INCOMING_BLACK_LEVELS),
153  translation_key=INCOMING_BLACK_LEVELS,
154  device_class=SensorDeviceClass.ENUM,
155  options=["TV", "PC"],
156  ),
158  key=INCOMING_ASPECT_RATIO,
159  value_fn=lambda coordinator: coordinator.data.get(INCOMING_ASPECT_RATIO),
160  translation_key=INCOMING_ASPECT_RATIO,
161  device_class=SensorDeviceClass.ENUM,
162  options=["16:9", "4:3"],
163  entity_registry_enabled_default=False,
164  ),
166  key=OUTGOING_RES,
167  value_fn=lambda coordinator: coordinator.data.get(OUTGOING_RES),
168  translation_key=OUTGOING_RES,
169  ),
171  key=OUTGOING_SIGNAL_TYPE,
172  value_fn=lambda coordinator: coordinator.data.get(OUTGOING_SIGNAL_TYPE),
173  translation_key=OUTGOING_SIGNAL_TYPE,
174  device_class=SensorDeviceClass.ENUM,
175  options=["2D", "3D"],
176  entity_registry_enabled_default=False,
177  ),
179  key=OUTGOING_FRAME_RATE,
180  value_fn=lambda coordinator: coordinator.data.get(OUTGOING_FRAME_RATE),
181  translation_key=OUTGOING_FRAME_RATE,
182  ),
184  key=OUTGOING_COLOR_SPACE,
185  value_fn=lambda coordinator: coordinator.data.get(OUTGOING_COLOR_SPACE),
186  translation_key=OUTGOING_COLOR_SPACE,
187  device_class=SensorDeviceClass.ENUM,
188  options=["RGB", "444", "422", "420"],
189  ),
191  key=OUTGOING_BIT_DEPTH,
192  value_fn=lambda coordinator: coordinator.data.get(OUTGOING_BIT_DEPTH),
193  translation_key=OUTGOING_BIT_DEPTH,
194  device_class=SensorDeviceClass.ENUM,
195  options=["8bit", "10bit", "12bit"],
196  ),
198  key=OUTGOING_COLORIMETRY,
199  value_fn=lambda coordinator: coordinator.data.get(OUTGOING_COLORIMETRY),
200  translation_key=OUTGOING_COLORIMETRY,
201  device_class=SensorDeviceClass.ENUM,
202  options=["SDR", "HDR10", "HLG 601", "PAL", "709", "DCI", "2020"],
203  ),
205  key=OUTGOING_BLACK_LEVELS,
206  value_fn=lambda coordinator: coordinator.data.get(OUTGOING_BLACK_LEVELS),
207  translation_key=OUTGOING_BLACK_LEVELS,
208  device_class=SensorDeviceClass.ENUM,
209  options=["TV", "PC"],
210  ),
212  key=ASPECT_RES,
213  value_fn=lambda coordinator: coordinator.data.get(ASPECT_RES),
214  translation_key=ASPECT_RES,
215  entity_registry_enabled_default=False,
216  ),
218  key=ASPECT_DEC,
219  value_fn=lambda coordinator: coordinator.data.get(ASPECT_DEC),
220  translation_key=ASPECT_DEC,
221  ),
223  key=ASPECT_INT,
224  value_fn=lambda coordinator: coordinator.data.get(ASPECT_INT),
225  translation_key=ASPECT_INT,
226  entity_registry_enabled_default=False,
227  ),
229  key=ASPECT_NAME,
230  value_fn=lambda coordinator: coordinator.data.get(ASPECT_NAME),
231  translation_key=ASPECT_NAME,
232  entity_registry_enabled_default=False,
233  ),
235  key=MASKING_RES,
236  value_fn=lambda coordinator: coordinator.data.get(MASKING_RES),
237  translation_key=MASKING_RES,
238  entity_registry_enabled_default=False,
239  ),
241  key=MASKING_DEC,
242  value_fn=lambda coordinator: coordinator.data.get(MASKING_DEC),
243  translation_key=MASKING_DEC,
244  ),
246  key=MASKING_INT,
247  value_fn=lambda coordinator: coordinator.data.get(MASKING_INT),
248  translation_key=MASKING_INT,
249  entity_registry_enabled_default=False,
250  ),
251 )
252 
253 
255  hass: HomeAssistant,
256  entry: MadVRConfigEntry,
257  async_add_entities: AddEntitiesCallback,
258 ) -> None:
259  """Set up the sensor entities."""
260  coordinator = entry.runtime_data
261  async_add_entities(MadvrSensor(coordinator, description) for description in SENSORS)
262 
263 
265  """Base class for madVR sensors."""
266 
267  def __init__(
268  self,
269  coordinator: MadVRCoordinator,
270  description: MadvrSensorEntityDescription,
271  ) -> None:
272  """Initialize the sensor."""
273  super().__init__(coordinator)
274  self.entity_description: MadvrSensorEntityDescription = description
275  self._attr_unique_id_attr_unique_id = f"{coordinator.mac}_{description.key}"
276 
277  @property
278  def native_value(self) -> float | str | None:
279  """Return the state of the sensor."""
280  val = self.entity_description.value_fn(self.coordinator)
281  # check if sensor is enum
282  if self.entity_description.device_class == SensorDeviceClass.ENUM:
283  if (
284  self.entity_description.options
285  and val in self.entity_description.options
286  ):
287  return val
288  # return None for values that are not in the options
289  return None
290 
291  return val
None __init__(self, MadVRCoordinator coordinator, MadvrSensorEntityDescription description)
Definition: sensor.py:271
float|None get_temperature(MadVRCoordinator coordinator, str key)
Definition: sensor.py:57
None async_setup_entry(HomeAssistant hass, MadVRConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:258
bool is_valid_temperature(float|None value)
Definition: sensor.py:52