Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for Tractive sensors."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable
6 from dataclasses import dataclass
7 from typing import Any
8 
10  SensorDeviceClass,
11  SensorEntity,
12  SensorEntityDescription,
13  SensorStateClass,
14 )
15 from homeassistant.const import (
16  ATTR_BATTERY_LEVEL,
17  PERCENTAGE,
18  EntityCategory,
19  UnitOfTime,
20 )
21 from homeassistant.core import HomeAssistant, callback
22 from homeassistant.helpers.entity_platform import AddEntitiesCallback
23 from homeassistant.helpers.typing import StateType
24 
25 from . import Trackables, TractiveClient, TractiveConfigEntry
26 from .const import (
27  ATTR_ACTIVITY_LABEL,
28  ATTR_CALORIES,
29  ATTR_DAILY_GOAL,
30  ATTR_MINUTES_ACTIVE,
31  ATTR_MINUTES_DAY_SLEEP,
32  ATTR_MINUTES_NIGHT_SLEEP,
33  ATTR_MINUTES_REST,
34  ATTR_SLEEP_LABEL,
35  ATTR_TRACKER_STATE,
36  TRACKER_HARDWARE_STATUS_UPDATED,
37  TRACKER_WELLNESS_STATUS_UPDATED,
38 )
39 from .entity import TractiveEntity
40 
41 
42 @dataclass(frozen=True, kw_only=True)
44  """Class describing Tractive sensor entities."""
45 
46  signal_prefix: str
47 
48  hardware_sensor: bool = False
49  value_fn: Callable[[StateType], StateType] = lambda state: state
50 
51 
53  """Tractive sensor."""
54 
55  entity_description: TractiveSensorEntityDescription
56 
57  def __init__(
58  self,
59  client: TractiveClient,
60  item: Trackables,
61  description: TractiveSensorEntityDescription,
62  ) -> None:
63  """Initialize sensor entity."""
64  if description.hardware_sensor:
65  dispatcher_signal = (
66  f"{description.signal_prefix}-{item.tracker_details['_id']}"
67  )
68  else:
69  dispatcher_signal = f"{description.signal_prefix}-{item.trackable['_id']}"
70  super().__init__(
71  client, item.trackable, item.tracker_details, dispatcher_signal
72  )
73 
74  self._attr_unique_id_attr_unique_id = f"{item.trackable['_id']}_{description.key}"
75  self._attr_available_attr_available_attr_available = False
76  self.entity_descriptionentity_description = description
77 
78  @callback
79  def handle_status_update(self, event: dict[str, Any]) -> None:
80  """Handle status update."""
81  self._attr_native_value_attr_native_value = self.entity_descriptionentity_description.value_fn(
82  event[self.entity_descriptionentity_description.key]
83  )
84 
85  super().handle_status_update(event)
86 
87 
88 SENSOR_TYPES: tuple[TractiveSensorEntityDescription, ...] = (
90  key=ATTR_BATTERY_LEVEL,
91  translation_key="tracker_battery_level",
92  native_unit_of_measurement=PERCENTAGE,
93  device_class=SensorDeviceClass.BATTERY,
94  signal_prefix=TRACKER_HARDWARE_STATUS_UPDATED,
95  hardware_sensor=True,
96  entity_category=EntityCategory.DIAGNOSTIC,
97  ),
99  key=ATTR_TRACKER_STATE,
100  translation_key="tracker_state",
101  signal_prefix=TRACKER_HARDWARE_STATUS_UPDATED,
102  hardware_sensor=True,
103  entity_category=EntityCategory.DIAGNOSTIC,
104  device_class=SensorDeviceClass.ENUM,
105  options=[
106  "inaccurate_position",
107  "not_reporting",
108  "operational",
109  "system_shutdown_user",
110  "system_startup",
111  ],
112  ),
114  key=ATTR_MINUTES_ACTIVE,
115  translation_key="activity_time",
116  native_unit_of_measurement=UnitOfTime.MINUTES,
117  signal_prefix=TRACKER_WELLNESS_STATUS_UPDATED,
118  state_class=SensorStateClass.TOTAL,
119  ),
121  key=ATTR_MINUTES_REST,
122  translation_key="rest_time",
123  native_unit_of_measurement=UnitOfTime.MINUTES,
124  signal_prefix=TRACKER_WELLNESS_STATUS_UPDATED,
125  state_class=SensorStateClass.TOTAL,
126  ),
128  key=ATTR_CALORIES,
129  translation_key="calories",
130  native_unit_of_measurement="kcal",
131  signal_prefix=TRACKER_WELLNESS_STATUS_UPDATED,
132  state_class=SensorStateClass.TOTAL,
133  ),
135  key=ATTR_DAILY_GOAL,
136  translation_key="daily_goal",
137  native_unit_of_measurement=UnitOfTime.MINUTES,
138  signal_prefix=TRACKER_WELLNESS_STATUS_UPDATED,
139  ),
141  key=ATTR_MINUTES_DAY_SLEEP,
142  translation_key="minutes_day_sleep",
143  native_unit_of_measurement=UnitOfTime.MINUTES,
144  signal_prefix=TRACKER_WELLNESS_STATUS_UPDATED,
145  state_class=SensorStateClass.TOTAL,
146  ),
148  key=ATTR_MINUTES_NIGHT_SLEEP,
149  translation_key="minutes_night_sleep",
150  native_unit_of_measurement=UnitOfTime.MINUTES,
151  signal_prefix=TRACKER_WELLNESS_STATUS_UPDATED,
152  state_class=SensorStateClass.TOTAL,
153  ),
155  key=ATTR_SLEEP_LABEL,
156  translation_key="sleep",
157  signal_prefix=TRACKER_WELLNESS_STATUS_UPDATED,
158  value_fn=lambda state: state.lower() if isinstance(state, str) else state,
159  device_class=SensorDeviceClass.ENUM,
160  options=[
161  "good",
162  "low",
163  "ok",
164  ],
165  ),
167  key=ATTR_ACTIVITY_LABEL,
168  translation_key="activity",
169  signal_prefix=TRACKER_WELLNESS_STATUS_UPDATED,
170  value_fn=lambda state: state.lower() if isinstance(state, str) else state,
171  device_class=SensorDeviceClass.ENUM,
172  options=[
173  "good",
174  "low",
175  "ok",
176  ],
177  ),
178 )
179 
180 
182  hass: HomeAssistant,
183  entry: TractiveConfigEntry,
184  async_add_entities: AddEntitiesCallback,
185 ) -> None:
186  """Set up Tractive device trackers."""
187  client = entry.runtime_data.client
188  trackables = entry.runtime_data.trackables
189 
190  entities = [
191  TractiveSensor(client, item, description)
192  for description in SENSOR_TYPES
193  for item in trackables
194  ]
195 
196  async_add_entities(entities)
None __init__(self, TractiveClient client, Trackables item, TractiveSensorEntityDescription description)
Definition: sensor.py:62
None handle_status_update(self, dict[str, Any] event)
Definition: sensor.py:79
None async_setup_entry(HomeAssistant hass, TractiveConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:185