[#340] Better state management for alarms.

- Added `AlarmEnabledEvent` and `AlarmDisabledEvent`.
- Added `snooze_interval` configurable both at plugin level and alarm
  level.
This commit is contained in:
Fabio Manganiello 2023-12-09 17:12:20 +01:00
parent 34e2a59285
commit f27e7bb7e2
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
4 changed files with 54 additions and 9 deletions

View file

@ -4,43 +4,54 @@ from platypush.message.event import Event
class AlarmEvent(Event): class AlarmEvent(Event):
def __init__(self, name: Optional[str] = None, *args, **kwargs): """
Base class for alarm events.
"""
def __init__(self, *args, name: Optional[str] = None, **kwargs):
super().__init__(*args, name=name, **kwargs) super().__init__(*args, name=name, **kwargs)
class AlarmEnabledEvent(AlarmEvent):
"""
Triggered when an alarm is enabled.
"""
class AlarmDisabledEvent(AlarmEvent):
"""
Triggered when an alarm is disabled.
"""
class AlarmStartedEvent(AlarmEvent): class AlarmStartedEvent(AlarmEvent):
""" """
Triggered when an alarm starts. Triggered when an alarm starts.
""" """
pass
class AlarmEndedEvent(AlarmEvent): class AlarmEndedEvent(AlarmEvent):
""" """
Triggered when an alarm stops. Triggered when an alarm stops.
""" """
pass
class AlarmDismissedEvent(AlarmEndedEvent): class AlarmDismissedEvent(AlarmEndedEvent):
""" """
Triggered when an alarm is dismissed. Triggered when an alarm is dismissed.
""" """
pass
class AlarmSnoozedEvent(AlarmEvent): class AlarmSnoozedEvent(AlarmEvent):
""" """
Triggered when an alarm is snoozed. Triggered when an alarm is snoozed.
""" """
pass
class AlarmTimeoutEvent(AlarmEndedEvent): class AlarmTimeoutEvent(AlarmEndedEvent):
""" """
Triggered when an alarm times out. Triggered when an alarm times out.
""" """
pass
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View file

@ -79,6 +79,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
alarms: Optional[Union[list, Dict[str, Any]]] = None, alarms: Optional[Union[list, Dict[str, Any]]] = None,
media_plugin: Optional[str] = None, media_plugin: Optional[str] = None,
poll_interval: Optional[float] = 5.0, poll_interval: Optional[float] = 5.0,
snooze_interval: float = 300.0,
**kwargs, **kwargs,
): ):
""" """
@ -90,8 +91,11 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
``media.gstreamer`` etc. If not specified, the first available ``media.gstreamer`` etc. If not specified, the first available
configured local media plugin will be used. This only applies to configured local media plugin will be used. This only applies to
alarms that are configured to play an audio resource. alarms that are configured to play an audio resource.
:param poll_interval: Poll interval in seconds (default: 5).
:param snooze_interval: Default snooze interval in seconds (default: 300).
""" """
super().__init__(poll_interval=poll_interval, **kwargs) super().__init__(poll_interval=poll_interval, **kwargs)
self.snooze_interval = snooze_interval
self._db_lock = RLock() self._db_lock = RLock()
alarms = alarms or [] alarms = alarms or []
if isinstance(alarms, dict): if isinstance(alarms, dict):
@ -160,7 +164,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
self.alarms[name] = Alarm.from_db( self.alarms[name] = Alarm.from_db(
alarm, alarm,
stop_event=self._should_stop, stop_event=self._should_stop,
media_plugin=self.media_plugin, media_plugin=alarm.media_plugin or self.media_plugin,
) )
def _sync_alarms(self): def _sync_alarms(self):
@ -240,6 +244,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
audio_file: Optional[str] = None, audio_file: Optional[str] = None,
audio_volume: Optional[Union[int, float]] = None, audio_volume: Optional[Union[int, float]] = None,
enabled: bool = True, enabled: bool = True,
snooze_interval: Optional[float] = None,
) -> Alarm: ) -> Alarm:
alarm = Alarm( alarm = Alarm(
when=when, when=when,
@ -249,6 +254,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
media=media or audio_file, media=media or audio_file,
media_plugin=self.media_plugin, media_plugin=self.media_plugin,
audio_volume=audio_volume, audio_volume=audio_volume,
snooze_interval=snooze_interval or self.snooze_interval,
stop_event=self._should_stop, stop_event=self._should_stop,
on_change=self._on_alarm_update, on_change=self._on_alarm_update,
) )
@ -281,6 +287,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
self.logger.info('No alarm is running') self.logger.info('No alarm is running')
return return
interval = interval or alarm.snooze_interval or self.snooze_interval
alarm.snooze(interval=interval) alarm.snooze(interval=interval)
@action @action
@ -293,6 +300,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
audio_file: Optional[str] = None, audio_file: Optional[str] = None,
audio_volume: Optional[Union[int, float]] = None, audio_volume: Optional[Union[int, float]] = None,
enabled: bool = True, enabled: bool = True,
snooze_interval: Optional[float] = None,
) -> dict: ) -> dict:
""" """
Add a new alarm. Add a new alarm.
@ -307,6 +315,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
:param media: Path of the audio file to be played. :param media: Path of the audio file to be played.
:param audio_volume: Volume of the audio. :param audio_volume: Volume of the audio.
:param enabled: Whether the new alarm should be enabled (default: True). :param enabled: Whether the new alarm should be enabled (default: True).
:param snooze_interval: Snooze seconds before playing the alarm again.
:return: The newly created alarm. :return: The newly created alarm.
""" """
if audio_file: if audio_file:
@ -322,6 +331,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
name=name, name=name,
enabled=enabled, enabled=enabled,
audio_volume=audio_volume, audio_volume=audio_volume,
snooze_interval=snooze_interval,
).to_dict() ).to_dict()
@action @action
@ -343,6 +353,19 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
""" """
self._disable(name) self._disable(name)
@action
def set_enabled(self, name: str, enabled: bool):
"""
Enable/disable an alarm.
:param name: Alarm name.
:param enabled: Whether the alarm should be enabled.
"""
if enabled:
self._enable(name)
else:
self._disable(name)
@action @action
def dismiss(self): def dismiss(self):
""" """
@ -351,7 +374,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
self._dismiss() self._dismiss()
@action @action
def snooze(self, interval: Optional[float] = 300.0): def snooze(self, interval: Optional[float] = None):
""" """
Snooze the alarm that is currently running for the specified number of seconds. Snooze the alarm that is currently running for the specified number of seconds.
The alarm will stop and resume again later. The alarm will stop and resume again later.

View file

@ -12,9 +12,11 @@ from platypush.context import get_bus, get_plugin
from platypush.entities.alarm import Alarm as AlarmDb from platypush.entities.alarm import Alarm as AlarmDb
from platypush.message.request import Request from platypush.message.request import Request
from platypush.message.event.alarm import ( from platypush.message.event.alarm import (
AlarmStartedEvent, AlarmDisabledEvent,
AlarmDismissedEvent, AlarmDismissedEvent,
AlarmEnabledEvent,
AlarmSnoozedEvent, AlarmSnoozedEvent,
AlarmStartedEvent,
) )
from platypush.plugins.media import MediaPlugin, PlayerState from platypush.plugins.media import MediaPlugin, PlayerState
from platypush.procedure import Procedure from platypush.procedure import Procedure
@ -145,7 +147,13 @@ class Alarm:
self.set_enabled(True) self.set_enabled(True)
def set_enabled(self, enabled: bool): def set_enabled(self, enabled: bool):
if enabled == self._enabled:
return
self._enabled = enabled self._enabled = enabled
evt_type = AlarmEnabledEvent if enabled else AlarmDisabledEvent
get_bus().post(evt_type(name=self.name))
self._on_change()
def dismiss(self): def dismiss(self):
self.state = AlarmState.DISMISSED self.state = AlarmState.DISMISSED
@ -232,6 +240,7 @@ class Alarm:
sleep_time = self._runtime_snooze_interval sleep_time = self._runtime_snooze_interval
else: else:
self.state = AlarmState.WAITING self.state = AlarmState.WAITING
self._on_change()
break break

View file

@ -1,6 +1,8 @@
manifest: manifest:
events: events:
- platypush.message.event.alarm.AlarmDisabledEvent
- platypush.message.event.alarm.AlarmDismissedEvent - platypush.message.event.alarm.AlarmDismissedEvent
- platypush.message.event.alarm.AlarmEnabledEvent
- platypush.message.event.alarm.AlarmSnoozedEvent - platypush.message.event.alarm.AlarmSnoozedEvent
- platypush.message.event.alarm.AlarmStartedEvent - platypush.message.event.alarm.AlarmStartedEvent
- platypush.message.event.alarm.AlarmTimeoutEvent - platypush.message.event.alarm.AlarmTimeoutEvent