Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for HERE travel time sensors."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Mapping
6 from datetime import timedelta
7 from typing import Any
8 
10  RestoreSensor,
11  SensorDeviceClass,
12  SensorEntityDescription,
13  SensorStateClass,
14 )
15 from homeassistant.config_entries import ConfigEntry
16 from homeassistant.const import (
17  ATTR_ATTRIBUTION,
18  ATTR_LATITUDE,
19  ATTR_LONGITUDE,
20  CONF_MODE,
21  CONF_NAME,
22  UnitOfLength,
23  UnitOfTime,
24 )
25 from homeassistant.core import HomeAssistant, callback
26 from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
27 from homeassistant.helpers.entity_platform import AddEntitiesCallback
28 from homeassistant.helpers.update_coordinator import CoordinatorEntity
29 
30 from .const import (
31  ATTR_DESTINATION,
32  ATTR_DESTINATION_NAME,
33  ATTR_DISTANCE,
34  ATTR_DURATION,
35  ATTR_DURATION_IN_TRAFFIC,
36  ATTR_ORIGIN,
37  ATTR_ORIGIN_NAME,
38  DOMAIN,
39  ICON_CAR,
40  ICONS,
41 )
42 from .coordinator import (
43  HERERoutingDataUpdateCoordinator,
44  HERETransitDataUpdateCoordinator,
45 )
46 
47 SCAN_INTERVAL = timedelta(minutes=5)
48 
49 
50 def sensor_descriptions(travel_mode: str) -> tuple[SensorEntityDescription, ...]:
51  """Construct SensorEntityDescriptions."""
52  return (
54  translation_key="duration",
55  icon=ICONS.get(travel_mode, ICON_CAR),
56  key=ATTR_DURATION,
57  state_class=SensorStateClass.MEASUREMENT,
58  native_unit_of_measurement=UnitOfTime.MINUTES,
59  ),
61  translation_key="duration_in_traffic",
62  icon=ICONS.get(travel_mode, ICON_CAR),
63  key=ATTR_DURATION_IN_TRAFFIC,
64  state_class=SensorStateClass.MEASUREMENT,
65  native_unit_of_measurement=UnitOfTime.MINUTES,
66  ),
68  translation_key="distance",
69  icon=ICONS.get(travel_mode, ICON_CAR),
70  key=ATTR_DISTANCE,
71  state_class=SensorStateClass.MEASUREMENT,
72  device_class=SensorDeviceClass.DISTANCE,
73  native_unit_of_measurement=UnitOfLength.KILOMETERS,
74  ),
75  )
76 
77 
79  hass: HomeAssistant,
80  config_entry: ConfigEntry,
81  async_add_entities: AddEntitiesCallback,
82 ) -> None:
83  """Add HERE travel time entities from a config_entry."""
84 
85  entry_id = config_entry.entry_id
86  name = config_entry.data[CONF_NAME]
87  coordinator = hass.data[DOMAIN][entry_id]
88 
89  sensors: list[HERETravelTimeSensor] = [
91  entry_id,
92  name,
93  sensor_description,
94  coordinator,
95  )
96  for sensor_description in sensor_descriptions(config_entry.data[CONF_MODE])
97  ]
98  sensors.append(OriginSensor(entry_id, name, coordinator))
99  sensors.append(DestinationSensor(entry_id, name, coordinator))
100  async_add_entities(sensors)
101 
102 
104  CoordinatorEntity[
105  HERERoutingDataUpdateCoordinator | HERETransitDataUpdateCoordinator
106  ],
107  RestoreSensor,
108 ):
109  """Representation of a HERE travel time sensor."""
110 
111  _attr_has_entity_name = True
112 
113  def __init__(
114  self,
115  unique_id_prefix: str,
116  name: str,
117  sensor_description: SensorEntityDescription,
118  coordinator: HERERoutingDataUpdateCoordinator
119  | HERETransitDataUpdateCoordinator,
120  ) -> None:
121  """Initialize the sensor."""
122  super().__init__(coordinator)
123  self.entity_descriptionentity_description = sensor_description
124  self._attr_unique_id_attr_unique_id = f"{unique_id_prefix}_{sensor_description.key}"
125  self._attr_device_info_attr_device_info = DeviceInfo(
126  identifiers={(DOMAIN, unique_id_prefix)},
127  entry_type=DeviceEntryType.SERVICE,
128  name=name,
129  manufacturer="HERE Technologies",
130  )
131 
132  async def _async_restore_state(self) -> None:
133  """Restore state."""
134  if restored_data := await self.async_get_last_sensor_dataasync_get_last_sensor_data():
135  self._attr_native_value_attr_native_value = restored_data.native_value
136 
137  async def async_added_to_hass(self) -> None:
138  """Wait for start so origin and destination entities can be resolved."""
139  await self._async_restore_state_async_restore_state()
140  await super().async_added_to_hass()
141 
142  @callback
143  def _handle_coordinator_update(self) -> None:
144  """Handle updated data from the coordinator."""
145  if self.coordinator.data is not None:
146  self._attr_native_value_attr_native_value = self.coordinator.data.get( # type: ignore[assignment]
147  self.entity_descriptionentity_description.key
148  )
149  self.async_write_ha_stateasync_write_ha_state()
150 
151  @property
152  def attribution(self) -> str | None:
153  """Return the attribution."""
154  if self.coordinator.data is not None:
155  if (attribution := self.coordinator.data.get(ATTR_ATTRIBUTION)) is not None:
156  return str(attribution)
157  return None
158 
159 
161  """Sensor holding information about the route origin."""
162 
163  def __init__(
164  self,
165  unique_id_prefix: str,
166  name: str,
167  coordinator: HERERoutingDataUpdateCoordinator,
168  ) -> None:
169  """Initialize the sensor."""
170  sensor_description = SensorEntityDescription(
171  translation_key="origin",
172  icon="mdi:store-marker",
173  key=ATTR_ORIGIN_NAME,
174  )
175  super().__init__(unique_id_prefix, name, sensor_description, coordinator)
176 
177  @property
178  def extra_state_attributes(self) -> Mapping[str, Any] | None:
179  """GPS coordinates."""
180  if self.coordinator.data is not None:
181  return {
182  ATTR_LATITUDE: self.coordinator.data[ATTR_ORIGIN].split(",")[0],
183  ATTR_LONGITUDE: self.coordinator.data[ATTR_ORIGIN].split(",")[1],
184  }
185  return None
186 
187 
189  """Sensor holding information about the route destination."""
190 
191  def __init__(
192  self,
193  unique_id_prefix: str,
194  name: str,
195  coordinator: HERERoutingDataUpdateCoordinator,
196  ) -> None:
197  """Initialize the sensor."""
198  sensor_description = SensorEntityDescription(
199  translation_key="destination",
200  icon="mdi:store-marker",
201  key=ATTR_DESTINATION_NAME,
202  )
203  super().__init__(unique_id_prefix, name, sensor_description, coordinator)
204 
205  @property
206  def extra_state_attributes(self) -> Mapping[str, Any] | None:
207  """GPS coordinates."""
208  if self.coordinator.data is not None:
209  return {
210  ATTR_LATITUDE: self.coordinator.data[ATTR_DESTINATION].split(",")[0],
211  ATTR_LONGITUDE: self.coordinator.data[ATTR_DESTINATION].split(",")[1],
212  }
213  return None
None __init__(self, str unique_id_prefix, str name, HERERoutingDataUpdateCoordinator coordinator)
Definition: sensor.py:196
None __init__(self, str unique_id_prefix, str name, SensorEntityDescription sensor_description, HERERoutingDataUpdateCoordinator|HERETransitDataUpdateCoordinator coordinator)
Definition: sensor.py:120
None __init__(self, str unique_id_prefix, str name, HERERoutingDataUpdateCoordinator coordinator)
Definition: sensor.py:168
SensorExtraStoredData|None async_get_last_sensor_data(self)
Definition: __init__.py:934
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:82
tuple[SensorEntityDescription,...] sensor_descriptions(str travel_mode)
Definition: sensor.py:50