Home Assistant Unofficial Reference 2024.12.1
device_tracker.py
Go to the documentation of this file.
1 """Support for Traccar device tracking."""
2 
3 from __future__ import annotations
4 
5 from datetime import timedelta
6 import logging
7 
8 from homeassistant.components.device_tracker import TrackerEntity
9 from homeassistant.config_entries import ConfigEntry
10 from homeassistant.core import HomeAssistant, callback
11 from homeassistant.helpers import device_registry as dr
12 from homeassistant.helpers.device_registry import DeviceInfo
13 from homeassistant.helpers.dispatcher import async_dispatcher_connect
14 from homeassistant.helpers.entity_platform import AddEntitiesCallback
15 from homeassistant.helpers.restore_state import RestoreEntity
16 
17 from . import DOMAIN, TRACKER_UPDATE
18 from .const import (
19  ATTR_ACCURACY,
20  ATTR_ALTITUDE,
21  ATTR_BATTERY,
22  ATTR_BEARING,
23  ATTR_LATITUDE,
24  ATTR_LONGITUDE,
25  ATTR_SPEED,
26  EVENT_ALARM,
27  EVENT_ALL_EVENTS,
28  EVENT_COMMAND_RESULT,
29  EVENT_DEVICE_FUEL_DROP,
30  EVENT_DEVICE_MOVING,
31  EVENT_DEVICE_OFFLINE,
32  EVENT_DEVICE_ONLINE,
33  EVENT_DEVICE_OVERSPEED,
34  EVENT_DEVICE_STOPPED,
35  EVENT_DEVICE_UNKNOWN,
36  EVENT_DRIVER_CHANGED,
37  EVENT_GEOFENCE_ENTER,
38  EVENT_GEOFENCE_EXIT,
39  EVENT_IGNITION_OFF,
40  EVENT_IGNITION_ON,
41  EVENT_MAINTENANCE,
42  EVENT_TEXT_MESSAGE,
43 )
44 
45 _LOGGER = logging.getLogger(__name__)
46 
47 DEFAULT_SCAN_INTERVAL = timedelta(seconds=30)
48 SCAN_INTERVAL = DEFAULT_SCAN_INTERVAL
49 
50 EVENTS = [
51  EVENT_DEVICE_MOVING,
52  EVENT_COMMAND_RESULT,
53  EVENT_DEVICE_FUEL_DROP,
54  EVENT_GEOFENCE_ENTER,
55  EVENT_DEVICE_OFFLINE,
56  EVENT_DRIVER_CHANGED,
57  EVENT_GEOFENCE_EXIT,
58  EVENT_DEVICE_OVERSPEED,
59  EVENT_DEVICE_ONLINE,
60  EVENT_DEVICE_STOPPED,
61  EVENT_MAINTENANCE,
62  EVENT_ALARM,
63  EVENT_TEXT_MESSAGE,
64  EVENT_DEVICE_UNKNOWN,
65  EVENT_IGNITION_OFF,
66  EVENT_IGNITION_ON,
67  EVENT_ALL_EVENTS,
68 ]
69 
70 
72  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
73 ) -> None:
74  """Configure a dispatcher connection based on a config entry."""
75 
76  @callback
77  def _receive_data(device, latitude, longitude, battery, accuracy, attrs):
78  """Receive set location."""
79  if device in hass.data[DOMAIN]["devices"]:
80  return
81 
82  hass.data[DOMAIN]["devices"].add(device)
83 
85  [TraccarEntity(device, latitude, longitude, battery, accuracy, attrs)]
86  )
87 
88  hass.data[DOMAIN]["unsub_device_tracker"][entry.entry_id] = (
89  async_dispatcher_connect(hass, TRACKER_UPDATE, _receive_data)
90  )
91 
92  # Restore previously loaded devices
93  dev_reg = dr.async_get(hass)
94  dev_ids = {
95  identifier[1]
96  for device in dev_reg.devices.get_devices_for_config_entry_id(entry.entry_id)
97  for identifier in device.identifiers
98  }
99  if not dev_ids:
100  return
101 
102  entities = []
103  for dev_id in dev_ids:
104  hass.data[DOMAIN]["devices"].add(dev_id)
105  entity = TraccarEntity(dev_id, None, None, None, None, None)
106  entities.append(entity)
107 
108  async_add_entities(entities)
109 
110 
111 class TraccarEntity(TrackerEntity, RestoreEntity):
112  """Represent a tracked device."""
113 
114  _attr_has_entity_name = True
115  _attr_name = None
116 
117  def __init__(self, device, latitude, longitude, battery, accuracy, attributes):
118  """Set up Traccar entity."""
119  self._attr_location_accuracy_attr_location_accuracy = accuracy
120  self._attr_extra_state_attributes_attr_extra_state_attributes = attributes
121  self._device_device = device
122  self._battery_battery = battery
123  self._attr_latitude_attr_latitude = latitude
124  self._attr_longitude_attr_longitude = longitude
125  self._unsub_dispatcher_unsub_dispatcher = None
126  self._attr_unique_id_attr_unique_id = device
127  self._attr_device_info_attr_device_info = DeviceInfo(
128  name=device,
129  identifiers={(DOMAIN, device)},
130  )
131 
132  @property
133  def battery_level(self):
134  """Return battery value of the device."""
135  return self._battery_battery
136 
137  async def async_added_to_hass(self) -> None:
138  """Register state update callback."""
139  await super().async_added_to_hass()
140  self._unsub_dispatcher_unsub_dispatcher = async_dispatcher_connect(
141  self.hasshass, TRACKER_UPDATE, self._async_receive_data_async_receive_data
142  )
143 
144  # don't restore if we got created with data
145  if self.latitude is not None or self.longitude is not None:
146  return
147 
148  if (state := await self.async_get_last_stateasync_get_last_state()) is None:
149  self._attr_latitude_attr_latitude = None
150  self._attr_longitude_attr_longitude = None
151  self._attr_location_accuracy_attr_location_accuracy = 0
152  self._attr_extra_state_attributes_attr_extra_state_attributes = {
153  ATTR_ALTITUDE: None,
154  ATTR_BEARING: None,
155  ATTR_SPEED: None,
156  }
157  self._battery_battery = None
158  return
159 
160  attr = state.attributes
161  self._attr_latitude_attr_latitude = attr.get(ATTR_LATITUDE)
162  self._attr_longitude_attr_longitude = attr.get(ATTR_LONGITUDE)
163  self._attr_location_accuracy_attr_location_accuracy = attr.get(ATTR_ACCURACY, 0)
164  self._attr_extra_state_attributes_attr_extra_state_attributes = {
165  ATTR_ALTITUDE: attr.get(ATTR_ALTITUDE),
166  ATTR_BEARING: attr.get(ATTR_BEARING),
167  ATTR_SPEED: attr.get(ATTR_SPEED),
168  }
169  self._battery_battery = attr.get(ATTR_BATTERY)
170 
171  async def async_will_remove_from_hass(self) -> None:
172  """Clean up after entity before removal."""
173  await super().async_will_remove_from_hass()
174  self._unsub_dispatcher_unsub_dispatcher()
175 
176  @callback
178  self, device, latitude, longitude, battery, accuracy, attributes
179  ):
180  """Mark the device as seen."""
181  if device != self._device_device:
182  return
183 
184  self._attr_latitude_attr_latitude = latitude
185  self._attr_longitude_attr_longitude = longitude
186  self._battery_battery = battery
187  self._attr_location_accuracy_attr_location_accuracy = accuracy
188  self._attr_extra_state_attributes_attr_extra_state_attributes.update(attributes)
189  self.async_write_ha_stateasync_write_ha_state()
def _async_receive_data(self, device, latitude, longitude, battery, accuracy, attributes)
def __init__(self, device, latitude, longitude, battery, accuracy, attributes)
bool add(self, _T matcher)
Definition: match.py:185
IssData update(pyiss.ISS iss)
Definition: __init__.py:33
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103