diff --git a/platypush/backend/http/webapp/src/components/panels/Entities/Alarm/AlarmEditor.vue b/platypush/backend/http/webapp/src/components/panels/Entities/Alarm/AlarmEditor.vue
index 1b5e44720..bacb7c8a6 100644
--- a/platypush/backend/http/webapp/src/components/panels/Entities/Alarm/AlarmEditor.vue
+++ b/platypush/backend/http/webapp/src/components/panels/Entities/Alarm/AlarmEditor.vue
@@ -138,8 +138,8 @@
             <br />
             <span class="subtext">
               <span class="text">
-                How long the interval should be paused after being triggered and
-                snoozed.
+                How long the alarm should be paused after being triggered and
+                manually snoozed.
               </span>
             </span>
           </div>
@@ -150,6 +150,26 @@
           </div>
         </div>
 
+        <div class="row item">
+          <div class="name">
+            <label>
+              <i class="icon fas fa-xmark" />
+              Dismiss timeout
+            </label>
+            <br />
+            <span class="subtext">
+              <span class="text">
+                How long the alarm should run before being automatically dismissed.
+              </span>
+            </span>
+          </div>
+
+          <div class="value">
+            <TimeInterval :value="editForm.dismiss_interval"
+                          @input="editForm.dismiss_interval = $event" />
+          </div>
+        </div>
+
         <div class="row item">
           <div class="name">
             <label>
@@ -247,6 +267,7 @@ export default {
         'media_plugin',
         'name',
         'snooze_interval',
+        'dismiss_interval',
         'when',
       ].forEach(key => {
         if (this.editForm[key] !== this.value[key])
@@ -258,6 +279,17 @@ export default {
   },
 
   methods: {
+    actionsToArgs(actions) {
+      return actions?.map(action => {
+        if (action.name) {
+          action.action = action.name
+          delete action.name
+        }
+
+        return action
+      }) ?? []
+    },
+
     onWhenInput(value, type) {
       if (value == null)
         return
@@ -302,7 +334,8 @@ export default {
           media_plugin: this.editForm.media_plugin,
           audio_volume: this.editForm.audio_volume,
           snooze_interval: this.editForm.snooze_interval,
-          actions: this.editForm.actions,
+          dismiss_interval: this.editForm.dismiss_interval,
+          actions: this.actionsToArgs(this.editForm.actions),
         }
       } else {
         action = 'alarm.edit'
@@ -311,6 +344,9 @@ export default {
           ...this.changes,
         }
 
+        if (this.changes.actions)
+          args.actions = this.actionsToArgs(this.changes.actions)
+
         if (this.changes.name != null) {
           args.name = this.value.name
           args.new_name = this.changes.name
diff --git a/platypush/entities/alarm.py b/platypush/entities/alarm.py
index 6a93c3345..7b2698a23 100644
--- a/platypush/entities/alarm.py
+++ b/platypush/entities/alarm.py
@@ -26,6 +26,7 @@ if not is_defined('alarm'):
         media_plugin = Column(String, nullable=True)
         audio_volume = Column(Integer, nullable=True)
         snooze_interval = Column(Integer, nullable=True)
+        dismiss_interval = Column(Integer, nullable=True)
         actions = Column(JSON, nullable=True)
         static = Column(Boolean, nullable=False, default=False)
         condition_type = Column(String, nullable=False)
diff --git a/platypush/plugins/alarm/__init__.py b/platypush/plugins/alarm/__init__.py
index 7aaa66f07..d0aef9b07 100644
--- a/platypush/plugins/alarm/__init__.py
+++ b/platypush/plugins/alarm/__init__.py
@@ -77,14 +77,15 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
 
     def __init__(
         self,
-        alarms: Optional[Union[list, Dict[str, Any]]] = None,
+        alarms: Optional[Union[List[dict], Dict[str, dict]]] = None,
         media_plugin: Optional[str] = None,
-        poll_interval: Optional[float] = 5.0,
+        poll_interval: Optional[float] = 2.0,
         snooze_interval: float = 300.0,
+        dismiss_interval: float = 300.0,
         **kwargs,
     ):
         """
-        :param alarms: List or name->value dict with the configured alarms. Example:
+        :param alarms: List or name->value dict with the configured alarms.
         :param media_plugin: Media plugin (instance of
             :class:`platypush.plugins.media.MediaPlugin`) that will be used to
             play the alarm audio. It needs to be a supported local media
@@ -92,11 +93,18 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
             ``media.gstreamer``, ``sound``, etc. If not specified, the first
             available configured local media plugin will be used. This only
             applies to 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).
+        :param poll_interval: (Internal) poll interval, in seconds (default: 2).
+        :param snooze_interval: Default snooze interval in seconds. This
+            specifies how long to wait between alarm runs when an alarm is
+            dismissed (default: 300).
+        :param dismiss_interval: Default dismiss interval in seconds. This
+            specifies how long an alarm should run without being manually
+            snoozed/dismissed before being automatically dismissed (default:
+            300).
         """
         super().__init__(poll_interval=poll_interval, **kwargs)
         self.snooze_interval = snooze_interval
+        self.dismiss_interval = dismiss_interval
         self._db_lock = RLock()
         alarms = alarms or []
         if isinstance(alarms, dict):
@@ -259,6 +267,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
         audio_volume: Optional[Union[int, float]] = None,
         enabled: bool = True,
         snooze_interval: Optional[float] = None,
+        dismiss_interval: Optional[float] = None,
     ) -> Alarm:
         alarm = Alarm(
             when=when,
@@ -269,6 +278,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
             media_plugin=media_plugin or self.media_plugin,
             audio_volume=audio_volume,
             snooze_interval=snooze_interval or self.snooze_interval,
+            dismiss_interval=dismiss_interval or self.dismiss_interval,
             stop_event=self._should_stop,
             on_change=self._on_alarm_update,
         )
@@ -316,6 +326,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
         audio_volume: Optional[Union[int, float]] = None,
         enabled: bool = True,
         snooze_interval: Optional[float] = None,
+        dismiss_interval: Optional[float] = None,
     ) -> dict:
         """
         Add a new alarm.
@@ -332,6 +343,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
         :param audio_volume: Volume of the audio.
         :param enabled: Whether the new alarm should be enabled (default: True).
         :param snooze_interval: Snooze seconds before playing the alarm again.
+        :param dismiss_interval: Dismiss seconds before stopping the alarm.
         :return: The newly created alarm.
         """
         if audio_file:
@@ -349,6 +361,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
             enabled=enabled,
             audio_volume=audio_volume,
             snooze_interval=snooze_interval,
+            dismiss_interval=dismiss_interval,
         ).to_dict()
 
     @action
@@ -363,6 +376,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
         audio_volume: Optional[Union[int, float]] = None,
         enabled: Optional[bool] = None,
         snooze_interval: Optional[float] = None,
+        dismiss_interval: Optional[float] = None,
     ) -> dict:
         """
         Edit an existing alarm.
@@ -383,6 +397,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
         :param audio_volume: Volume of the audio.
         :param enabled: Whether the new alarm should be enabled.
         :param snooze_interval: Snooze seconds before playing the alarm again.
+        :param dismiss_interval: Dismiss seconds before stopping the alarm.
         :return: The modified alarm.
         """
         alarm = self._get_alarm(name)
@@ -410,6 +425,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
                 if audio_volume is not None
                 else alarm.audio_volume,
                 snooze_interval=snooze_interval or alarm.snooze_interval,
+                dismiss_interval=dismiss_interval or alarm.dismiss_interval,
             ).to_dict()
 
     @action
@@ -419,15 +435,25 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
 
         :param name: Alarm name.
         """
-        alarm = self._get_alarm(name)
+        try:
+            alarm = self._get_alarm(name)
+        except AssertionError:
+            self.logger.warning('Alarm %s does not exist', name)
+            return
+
         assert not alarm.static, (
             f'Alarm {name} is statically defined in the configuration, '
             'cannot overwrite it programmatically'
         )
 
+        alarm.stop()
+
         with self._db.get_session() as session:
             db_alarm = session.query(DbAlarm).filter_by(name=name).first()
-            assert db_alarm, f'Alarm {name} does not exist'
+            if not db_alarm:
+                self.logger.warning('Alarm %s does not exist', name)
+                return
+
             self._clear_alarm(db_alarm, session)
 
     @action
@@ -507,6 +533,7 @@ class AlarmPlugin(RunnablePlugin, EntityManager):
                         "media_plugin": "media.vlc",
                         "audio_volume": 10,
                         "snooze_interval": 300,
+                        "dismiss_interval": 300,
                         "actions": [
                             {
                                 "action": "tts.say",
diff --git a/platypush/plugins/alarm/_model.py b/platypush/plugins/alarm/_model.py
index 406b0c058..eddb93c04 100644
--- a/platypush/plugins/alarm/_model.py
+++ b/platypush/plugins/alarm/_model.py
@@ -61,7 +61,8 @@ class Alarm:
         media_plugin: Optional[str] = None,
         audio_volume: Optional[Union[int, float]] = None,
         snooze_interval: float = 300,
-        poll_interval: float = 5,
+        dismiss_interval: float = 300,
+        poll_interval: float = 2,
         enabled: bool = True,
         static: bool = False,
         stop_event: Optional[threading.Event] = None,
@@ -75,6 +76,7 @@ class Alarm:
         self.media_plugin = media_plugin
         self.audio_volume = audio_volume
         self.snooze_interval = snooze_interval
+        self.dismiss_interval = dismiss_interval
         self.state = AlarmState.UNKNOWN
         self.timer: Optional[threading.Timer] = None
         self.static = static
@@ -91,6 +93,7 @@ class Alarm:
         self.stop_event = stop_event or threading.Event()
         self.poll_interval = poll_interval
         self.on_change = on_change
+        self._dismiss_timer: Optional[threading.Timer] = None
 
     def _on_change(self):
         if self.on_change:
@@ -209,6 +212,7 @@ class Alarm:
     def dismiss(self):
         self.state = AlarmState.DISMISSED
         self.stop_audio()
+        self._clear_dismiss_timer()
         get_bus().post(AlarmDismissedEvent(name=self.name))
         self._on_change()
 
@@ -216,6 +220,7 @@ class Alarm:
         self._runtime_snooze_interval = interval or self.snooze_interval
         self.state = AlarmState.SNOOZED
         self.stop_audio()
+        self._clear_dismiss_timer()
         get_bus().post(
             AlarmSnoozedEvent(name=self.name, interval=self._runtime_snooze_interval)
         )
@@ -230,19 +235,27 @@ class Alarm:
             return
 
         interval = next_run - time.time()
+        self.state = AlarmState.WAITING
         self.timer = threading.Timer(interval, self.alarm_callback)
         self.timer.start()
-        self.state = AlarmState.WAITING
+        self._clear_dismiss_timer()
         self._on_change()
 
     def stop(self):
         self.state = AlarmState.SHUTDOWN
+        self.stop_audio()
+
         if self.timer:
             self.timer.cancel()
             self.timer = None
 
         self._on_change()
 
+    def _clear_dismiss_timer(self):
+        if self._dismiss_timer:
+            self._dismiss_timer.cancel()
+            self._dismiss_timer = None
+
     def _get_media_plugin(self) -> MediaPlugin:
         plugin = get_plugin(self.media_plugin)
         assert plugin and isinstance(plugin, MediaPlugin), (
@@ -265,16 +278,23 @@ class Alarm:
     def stop_audio(self):
         self._get_media_plugin().stop()
 
+    def _on_start(self):
+        if self.state != AlarmState.RUNNING:
+            self._dismiss_timer = threading.Timer(self.dismiss_interval, self.dismiss)
+            self._dismiss_timer.start()
+
+        self.state = AlarmState.RUNNING
+        get_bus().post(AlarmStartedEvent(name=self.name))
+        self._on_change()
+        if self.media_plugin and self.media:
+            self.play_audio()
+
+        self.actions.execute()
+
     def alarm_callback(self):
         while not self.should_stop():
             if self.is_enabled():
-                self.state = AlarmState.RUNNING
-                get_bus().post(AlarmStartedEvent(name=self.name))
-                self._on_change()
-                if self.media_plugin and self.media:
-                    self.play_audio()
-
-                self.actions.execute()
+                self._on_start()
             elif self.state != AlarmState.WAITING:
                 self.state = AlarmState.WAITING
                 self._on_change()
@@ -339,6 +359,7 @@ class Alarm:
             'media_plugin': self.media_plugin,
             'audio_volume': self.audio_volume,
             'snooze_interval': self.snooze_interval,
+            'dismiss_interval': self.dismiss_interval,
             'actions': self.actions.requests,
             'static': self.static,
             'condition_type': self.condition_type.value,
@@ -354,6 +375,7 @@ class Alarm:
             audio_volume=alarm.audio_volume,  # type: ignore
             actions=alarm.actions,  # type: ignore
             snooze_interval=alarm.snooze_interval,  # type: ignore
+            dismiss_interval=alarm.dismiss_interval,  # type: ignore
             enabled=bool(alarm.enabled),
             static=bool(alarm.static),
             state=getattr(AlarmState, str(alarm.state)),
@@ -375,6 +397,7 @@ class Alarm:
                 for req in self.actions.requests
             ],
             snooze_interval=self.snooze_interval,
+            dismiss_interval=self.dismiss_interval,
             enabled=self.is_enabled(),
             static=self.static,
             condition_type=self.condition_type.value,
diff --git a/platypush/plugins/media/vlc/__init__.py b/platypush/plugins/media/vlc/__init__.py
index 0965c9e7f..a80a7bef4 100644
--- a/platypush/plugins/media/vlc/__init__.py
+++ b/platypush/plugins/media/vlc/__init__.py
@@ -238,7 +238,10 @@ class MediaVlcPlugin(MediaPlugin):
     def quit(self, *_, **__):
         """Quit the player (same as `stop`)"""
         with self._stop_lock:
-            assert self._player, 'No vlc instance is running'
+            if not self._player:
+                self.logger.warning('No vlc instance is running')
+                return self.status()
+
             self._player.stop()
             self._on_stop_event.wait(timeout=5)
             self._reset_state()