Home Assistant Unofficial Reference 2024.12.1
geo_location.py
Go to the documentation of this file.
1 """Support for generic GeoJSON events."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable
6 import logging
7 from typing import Any
8 
9 from aio_geojson_generic_client.feed_entry import GenericFeedEntry
10 
11 from homeassistant.components.geo_location import GeolocationEvent
12 from homeassistant.config_entries import ConfigEntry
13 from homeassistant.const import UnitOfLength
14 from homeassistant.core import HomeAssistant, callback
15 from homeassistant.helpers.dispatcher import async_dispatcher_connect
16 from homeassistant.helpers.entity_platform import AddEntitiesCallback
17 
18 from . import GeoJsonFeedEntityManager
19 from .const import (
20  ATTR_EXTERNAL_ID,
21  DOMAIN,
22  SIGNAL_DELETE_ENTITY,
23  SIGNAL_UPDATE_ENTITY,
24  SOURCE,
25 )
26 
27 _LOGGER = logging.getLogger(__name__)
28 
29 
31  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
32 ) -> None:
33  """Set up the GeoJSON Events platform."""
34  manager: GeoJsonFeedEntityManager = hass.data[DOMAIN][entry.entry_id]
35 
36  @callback
37  def async_add_geolocation(
38  feed_manager: GeoJsonFeedEntityManager,
39  external_id: str,
40  ) -> None:
41  """Add geolocation entity from feed."""
42  new_entity = GeoJsonLocationEvent(feed_manager, external_id)
43  _LOGGER.debug("Adding geolocation %s", new_entity)
44  async_add_entities([new_entity], True)
45 
46  manager.listeners.append(
47  async_dispatcher_connect(hass, manager.signal_new_entity, async_add_geolocation)
48  )
49  # Do not wait for update here so that the setup can be completed and because an
50  # update will fetch data from the feed via HTTP and then process that data.
51  entry.async_create_task(hass, manager.async_update())
52  _LOGGER.debug("Geolocation setup done")
53 
54 
56  """Represents an external event with GeoJSON data."""
57 
58  _attr_should_poll = False
59  _attr_source = SOURCE
60  _attr_unit_of_measurement = UnitOfLength.KILOMETERS
61 
62  def __init__(
63  self,
64  feed_manager: GeoJsonFeedEntityManager,
65  external_id: str,
66  ) -> None:
67  """Initialize entity with data from feed entry."""
68  self._feed_manager_feed_manager = feed_manager
69  self._external_id_external_id = external_id
70  self._attr_unique_id_attr_unique_id = f"{feed_manager.entry_id}_{external_id}"
71  self._remove_signal_delete_remove_signal_delete: Callable[[], None]
72  self._remove_signal_update_remove_signal_update: Callable[[], None]
73 
74  async def async_added_to_hass(self) -> None:
75  """Call when entity is added to hass."""
76  self._remove_signal_delete_remove_signal_delete = async_dispatcher_connect(
77  self.hasshass,
78  SIGNAL_DELETE_ENTITY.format(self._external_id_external_id),
79  self._delete_callback_delete_callback,
80  )
81  self._remove_signal_update_remove_signal_update = async_dispatcher_connect(
82  self.hasshass,
83  SIGNAL_UPDATE_ENTITY.format(self._external_id_external_id),
84  self._update_callback_update_callback,
85  )
86 
87  @callback
88  def _delete_callback(self) -> None:
89  """Remove this entity."""
90  self._remove_signal_delete_remove_signal_delete()
91  self._remove_signal_update_remove_signal_update()
92  self.hasshass.async_create_task(self.async_removeasync_remove(force_remove=True))
93 
94  @callback
95  def _update_callback(self) -> None:
96  """Call update method."""
97  self.async_schedule_update_ha_stateasync_schedule_update_ha_state(True)
98 
99  async def async_update(self) -> None:
100  """Update this entity from the data held in the feed manager."""
101  _LOGGER.debug("Updating %s", self._external_id_external_id)
102  feed_entry = self._feed_manager_feed_manager.get_entry(self._external_id_external_id)
103  if feed_entry:
104  self._update_from_feed_update_from_feed(feed_entry)
105 
106  def _update_from_feed(self, feed_entry: GenericFeedEntry) -> None:
107  """Update the internal state from the provided feed entry."""
108  if feed_entry.properties and "name" in feed_entry.properties:
109  # The entry name's type can vary, but our own name must be a string
110  self._attr_name_attr_name = str(feed_entry.properties["name"])
111  else:
112  self._attr_name_attr_name = feed_entry.title
113  self._attr_distance_attr_distance = feed_entry.distance_to_home
114  self._attr_latitude_attr_latitude = feed_entry.coordinates[0]
115  self._attr_longitude_attr_longitude = feed_entry.coordinates[1]
116 
117  @property
118  def extra_state_attributes(self) -> dict[str, Any]:
119  """Return the device state attributes."""
120  if not self._external_id_external_id:
121  return {}
122  return {ATTR_EXTERNAL_ID: self._external_id_external_id}
None __init__(self, GeoJsonFeedEntityManager feed_manager, str external_id)
Definition: geo_location.py:66
None async_schedule_update_ha_state(self, bool force_refresh=False)
Definition: entity.py:1265
None async_remove(self, *bool force_remove=False)
Definition: entity.py:1387
config_entries.ConfigEntry|None get_entry(HomeAssistant hass, websocket_api.ActiveConnection connection, str entry_id, int msg_id)
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: geo_location.py:32
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103