Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for MySensors sensors."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 from awesomeversion import AwesomeVersion
8 from mysensors import BaseAsyncGateway
9 
11  SensorDeviceClass,
12  SensorEntity,
13  SensorEntityDescription,
14  SensorStateClass,
15 )
16 from homeassistant.config_entries import ConfigEntry
17 from homeassistant.const import (
18  DEGREE,
19  LIGHT_LUX,
20  PERCENTAGE,
21  Platform,
22  UnitOfApparentPower,
23  UnitOfConductivity,
24  UnitOfElectricCurrent,
25  UnitOfElectricPotential,
26  UnitOfEnergy,
27  UnitOfFrequency,
28  UnitOfLength,
29  UnitOfMass,
30  UnitOfPower,
31  UnitOfReactivePower,
32  UnitOfSoundPressure,
33  UnitOfTemperature,
34  UnitOfVolume,
35 )
36 from homeassistant.core import HomeAssistant, callback
37 from homeassistant.helpers.dispatcher import async_dispatcher_connect
38 from homeassistant.helpers.entity_platform import AddEntitiesCallback
39 from homeassistant.util.unit_system import METRIC_SYSTEM
40 
41 from . import setup_mysensors_platform
42 from .const import (
43  ATTR_GATEWAY_ID,
44  ATTR_NODE_ID,
45  DOMAIN,
46  MYSENSORS_DISCOVERY,
47  MYSENSORS_GATEWAYS,
48  MYSENSORS_NODE_DISCOVERY,
49  DiscoveryInfo,
50  NodeDiscoveryInfo,
51 )
52 from .entity import MySensorNodeEntity, MySensorsChildEntity
53 from .helpers import on_unload
54 
55 SENSORS: dict[str, SensorEntityDescription] = {
56  "V_TEMP": SensorEntityDescription(
57  key="V_TEMP",
58  device_class=SensorDeviceClass.TEMPERATURE,
59  state_class=SensorStateClass.MEASUREMENT,
60  ),
61  "V_HUM": SensorEntityDescription(
62  key="V_HUM",
63  native_unit_of_measurement=PERCENTAGE,
64  device_class=SensorDeviceClass.HUMIDITY,
65  state_class=SensorStateClass.MEASUREMENT,
66  ),
67  "V_DIMMER": SensorEntityDescription(
68  key="V_DIMMER",
69  native_unit_of_measurement=PERCENTAGE,
70  icon="mdi:percent",
71  ),
72  "V_PERCENTAGE": SensorEntityDescription(
73  key="V_PERCENTAGE",
74  native_unit_of_measurement=PERCENTAGE,
75  icon="mdi:percent",
76  ),
77  "V_PRESSURE": SensorEntityDescription(
78  key="V_PRESSURE",
79  icon="mdi:gauge",
80  ),
81  "V_FORECAST": SensorEntityDescription(
82  key="V_FORECAST",
83  icon="mdi:weather-partly-cloudy",
84  ),
85  "V_RAIN": SensorEntityDescription(
86  key="V_RAIN",
87  icon="mdi:weather-rainy",
88  ),
89  "V_RAINRATE": SensorEntityDescription(
90  key="V_RAINRATE",
91  icon="mdi:weather-rainy",
92  ),
93  "V_WIND": SensorEntityDescription(
94  key="V_WIND",
95  icon="mdi:weather-windy",
96  ),
97  "V_GUST": SensorEntityDescription(
98  key="V_GUST",
99  icon="mdi:weather-windy",
100  ),
101  "V_DIRECTION": SensorEntityDescription(
102  key="V_DIRECTION",
103  native_unit_of_measurement=DEGREE,
104  icon="mdi:compass",
105  ),
106  "V_WEIGHT": SensorEntityDescription(
107  key="V_WEIGHT",
108  native_unit_of_measurement=UnitOfMass.KILOGRAMS,
109  device_class=SensorDeviceClass.WEIGHT,
110  ),
111  "V_DISTANCE": SensorEntityDescription(
112  key="V_DISTANCE",
113  native_unit_of_measurement=UnitOfLength.METERS,
114  device_class=SensorDeviceClass.DISTANCE,
115  ),
116  "V_IMPEDANCE": SensorEntityDescription(
117  key="V_IMPEDANCE",
118  native_unit_of_measurement="ohm",
119  ),
120  "V_WATT": SensorEntityDescription(
121  key="V_WATT",
122  native_unit_of_measurement=UnitOfPower.WATT,
123  device_class=SensorDeviceClass.POWER,
124  state_class=SensorStateClass.MEASUREMENT,
125  ),
126  "V_KWH": SensorEntityDescription(
127  key="V_KWH",
128  native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
129  device_class=SensorDeviceClass.ENERGY,
130  state_class=SensorStateClass.TOTAL_INCREASING,
131  ),
132  "V_LIGHT_LEVEL": SensorEntityDescription(
133  key="V_LIGHT_LEVEL",
134  native_unit_of_measurement=PERCENTAGE,
135  icon="mdi:white-balance-sunny",
136  ),
137  "V_FLOW": SensorEntityDescription(
138  # The documentation on this measurement is inconsistent.
139  # Better not to set a device class here yet.
140  key="V_FLOW",
141  native_unit_of_measurement=UnitOfLength.METERS,
142  icon="mdi:gauge",
143  ),
144  "V_VOLUME": SensorEntityDescription(
145  key="V_VOLUME",
146  native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
147  device_class=SensorDeviceClass.VOLUME,
148  ),
149  "V_LEVEL_S_SOUND": SensorEntityDescription(
150  key="V_LEVEL_S_SOUND",
151  native_unit_of_measurement=UnitOfSoundPressure.DECIBEL,
152  device_class=SensorDeviceClass.SOUND_PRESSURE,
153  ),
154  "V_LEVEL_S_VIBRATION": SensorEntityDescription(
155  key="V_LEVEL_S_VIBRATION",
156  native_unit_of_measurement=UnitOfFrequency.HERTZ,
157  ),
158  "V_LEVEL_S_LIGHT_LEVEL": SensorEntityDescription(
159  key="V_LEVEL_S_LIGHT_LEVEL",
160  native_unit_of_measurement=LIGHT_LUX,
161  device_class=SensorDeviceClass.ILLUMINANCE,
162  state_class=SensorStateClass.MEASUREMENT,
163  ),
164  "V_LEVEL_S_MOISTURE": SensorEntityDescription(
165  key="V_LEVEL_S_MOISTURE",
166  native_unit_of_measurement=PERCENTAGE,
167  icon="mdi:water-percent",
168  ),
169  "V_VOLTAGE": SensorEntityDescription(
170  key="V_VOLTAGE",
171  native_unit_of_measurement=UnitOfElectricPotential.VOLT,
172  device_class=SensorDeviceClass.VOLTAGE,
173  state_class=SensorStateClass.MEASUREMENT,
174  ),
175  "V_CURRENT": SensorEntityDescription(
176  key="V_CURRENT",
177  native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
178  device_class=SensorDeviceClass.CURRENT,
179  state_class=SensorStateClass.MEASUREMENT,
180  ),
181  "V_IR_RECORD": SensorEntityDescription(
182  key="V_IR_RECORD",
183  icon="mdi:remote",
184  ),
185  "V_PH": SensorEntityDescription(
186  key="V_PH",
187  native_unit_of_measurement="pH",
188  ),
189  "V_ORP": SensorEntityDescription(
190  key="V_ORP",
191  native_unit_of_measurement=UnitOfElectricPotential.MILLIVOLT,
192  device_class=SensorDeviceClass.VOLTAGE,
193  ),
194  "V_EC": SensorEntityDescription(
195  key="V_EC",
196  native_unit_of_measurement=UnitOfConductivity.MICROSIEMENS_PER_CM,
197  ),
198  "V_VAR": SensorEntityDescription(
199  key="V_VAR",
200  native_unit_of_measurement=UnitOfReactivePower.VOLT_AMPERE_REACTIVE,
201  ),
202  "V_VA": SensorEntityDescription(
203  key="V_VA",
204  native_unit_of_measurement=UnitOfApparentPower.VOLT_AMPERE,
205  device_class=SensorDeviceClass.APPARENT_POWER,
206  ),
207 }
208 
209 
211  hass: HomeAssistant,
212  config_entry: ConfigEntry,
213  async_add_entities: AddEntitiesCallback,
214 ) -> None:
215  """Set up this platform for a specific ConfigEntry(==Gateway)."""
216 
217  async def async_discover(discovery_info: DiscoveryInfo) -> None:
218  """Discover and add a MySensors sensor."""
220  hass,
221  Platform.SENSOR,
222  discovery_info,
223  MySensorsSensor,
224  async_add_entities=async_add_entities,
225  )
226 
227  @callback
228  def async_node_discover(discovery_info: NodeDiscoveryInfo) -> None:
229  """Add battery sensor for each MySensors node."""
230  gateway_id = discovery_info[ATTR_GATEWAY_ID]
231  node_id = discovery_info[ATTR_NODE_ID]
232  gateway: BaseAsyncGateway = hass.data[DOMAIN][MYSENSORS_GATEWAYS][gateway_id]
233  async_add_entities([MyBatterySensor(gateway_id, gateway, node_id)])
234 
235  on_unload(
236  hass,
237  config_entry.entry_id,
239  hass,
240  MYSENSORS_DISCOVERY.format(config_entry.entry_id, Platform.SENSOR),
241  async_discover,
242  ),
243  )
244 
245  on_unload(
246  hass,
247  config_entry.entry_id,
249  hass,
250  MYSENSORS_NODE_DISCOVERY,
251  async_node_discover,
252  ),
253  )
254 
255 
257  """Battery sensor of MySensors node."""
258 
259  _attr_device_class = SensorDeviceClass.BATTERY
260  _attr_state_class = SensorStateClass.MEASUREMENT
261  _attr_native_unit_of_measurement = PERCENTAGE
262  _attr_force_update = True
263 
264  @property
265  def unique_id(self) -> str:
266  """Return a unique ID for use in home assistant."""
267  return f"{self.gateway_id}-{self.node_id}-battery"
268 
269  @property
270  def name(self) -> str:
271  """Return the name of this entity."""
272  return f"{self.node_name} Battery"
273 
274  @callback
275  def _async_update_callback(self) -> None:
276  """Update the controller with the latest battery level."""
277  self._attr_native_value_attr_native_value = self._node_node.battery_level
278  self.async_write_ha_stateasync_write_ha_state()
279 
280 
282  """Representation of a MySensors Sensor child node."""
283 
284  _attr_force_update = True
285 
286  def __init__(self, *args: Any, **kwargs: Any) -> None:
287  """Set up the instance."""
288  super().__init__(*args, **kwargs)
289  if entity_description := self._get_entity_description_get_entity_description():
290  self.entity_descriptionentity_description = entity_description
291 
292  @property
293  def native_value(self) -> str | None:
294  """Return the state of the sensor."""
295  return self._values.get(self.value_type)
296 
297  @property
298  def native_unit_of_measurement(self) -> str | None:
299  """Return the unit of measurement of this entity."""
300  set_req = self.gateway.const.SetReq
301  if (
302  AwesomeVersion(self.gateway.protocol_version) >= AwesomeVersion("1.5")
303  and set_req.V_UNIT_PREFIX in self._values
304  ):
305  custom_unit: str = self._values[set_req.V_UNIT_PREFIX]
306  return custom_unit
307 
308  if set_req(self.value_type) == set_req.V_TEMP:
309  if self.hasshass.config.units is METRIC_SYSTEM:
310  return UnitOfTemperature.CELSIUS
311  return UnitOfTemperature.FAHRENHEIT
312 
313  if hasattr(self, "entity_description"):
314  return self.entity_descriptionentity_description.native_unit_of_measurement
315  return None
316 
317  def _get_entity_description(self) -> SensorEntityDescription | None:
318  """Return the sensor entity description."""
319  set_req = self.gateway.const.SetReq
320  entity_description = SENSORS.get(set_req(self.value_type).name)
321 
322  if not entity_description:
323  presentation = self.gateway.const.Presentation
324  entity_description = SENSORS.get(
325  f"{set_req(self.value_type).name}_{presentation(self.child_type).name}"
326  )
327 
328  return entity_description
SensorEntityDescription|None _get_entity_description(self)
Definition: sensor.py:317
None __init__(self, *Any args, **Any kwargs)
Definition: sensor.py:286
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
None on_unload(HomeAssistant hass, GatewayId gateway_id, Callable fnct)
Definition: helpers.py:45
None async_discover(DiscoveryInfo discovery_info)
Definition: sensor.py:217
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:214
None async_node_discover(NodeDiscoveryInfo discovery_info)
Definition: sensor.py:228
list[MySensorsChildEntity]|None setup_mysensors_platform(HomeAssistant hass, Platform domain, DiscoveryInfo discovery_info, type[MySensorsChildEntity]|Mapping[SensorType, type[MySensorsChildEntity]] device_class,(tuple|None) device_args=None, Callable|None async_add_entities=None)
Definition: __init__.py:112
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103