Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for TPLink sensor entities."""
2 
3 from __future__ import annotations
4 
5 from dataclasses import dataclass
6 from typing import TYPE_CHECKING, cast
7 
8 from kasa import Feature
9 
11  DOMAIN as SENSOR_DOMAIN,
12  SensorDeviceClass,
13  SensorEntity,
14  SensorEntityDescription,
15  SensorStateClass,
16 )
17 from homeassistant.core import HomeAssistant, callback
18 from homeassistant.helpers.entity_platform import AddEntitiesCallback
19 
20 from . import TPLinkConfigEntry
21 from .const import UNIT_MAPPING
22 from .deprecate import async_cleanup_deprecated
23 from .entity import CoordinatedTPLinkFeatureEntity, TPLinkFeatureEntityDescription
24 
25 
26 @dataclass(frozen=True, kw_only=True)
28  SensorEntityDescription, TPLinkFeatureEntityDescription
29 ):
30  """Base class for a TPLink feature based sensor entity description."""
31 
32 
33 SENSOR_DESCRIPTIONS: tuple[TPLinkSensorEntityDescription, ...] = (
35  key="current_consumption",
36  device_class=SensorDeviceClass.POWER,
37  state_class=SensorStateClass.MEASUREMENT,
38  ),
40  key="consumption_total",
41  device_class=SensorDeviceClass.ENERGY,
42  state_class=SensorStateClass.TOTAL_INCREASING,
43  ),
45  key="consumption_today",
46  device_class=SensorDeviceClass.ENERGY,
47  state_class=SensorStateClass.TOTAL_INCREASING,
48  ),
50  key="consumption_this_month",
51  device_class=SensorDeviceClass.ENERGY,
52  state_class=SensorStateClass.TOTAL_INCREASING,
53  ),
55  key="voltage",
56  device_class=SensorDeviceClass.VOLTAGE,
57  state_class=SensorStateClass.MEASUREMENT,
58  ),
60  key="current",
61  device_class=SensorDeviceClass.CURRENT,
62  state_class=SensorStateClass.MEASUREMENT,
63  ),
65  key="temperature",
66  device_class=SensorDeviceClass.TEMPERATURE,
67  state_class=SensorStateClass.MEASUREMENT,
68  ),
70  # Disable as the value reported by the device changes seconds frequently
71  entity_registry_enabled_default=False,
72  key="on_since",
73  device_class=SensorDeviceClass.TIMESTAMP,
74  ),
76  key="rssi",
77  device_class=SensorDeviceClass.SIGNAL_STRENGTH,
78  state_class=SensorStateClass.MEASUREMENT,
79  ),
81  key="signal_level",
82  state_class=SensorStateClass.MEASUREMENT,
83  ),
85  key="ssid",
86  ),
88  key="battery_level",
89  device_class=SensorDeviceClass.BATTERY,
90  state_class=SensorStateClass.MEASUREMENT,
91  ),
93  key="auto_off_at",
94  device_class=SensorDeviceClass.TIMESTAMP,
95  ),
97  key="device_time",
98  device_class=SensorDeviceClass.TIMESTAMP,
99  ),
101  key="water_alert_timestamp",
102  device_class=SensorDeviceClass.TIMESTAMP,
103  ),
105  key="humidity",
106  device_class=SensorDeviceClass.HUMIDITY,
107  state_class=SensorStateClass.MEASUREMENT,
108  ),
110  key="report_interval",
111  device_class=SensorDeviceClass.DURATION,
112  ),
114  key="alarm_source",
115  ),
117  key="temperature",
118  device_class=SensorDeviceClass.TEMPERATURE,
119  state_class=SensorStateClass.MEASUREMENT,
120  ),
121 )
122 
123 SENSOR_DESCRIPTIONS_MAP = {desc.key: desc for desc in SENSOR_DESCRIPTIONS}
124 
125 
127  hass: HomeAssistant,
128  config_entry: TPLinkConfigEntry,
129  async_add_entities: AddEntitiesCallback,
130 ) -> None:
131  """Set up sensors."""
132  data = config_entry.runtime_data
133  parent_coordinator = data.parent_coordinator
134  children_coordinators = data.children_coordinators
135  device = parent_coordinator.device
136 
137  entities = CoordinatedTPLinkFeatureEntity.entities_for_device_and_its_children(
138  hass=hass,
139  device=device,
140  coordinator=parent_coordinator,
141  feature_type=Feature.Type.Sensor,
142  entity_class=TPLinkSensorEntity,
143  descriptions=SENSOR_DESCRIPTIONS_MAP,
144  child_coordinators=children_coordinators,
145  )
146  async_cleanup_deprecated(hass, SENSOR_DOMAIN, config_entry.entry_id, entities)
147  async_add_entities(entities)
148 
149 
151  """Representation of a feature-based TPLink sensor."""
152 
153  entity_description: TPLinkSensorEntityDescription
154 
155  @callback
156  def _async_update_attrs(self) -> None:
157  """Update the entity's attributes."""
158  value = self._feature_feature.value
159  if value is not None and self._feature_feature.precision_hint is not None:
160  value = round(cast(float, value), self._feature_feature.precision_hint)
161  # We probably do not need this, when we are rounding already?
162  self._attr_suggested_display_precision_attr_suggested_display_precision = self._feature_feature.precision_hint
163 
164  if TYPE_CHECKING:
165  # pylint: disable-next=import-outside-toplevel
166  from datetime import date, datetime
167 
168  assert isinstance(value, str | int | float | date | datetime | None)
169 
170  self._attr_native_value_attr_native_value = value
171  # Map to homeassistant units and fallback to upstream one if none found
172  if (unit := self._feature_feature.unit) is not None:
173  self._attr_native_unit_of_measurement_attr_native_unit_of_measurement = UNIT_MAPPING.get(unit, unit)