Home Assistant Unofficial Reference 2024.12.1
device_tracker.py
Go to the documentation of this file.
1 """Support for Tile device trackers."""
2 
3 from __future__ import annotations
4 
5 import logging
6 
7 from pytile.tile import Tile
8 
9 from homeassistant.components.device_tracker import AsyncSeeCallback, TrackerEntity
10 from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
11 from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
12 from homeassistant.core import HomeAssistant, callback
13 from homeassistant.helpers.device_registry import DeviceInfo
14 from homeassistant.helpers.entity_platform import AddEntitiesCallback
15 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
17  CoordinatorEntity,
18  DataUpdateCoordinator,
19 )
20 from homeassistant.util.dt import as_utc
21 
22 from . import TileData
23 from .const import DOMAIN
24 
25 _LOGGER = logging.getLogger(__name__)
26 
27 ATTR_ALTITUDE = "altitude"
28 ATTR_CONNECTION_STATE = "connection_state"
29 ATTR_IS_DEAD = "is_dead"
30 ATTR_IS_LOST = "is_lost"
31 ATTR_LAST_LOST_TIMESTAMP = "last_lost_timestamp"
32 ATTR_LAST_TIMESTAMP = "last_timestamp"
33 ATTR_RING_STATE = "ring_state"
34 ATTR_TILE_NAME = "tile_name"
35 ATTR_VOIP_STATE = "voip_state"
36 
37 
39  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
40 ) -> None:
41  """Set up Tile device trackers."""
42  data: TileData = hass.data[DOMAIN][entry.entry_id]
43 
45  [
46  TileDeviceTracker(entry, data.coordinators[tile_uuid], tile)
47  for tile_uuid, tile in data.tiles.items()
48  ]
49  )
50 
51 
53  hass: HomeAssistant,
54  config: ConfigType,
55  async_see: AsyncSeeCallback,
56  discovery_info: DiscoveryInfoType | None = None,
57 ) -> bool:
58  """Detect a legacy configuration and import it."""
59  hass.async_create_task(
60  hass.config_entries.flow.async_init(
61  DOMAIN,
62  context={"source": SOURCE_IMPORT},
63  data={
64  CONF_USERNAME: config[CONF_USERNAME],
65  CONF_PASSWORD: config[CONF_PASSWORD],
66  },
67  )
68  )
69 
70  _LOGGER.debug(
71  "Your Tile configuration has been imported into the UI; "
72  "please remove it from configuration.yaml"
73  )
74 
75  return True
76 
77 
78 class TileDeviceTracker(CoordinatorEntity[DataUpdateCoordinator[None]], TrackerEntity):
79  """Representation of a network infrastructure device."""
80 
81  _attr_has_entity_name = True
82  _attr_name = None
83  _attr_translation_key = "tile"
84 
85  def __init__(
86  self, entry: ConfigEntry, coordinator: DataUpdateCoordinator[None], tile: Tile
87  ) -> None:
88  """Initialize."""
89  super().__init__(coordinator)
90 
91  self._attr_extra_state_attributes_attr_extra_state_attributes = {}
92  self._attr_unique_id_attr_unique_id = f"{entry.data[CONF_USERNAME]}_{tile.uuid}"
93  self._entry_entry = entry
94  self._tile_tile = tile
95 
96  @property
97  def available(self) -> bool:
98  """Return if entity is available."""
99  return super().available and not self._tile_tile.dead
100 
101  @property
102  def device_info(self) -> DeviceInfo:
103  """Return device info."""
104  return DeviceInfo(identifiers={(DOMAIN, self._tile_tile.uuid)}, name=self._tile_tile.name)
105 
106  @callback
107  def _handle_coordinator_update(self) -> None:
108  """Respond to a DataUpdateCoordinator update."""
109  self._update_from_latest_data_update_from_latest_data()
110  self.async_write_ha_state()
111 
112  @callback
113  def _update_from_latest_data(self) -> None:
114  """Update the entity from the latest data."""
115  self._attr_longitude_attr_longitude = (
116  None if not self._tile_tile.longitude else self._tile_tile.longitude
117  )
118  self._attr_latitude_attr_latitude = None if not self._tile_tile.latitude else self._tile_tile.latitude
119  self._attr_location_accuracy_attr_location_accuracy = (
120  0 if not self._tile_tile.accuracy else int(self._tile_tile.accuracy)
121  )
122 
123  self._attr_extra_state_attributes_attr_extra_state_attributes = {
124  ATTR_ALTITUDE: self._tile_tile.altitude,
125  ATTR_IS_LOST: self._tile_tile.lost,
126  ATTR_RING_STATE: self._tile_tile.ring_state,
127  ATTR_VOIP_STATE: self._tile_tile.voip_state,
128  }
129  for timestamp_attr in (
130  (ATTR_LAST_LOST_TIMESTAMP, self._tile_tile.lost_timestamp),
131  (ATTR_LAST_TIMESTAMP, self._tile_tile.last_timestamp),
132  ):
133  if not timestamp_attr[1]:
134  # If the API doesn't return a value for a particular timestamp
135  # attribute, skip it:
136  continue
137  self._attr_extra_state_attributes_attr_extra_state_attributes[timestamp_attr[0]] = as_utc(
138  timestamp_attr[1]
139  )
140 
141  async def async_added_to_hass(self) -> None:
142  """Handle entity which will be added."""
143  await super().async_added_to_hass()
144  self._update_from_latest_data_update_from_latest_data()
None __init__(self, ConfigEntry entry, DataUpdateCoordinator[None] coordinator, Tile tile)
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
bool async_setup_scanner(HomeAssistant hass, ConfigType config, AsyncSeeCallback async_see, DiscoveryInfoType|None discovery_info=None)
dt.datetime as_utc(dt.datetime dattim)
Definition: dt.py:132