Home Assistant Unofficial Reference 2024.12.1
alarms.py
Go to the documentation of this file.
1 """Class representing Sonos alarms."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Iterator
6 import logging
7 from typing import TYPE_CHECKING, Any
8 
9 from soco import SoCo
10 from soco.alarms import Alarm, Alarms
11 from soco.events_base import Event as SonosEvent
12 
13 from homeassistant.helpers.dispatcher import async_dispatcher_send
14 
15 from .const import DATA_SONOS, SONOS_ALARMS_UPDATED, SONOS_CREATE_ALARM
16 from .helpers import soco_error
17 from .household_coordinator import SonosHouseholdCoordinator
18 
19 if TYPE_CHECKING:
20  from .speaker import SonosSpeaker
21 
22 _LOGGER = logging.getLogger(__name__)
23 
24 
26  """Coordinator class for Sonos alarms."""
27 
28  def __init__(self, *args: Any) -> None:
29  """Initialize the data."""
30  super().__init__(*args)
31  self.alarms: Alarms = Alarms()
32  self.created_alarm_ids: set[str] = set()
33 
34  def __iter__(self) -> Iterator:
35  """Return an iterator for the known alarms."""
36  return iter(self.alarms)
37 
38  def get(self, alarm_id: str) -> Alarm | None:
39  """Get an Alarm instance."""
40  return self.alarms.get(alarm_id)
41 
43  self, soco: SoCo, update_id: int | None = None
44  ) -> None:
45  """Create and update alarms entities, return success."""
46  updated = await self.hasshass.async_add_executor_job(
47  self.update_cacheupdate_cacheupdate_cache, soco, update_id
48  )
49  if not updated:
50  return
51 
52  for alarm_id, alarm in self.alarms.alarms.items():
53  if alarm_id in self.created_alarm_ids:
54  continue
55  speaker = self.hasshass.data[DATA_SONOS].discovered.get(alarm.zone.uid)
56  if speaker:
58  self.hasshass, SONOS_CREATE_ALARM, speaker, [alarm_id]
59  )
60  async_dispatcher_send(self.hasshass, f"{SONOS_ALARMS_UPDATED}-{self.household_id}")
61 
63  self, event: SonosEvent, speaker: SonosSpeaker
64  ) -> None:
65  """Process the event payload in an async lock and update entities."""
66  event_id = event.variables["alarm_list_version"].split(":")[-1]
67  event_id = int(event_id)
68  async with self.cache_update_lockcache_update_lock:
69  if event_id <= self.last_processed_event_idlast_processed_event_id:
70  # Skip updates if this event_id has already been seen
71  return
72  speaker.event_stats.process(event)
73  await self.async_update_entitiesasync_update_entitiesasync_update_entities(speaker.soco, event_id)
74 
75  @soco_error()
76  def update_cache(self, soco: SoCo, update_id: int | None = None) -> bool:
77  """Update cache of known alarms and return if cache has changed."""
78  self.alarms.update(soco)
79 
80  if update_id and self.alarms.last_id < update_id:
81  # Skip updates if latest query result is outdated or lagging
82  return False
83 
84  if (
85  self.last_processed_event_idlast_processed_event_id
86  and self.alarms.last_id <= self.last_processed_event_idlast_processed_event_id
87  ):
88  # Skip updates already processed
89  return False
90 
91  _LOGGER.debug(
92  "Updating processed event %s from %s (was %s)",
93  self.alarms.last_id,
94  soco,
95  self.last_processed_event_idlast_processed_event_id,
96  )
97  self.last_processed_event_idlast_processed_event_id = self.alarms.last_id
98  return True
None async_update_entities(self, SoCo soco, int|None update_id=None)
Definition: alarms.py:44
Alarm|None get(self, str alarm_id)
Definition: alarms.py:38
bool update_cache(self, SoCo soco, int|None update_id=None)
Definition: alarms.py:76
None async_process_event(self, SonosEvent event, SonosSpeaker speaker)
Definition: alarms.py:64
IssData update(pyiss.ISS iss)
Definition: __init__.py:33
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)
Definition: dispatcher.py:193