Home Assistant Unofficial Reference 2024.12.1
geo_location.py
Go to the documentation of this file.
1 """Geolocation support for GeoNet NZ Quakes Feeds."""
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_geonetnz_quakes.feed_entry import GeonetnzQuakesFeedEntry
10 
11 from homeassistant.components.geo_location import GeolocationEvent
12 from homeassistant.config_entries import ConfigEntry
13 from homeassistant.const import ATTR_TIME, UnitOfLength
14 from homeassistant.core import HomeAssistant, callback
15 from homeassistant.helpers import entity_registry as er
16 from homeassistant.helpers.dispatcher import async_dispatcher_connect
17 from homeassistant.helpers.entity_platform import AddEntitiesCallback
18 from homeassistant.util.unit_conversion import DistanceConverter
19 from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
20 
21 from . import GeonetnzQuakesFeedEntityManager
22 from .const import DOMAIN, FEED
23 
24 _LOGGER = logging.getLogger(__name__)
25 
26 ATTR_DEPTH = "depth"
27 ATTR_EXTERNAL_ID = "external_id"
28 ATTR_LOCALITY = "locality"
29 ATTR_MAGNITUDE = "magnitude"
30 ATTR_MMI = "mmi"
31 ATTR_PUBLICATION_DATE = "publication_date"
32 ATTR_QUALITY = "quality"
33 
34 # An update of this entity is not making a web request, but uses internal data only.
35 PARALLEL_UPDATES = 0
36 
37 SOURCE = "geonetnz_quakes"
38 
39 
41  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
42 ) -> None:
43  """Set up the GeoNet NZ Quakes Feed platform."""
44  manager: GeonetnzQuakesFeedEntityManager = hass.data[DOMAIN][FEED][entry.entry_id]
45 
46  @callback
47  def async_add_geolocation(
48  feed_manager: GeonetnzQuakesFeedEntityManager,
49  integration_id: str,
50  external_id: str,
51  ) -> None:
52  """Add geolocation entity from feed."""
53  new_entity = GeonetnzQuakesEvent(feed_manager, integration_id, external_id)
54  _LOGGER.debug("Adding geolocation %s", new_entity)
55  async_add_entities([new_entity], True)
56 
57  manager.listeners.append(
59  hass, manager.async_event_new_entity(), async_add_geolocation
60  )
61  )
62  # Do not wait for update here so that the setup can be completed and because an
63  # update will fetch data from the feed via HTTP and then process that data.
64  hass.async_create_task(manager.async_update())
65  _LOGGER.debug("Geolocation setup done")
66 
67 
69  """Represents an external event with GeoNet NZ Quakes feed data."""
70 
71  _attr_icon = "mdi:pulse"
72  _attr_should_poll = False
73  _attr_source = SOURCE
74 
75  def __init__(
76  self,
77  feed_manager: GeonetnzQuakesFeedEntityManager,
78  integration_id: str,
79  external_id: str,
80  ) -> None:
81  """Initialize entity with data from feed entry."""
82  self._feed_manager_feed_manager = feed_manager
83  self._external_id_external_id = external_id
84  self._attr_unique_id_attr_unique_id = f"{integration_id}_{external_id}"
85  self._attr_unit_of_measurement_attr_unit_of_measurement = UnitOfLength.KILOMETERS
86  self._depth_depth = None
87  self._locality_locality = None
88  self._magnitude_magnitude = None
89  self._mmi_mmi = None
90  self._quality_quality = None
91  self._time_time = None
92  self._remove_signal_delete_remove_signal_delete: Callable[[], None]
93  self._remove_signal_update_remove_signal_update: Callable[[], None]
94 
95  async def async_added_to_hass(self) -> None:
96  """Call when entity is added to hass."""
97  if self.hasshass.config.units is US_CUSTOMARY_SYSTEM:
98  self._attr_unit_of_measurement_attr_unit_of_measurement = UnitOfLength.MILES
99  self._remove_signal_delete_remove_signal_delete = async_dispatcher_connect(
100  self.hasshass,
101  f"geonetnz_quakes_delete_{self._external_id}",
102  self._delete_callback_delete_callback,
103  )
104  self._remove_signal_update_remove_signal_update = async_dispatcher_connect(
105  self.hasshass,
106  f"geonetnz_quakes_update_{self._external_id}",
107  self._update_callback_update_callback,
108  )
109 
110  async def async_will_remove_from_hass(self) -> None:
111  """Call when entity will be removed from hass."""
112  self._remove_signal_delete_remove_signal_delete()
113  self._remove_signal_update_remove_signal_update()
114  # Remove from entity registry.
115  entity_registry = er.async_get(self.hasshass)
116  if self.entity_identity_id in entity_registry.entities:
117  entity_registry.async_remove(self.entity_identity_id)
118 
119  @callback
120  def _delete_callback(self) -> None:
121  """Remove this entity."""
122  self.hasshass.async_create_task(self.async_removeasync_remove(force_remove=True))
123 
124  @callback
125  def _update_callback(self) -> None:
126  """Call update method."""
127  self.async_schedule_update_ha_stateasync_schedule_update_ha_state(True)
128 
129  async def async_update(self) -> None:
130  """Update this entity from the data held in the feed manager."""
131  _LOGGER.debug("Updating %s", self._external_id_external_id)
132  feed_entry = self._feed_manager_feed_manager.get_entry(self._external_id_external_id)
133  if feed_entry:
134  self._update_from_feed_update_from_feed(feed_entry)
135 
136  def _update_from_feed(self, feed_entry: GeonetnzQuakesFeedEntry) -> None:
137  """Update the internal state from the provided feed entry."""
138  self._attr_name_attr_name = feed_entry.title
139  # Convert distance if not metric system.
140  if self.hasshass.config.units is US_CUSTOMARY_SYSTEM:
141  self._attr_distance_attr_distance = DistanceConverter.convert(
142  feed_entry.distance_to_home, UnitOfLength.KILOMETERS, UnitOfLength.MILES
143  )
144  else:
145  self._attr_distance_attr_distance = feed_entry.distance_to_home
146  self._attr_latitude_attr_latitude = feed_entry.coordinates[0]
147  self._attr_longitude_attr_longitude = feed_entry.coordinates[1]
148  self._attr_attribution_attr_attribution = feed_entry.attribution
149  self._depth_depth = feed_entry.depth
150  self._locality_locality = feed_entry.locality
151  self._magnitude_magnitude = feed_entry.magnitude
152  self._mmi_mmi = feed_entry.mmi
153  self._quality_quality = feed_entry.quality
154  self._time_time = feed_entry.time
155 
156  @property
157  def extra_state_attributes(self) -> dict[str, Any]:
158  """Return the device state attributes."""
159  return {
160  key: value
161  for key, value in (
162  (ATTR_EXTERNAL_ID, self._external_id_external_id),
163  (ATTR_DEPTH, self._depth_depth),
164  (ATTR_LOCALITY, self._locality_locality),
165  (ATTR_MAGNITUDE, self._magnitude_magnitude),
166  (ATTR_MMI, self._mmi_mmi),
167  (ATTR_QUALITY, self._quality_quality),
168  (ATTR_TIME, self._time_time),
169  )
170  if value or isinstance(value, bool)
171  }
None _update_from_feed(self, GeonetnzQuakesFeedEntry feed_entry)
None __init__(self, GeonetnzQuakesFeedEntityManager feed_manager, str integration_id, str external_id)
Definition: geo_location.py:80
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:42
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103