Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for refoss sensors."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable
6 from dataclasses import dataclass
7 
8 from refoss_ha.controller.electricity import ElectricityXMix
9 
11  SensorDeviceClass,
12  SensorEntity,
13  SensorEntityDescription,
14  SensorStateClass,
15 )
16 from homeassistant.config_entries import ConfigEntry
17 from homeassistant.const import (
18  UnitOfElectricCurrent,
19  UnitOfElectricPotential,
20  UnitOfEnergy,
21  UnitOfPower,
22 )
23 from homeassistant.core import HomeAssistant, callback
24 from homeassistant.helpers.dispatcher import async_dispatcher_connect
25 from homeassistant.helpers.entity_platform import AddEntitiesCallback
26 from homeassistant.helpers.typing import StateType
27 
28 from .bridge import RefossDataUpdateCoordinator
29 from .const import (
30  CHANNEL_DISPLAY_NAME,
31  COORDINATORS,
32  DISPATCH_DEVICE_DISCOVERED,
33  DOMAIN,
34  SENSOR_EM,
35 )
36 from .entity import RefossEntity
37 
38 
39 @dataclass(frozen=True, kw_only=True)
41  """Describes Refoss sensor entity."""
42 
43  subkey: str
44  fn: Callable[[float], float] = lambda x: x
45 
46 
47 DEVICETYPE_SENSOR: dict[str, str] = {
48  "em06": SENSOR_EM,
49  "em16": SENSOR_EM,
50 }
51 
52 SENSORS: dict[str, tuple[RefossSensorEntityDescription, ...]] = {
53  SENSOR_EM: (
55  key="power",
56  translation_key="power",
57  device_class=SensorDeviceClass.POWER,
58  state_class=SensorStateClass.MEASUREMENT,
59  native_unit_of_measurement=UnitOfPower.WATT,
60  suggested_display_precision=2,
61  subkey="power",
62  fn=lambda x: x / 1000.0,
63  ),
65  key="voltage",
66  translation_key="voltage",
67  device_class=SensorDeviceClass.VOLTAGE,
68  state_class=SensorStateClass.MEASUREMENT,
69  native_unit_of_measurement=UnitOfElectricPotential.MILLIVOLT,
70  suggested_display_precision=2,
71  suggested_unit_of_measurement=UnitOfElectricPotential.VOLT,
72  subkey="voltage",
73  ),
75  key="current",
76  translation_key="current",
77  device_class=SensorDeviceClass.CURRENT,
78  state_class=SensorStateClass.MEASUREMENT,
79  native_unit_of_measurement=UnitOfElectricCurrent.MILLIAMPERE,
80  suggested_display_precision=2,
81  suggested_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
82  subkey="current",
83  ),
85  key="factor",
86  translation_key="power_factor",
87  device_class=SensorDeviceClass.POWER_FACTOR,
88  state_class=SensorStateClass.MEASUREMENT,
89  suggested_display_precision=2,
90  subkey="factor",
91  ),
93  key="energy",
94  translation_key="this_month_energy",
95  device_class=SensorDeviceClass.ENERGY,
96  state_class=SensorStateClass.TOTAL,
97  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
98  suggested_display_precision=2,
99  subkey="mConsume",
100  fn=lambda x: max(0, x),
101  ),
103  key="energy_returned",
104  translation_key="this_month_energy_returned",
105  device_class=SensorDeviceClass.ENERGY,
106  state_class=SensorStateClass.TOTAL,
107  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
108  suggested_display_precision=2,
109  subkey="mConsume",
110  fn=lambda x: abs(x) if x < 0 else 0,
111  ),
112  ),
113 }
114 
115 
117  hass: HomeAssistant,
118  config_entry: ConfigEntry,
119  async_add_entities: AddEntitiesCallback,
120 ) -> None:
121  """Set up the Refoss device from a config entry."""
122 
123  @callback
124  def init_device(coordinator: RefossDataUpdateCoordinator) -> None:
125  """Register the device."""
126  device = coordinator.device
127 
128  if not isinstance(device, ElectricityXMix):
129  return
130 
131  sensor_type = DEVICETYPE_SENSOR.get(device.device_type, "")
132 
133  descriptions: tuple[RefossSensorEntityDescription, ...] = SENSORS.get(
134  sensor_type, ()
135  )
136 
138  RefossSensor(
139  coordinator=coordinator,
140  channel=channel,
141  description=description,
142  )
143  for channel in device.channels
144  for description in descriptions
145  )
146 
147  for coordinator in hass.data[DOMAIN][COORDINATORS]:
148  init_device(coordinator)
149 
150  config_entry.async_on_unload(
151  async_dispatcher_connect(hass, DISPATCH_DEVICE_DISCOVERED, init_device)
152  )
153 
154 
156  """Refoss Sensor Device."""
157 
158  entity_description: RefossSensorEntityDescription
159 
160  def __init__(
161  self,
162  coordinator: RefossDataUpdateCoordinator,
163  channel: int,
164  description: RefossSensorEntityDescription,
165  ) -> None:
166  """Init Refoss sensor."""
167  super().__init__(coordinator, channel)
168  self.entity_descriptionentity_description = description
169  self._attr_unique_id_attr_unique_id_attr_unique_id = f"{super().unique_id}{description.key}"
170  device_type = coordinator.device.device_type
171  channel_name = CHANNEL_DISPLAY_NAME[device_type][channel]
172  self._attr_translation_placeholders_attr_translation_placeholders = {"channel_name": channel_name}
173 
174  @property
175  def native_value(self) -> StateType:
176  """Return the native value."""
177  value = self.coordinator.device.get_value(
178  self.channel_idchannel_id, self.entity_descriptionentity_description.subkey
179  )
180  if value is None:
181  return None
182  return self.entity_descriptionentity_description.fn(value)
None __init__(self, RefossDataUpdateCoordinator coordinator, int channel, RefossSensorEntityDescription description)
Definition: sensor.py:165
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:120
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103