diff --git a/platypush/plugins/alarm/__init__.py b/platypush/plugins/alarm/__init__.py index 90c65d884..4cf8d874f 100644 --- a/platypush/plugins/alarm/__init__.py +++ b/platypush/plugins/alarm/__init__.py @@ -167,6 +167,13 @@ class AlarmPlugin(RunnablePlugin, EntityManager): media_plugin=alarm.media_plugin or self.media_plugin, ) + # Stop and remove alarms that are not statically configured no longer + # present in the db + for name, alarm in self.alarms.copy().items(): + if not alarm.static and name not in alarms: + del self.alarms[name] + alarm.stop() + def _sync_alarms(self): with self._get_session() as session: db_alarms = { @@ -184,15 +191,16 @@ class AlarmPlugin(RunnablePlugin, EntityManager): self._synced = True def _clear_alarm(self, alarm: DbAlarm, session: Session): - self.alarms.pop(str(alarm.name), None) + alarm_obj = self.alarms.pop(str(alarm.name), None) + if alarm_obj: + alarm_obj.stop() + session.delete(alarm) self._bus.post(EntityDeleteEvent(entity=alarm)) def _clear_expired_alarms(self, session: Session): expired_alarms = [ - alarm - for alarm in self.alarms.values() - if alarm.is_expired() and alarm.is_shut_down() + alarm for alarm in self.alarms.values() if alarm.should_stop() ] if not expired_alarms: @@ -220,7 +228,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager): iter( alarm for alarm in self.alarms.values() - if alarm.state == AlarmState.RUNNING + if alarm.state in {AlarmState.RUNNING, AlarmState.SNOOZED} ), None, ) @@ -233,6 +241,9 @@ class AlarmPlugin(RunnablePlugin, EntityManager): def _on_alarm_update(self, alarm: Alarm): with self._db_lock: + if alarm.should_stop(): + return + self.publish_entities([alarm]) def _add( diff --git a/platypush/plugins/alarm/_model.py b/platypush/plugins/alarm/_model.py index c126dfe8f..9a536f619 100644 --- a/platypush/plugins/alarm/_model.py +++ b/platypush/plugins/alarm/_model.py @@ -3,6 +3,7 @@ import enum import os import time import threading +from random import randint from typing import Callable, Optional, Union import croniter @@ -40,9 +41,6 @@ class Alarm: Alarm model and controller. """ - _alarms_count = 0 - _id_lock = threading.RLock() - def __init__( self, when: Union[str, int, float], @@ -59,10 +57,7 @@ class Alarm: on_change: Optional[Callable[['Alarm'], None]] = None, **_, ): - with self._id_lock: - self._alarms_count += 1 - self.id = self._alarms_count - + self.id = randint(0, 65535) self.when = when self.name = name or f'Alarm_{self.id}' self.media = self._get_media_resource(media) @@ -240,10 +235,10 @@ class Alarm: sleep_time = self._runtime_snooze_interval else: self.state = AlarmState.WAITING - self._on_change() break + self._on_change() self.wait_stop(self.poll_interval) if self.state == AlarmState.SNOOZED: @@ -266,7 +261,11 @@ class Alarm: self.stop_event.wait(timeout) def should_stop(self): - return self.stop_event.is_set() or (self.is_expired() and self.is_shut_down()) + return ( + self.stop_event.is_set() + or (self.is_expired() and self.state == AlarmState.DISMISSED) + or self.state == AlarmState.SHUTDOWN + ) def to_dict(self) -> dict: return {