Home Assistant Unofficial Reference 2024.12.1
device_tracker.py
Go to the documentation of this file.
1 """Support for the GPSLogger device tracking."""
2 
3 from homeassistant.components.device_tracker import TrackerEntity
4 from homeassistant.config_entries import ConfigEntry
5 from homeassistant.const import (
6  ATTR_BATTERY_LEVEL,
7  ATTR_GPS_ACCURACY,
8  ATTR_LATITUDE,
9  ATTR_LONGITUDE,
10 )
11 from homeassistant.core import HomeAssistant, callback
12 from homeassistant.helpers import device_registry as dr
13 from homeassistant.helpers.device_registry import DeviceInfo
14 from homeassistant.helpers.dispatcher import async_dispatcher_connect
15 from homeassistant.helpers.entity_platform import AddEntitiesCallback
16 from homeassistant.helpers.restore_state import RestoreEntity
17 
18 from . import DOMAIN as GPL_DOMAIN, TRACKER_UPDATE
19 from .const import (
20  ATTR_ACTIVITY,
21  ATTR_ALTITUDE,
22  ATTR_DIRECTION,
23  ATTR_PROVIDER,
24  ATTR_SPEED,
25 )
26 
27 
29  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
30 ) -> None:
31  """Configure a dispatcher connection based on a config entry."""
32 
33  @callback
34  def _receive_data(device, gps, battery, accuracy, attrs):
35  """Receive set location."""
36  if device in hass.data[GPL_DOMAIN]["devices"]:
37  return
38 
39  hass.data[GPL_DOMAIN]["devices"].add(device)
40 
41  async_add_entities([GPSLoggerEntity(device, gps, battery, accuracy, attrs)])
42 
43  hass.data[GPL_DOMAIN]["unsub_device_tracker"][entry.entry_id] = (
44  async_dispatcher_connect(hass, TRACKER_UPDATE, _receive_data)
45  )
46 
47  # Restore previously loaded devices
48  dev_reg = dr.async_get(hass)
49  dev_ids = {
50  identifier[1]
51  for device in dev_reg.devices.get_devices_for_config_entry_id(entry.entry_id)
52  for identifier in device.identifiers
53  }
54  if not dev_ids:
55  return
56 
57  entities = []
58  for dev_id in dev_ids:
59  hass.data[GPL_DOMAIN]["devices"].add(dev_id)
60  entity = GPSLoggerEntity(dev_id, None, None, None, None)
61  entities.append(entity)
62 
63  async_add_entities(entities)
64 
65 
66 class GPSLoggerEntity(TrackerEntity, RestoreEntity):
67  """Represent a tracked device."""
68 
69  _attr_has_entity_name = True
70  _attr_name = None
71 
72  def __init__(self, device, location, battery, accuracy, attributes):
73  """Set up GPSLogger entity."""
74  self._attr_location_accuracy_attr_location_accuracy = accuracy
75  self._attr_extra_state_attributes_attr_extra_state_attributes = attributes
76  self._name_name = device
77  self._battery_battery = battery
78  if location:
79  self._attr_latitude_attr_latitude = location[0]
80  self._attr_longitude_attr_longitude = location[1]
81  self._unsub_dispatcher_unsub_dispatcher = None
82  self._attr_unique_id_attr_unique_id = device
83  self._attr_device_info_attr_device_info = DeviceInfo(
84  identifiers={(GPL_DOMAIN, device)},
85  name=device,
86  )
87 
88  @property
89  def battery_level(self):
90  """Return battery value of the device."""
91  return self._battery_battery
92 
93  async def async_added_to_hass(self) -> None:
94  """Register state update callback."""
95  await super().async_added_to_hass()
96  self._unsub_dispatcher_unsub_dispatcher = async_dispatcher_connect(
97  self.hasshass, TRACKER_UPDATE, self._async_receive_data_async_receive_data
98  )
99 
100  # don't restore if we got created with data
101  if self.latitude is not None:
102  return
103 
104  if (state := await self.async_get_last_stateasync_get_last_state()) is None:
105  self._attr_latitude_attr_latitude = None
106  self._attr_longitude_attr_longitude = None
107  self._attr_location_accuracy_attr_location_accuracy = 0
108  self._attr_extra_state_attributes_attr_extra_state_attributes = {
109  ATTR_ALTITUDE: None,
110  ATTR_ACTIVITY: None,
111  ATTR_DIRECTION: None,
112  ATTR_PROVIDER: None,
113  ATTR_SPEED: None,
114  }
115  self._battery_battery = None
116  return
117 
118  attr = state.attributes
119  self._attr_latitude_attr_latitude = attr.get(ATTR_LATITUDE)
120  self._attr_longitude_attr_longitude = attr.get(ATTR_LONGITUDE)
121  self._attr_location_accuracy_attr_location_accuracy = attr.get(ATTR_GPS_ACCURACY, 0)
122  self._attr_extra_state_attributes_attr_extra_state_attributes = {
123  ATTR_ALTITUDE: attr.get(ATTR_ALTITUDE),
124  ATTR_ACTIVITY: attr.get(ATTR_ACTIVITY),
125  ATTR_DIRECTION: attr.get(ATTR_DIRECTION),
126  ATTR_PROVIDER: attr.get(ATTR_PROVIDER),
127  ATTR_SPEED: attr.get(ATTR_SPEED),
128  }
129  self._battery_battery = attr.get(ATTR_BATTERY_LEVEL)
130 
131  async def async_will_remove_from_hass(self) -> None:
132  """Clean up after entity before removal."""
133  await super().async_will_remove_from_hass()
134  self._unsub_dispatcher_unsub_dispatcher()
135 
136  @callback
137  def _async_receive_data(self, device, location, battery, accuracy, attributes):
138  """Mark the device as seen."""
139  if device != self._name_name:
140  return
141 
142  self._attr_latitude_attr_latitude = location[0]
143  self._attr_longitude_attr_longitude = location[1]
144  self._battery_battery = battery
145  self._attr_location_accuracy_attr_location_accuracy = accuracy
146  self._attr_extra_state_attributes_attr_extra_state_attributes.update(attributes)
147  self.async_write_ha_stateasync_write_ha_state()
def _async_receive_data(self, device, location, battery, accuracy, attributes)
def __init__(self, device, location, battery, accuracy, attributes)
bool add(self, _T matcher)
Definition: match.py:185
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
IssData update(pyiss.ISS iss)
Definition: __init__.py:33
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103