Do stuff before and after an alarm

This blueprint performs an action at configurable duration before an alarm and another at a configurable duration after the alarm.

  • It can detect alarm snooze and delay the post-alarm actions after the snoozed alarm.
  • It can detect the manual update of an entity to a specific state to abort the script
  • It supports min/max hours for activation
  • It supports an optional activation blocking entity

Use case: I use it to warm-up my espresso machine before I wake-up. I use my presence sensor as a blocking entity, and use the switch ‘off’ as abort condition, this way, if I manualy decides to switch off the machine, the script won’t continue.

Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

blueprint:
  name: Do something Before/After alarm
  description: >
    Does an action at given time before alarm and after alarm
    It can delay post-actions on alarm snooze.
    It can abort if an entity switches to a given state.
  domain: automation
  input:
    alarm_sensor:
      name: Alarm sensor
      description: Alarm sensor used as a reference point
      selector:
        entity:
          device_class: timestamp

    before_duration_hours:
      name: Pre-alarm relative duration (hours)
      description: Pre-alarm action will be triggered at this duration before alarm
      default: 0
      selector:
        number:
          min: 0
          max: 24
          unit_of_measurement: hours
    before_duration_minutes:
      name: Pre-alarm relative duration (minutes)
      description: Pre-alarm action will be triggered at this duration before alarm
      default: 25
      selector:
        number:
          min: 0
          max: 60
          unit_of_measurement: minutes
    before_duration_seconds:
      name: Pre-alarm relative duration (seconds)
      description: Pre-alarm action will be triggered at this duration before alarm
      default: 0
      selector:
        number:
          min: 0
          max: 60
          unit_of_measurement: seconds

    before_actions:
      name: Pre-alarm actions
      description: Actions to be run at Pre-alarm time
      default: []
      selector:
        action: {}

    after_duration_hours:
      name: Post-alarm relative duration (hours)
      description: Post-alarm action will be triggered at alarm + this duration
      default: 0
      selector:
        number:
          min: 0
          max: 24
          unit_of_measurement: hours
    after_duration_minutes:
      name: Post-alarm relative duration (minutes)
      description: Post-alarm action will be triggered at alarm + this duration
      default: 20
      selector:
        number:
          min: 0
          max: 60
          unit_of_measurement: minutes
    after_duration_seconds:
      name: Post-alarm relative duration (seconds)
      description: Post-alarm action will be triggered at alarm + this duration
      default: 0
      selector:
        number:
          min: 0
          max: 60
          unit_of_measurement: seconds

    after_actions:
      name: Post-alarm actions
      description: Actions to be run at Post-alarm time
      default: []
      selector:
        action: {}

    postpone_on_snooze:
      name: Snooze detection duration
      description: >
        If an alarm is detected during Post-alarm duration and is not further away than Snooze detection duration time, after actions will be delayed after that alarm.
        This restarts Post-alarm duration time and can be repeated indefinitly.
        Set to a value a bit > than the alarm snooze delay. Set to 0 to disable.
      default: 11
      selector:
        number:
          min: 0
          max: 60
          unit_of_measurement: minutes

    abort_trigger_entity:
      name: Abort script on specific entity trigger
      description: Set to none to disable
      default: none
      selector:
        entity: {}

    abort_trigger_state:
      name: Abort script on specific entity trigger state
      description: Ignored if trigger entity is none
      default: off
      selector:
        text: {}

    execute_after_actions_on_abort:
      name: Executes Post-alarm actions on abort
      default: true
      selector:
        boolean:

    guard_time_min:
      name: Minimum time condition
      description: >
        Automation will not start when time is lower than this
      default: '00:00:00'
      selector:
        time: {}

    guard_time_max:
      name: Maximum time condition
      description: >
        Automation will not start when time is over than this
      default: '23:59:59'
      selector:
        time: {}

    guard_entity:
      name: Additional entity to check before triggering
      description: If set, checks if entity is 'on' or 'home' before triggering. Use sensor, device_tracker or person entity.
      default: none
      selector:
        entity: {}

mode: single
max_exceeded: silent

variables:
  alarm_sensor: !input alarm_sensor

  before_duration_hours:   !input before_duration_hours
  before_duration_minutes: !input before_duration_minutes
  before_duration_seconds: !input before_duration_seconds
  before_duration: '{{ ((before_duration_hours|int * 60) + before_duration_minutes|int) * 60 + before_duration_seconds|int }}'

  after_duration_hours:   !input after_duration_hours
  after_duration_minutes: !input after_duration_minutes
  after_duration_seconds: !input after_duration_seconds
  after_duration: '{{ ((after_duration_hours * 60) + after_duration_minutes) * 60 + after_duration_seconds }}'

  postpone_on_snooze: !input postpone_on_snooze
  execute_after_actions_on_abort: !input execute_after_actions_on_abort

  abort_trigger_entity: !input abort_trigger_entity
  abort_trigger_state:  !input abort_trigger_state

  guard_entity: !input guard_entity

trigger:
  - platform: time_pattern
    minutes: '*'

# Check for guard condition
condition:
  - condition: template
    value_template: '{{ states(guard_entity) in [''unknown'', ''on'', ''home'']}}'
  - condition: time
    after: !input guard_time_min
    before: !input guard_time_max
  - condition: template
    value_template: '{{ states(alarm_sensor) != ''unavailable'' and (states(alarm_sensor)|as_timestamp - now()|as_timestamp)|int <= before_duration }}'

action:
  # Execute Pre-alarm actions
  - choose: []
    default: !input before_actions

  - alias: 'Repeat until abort or timeout reached after alrm (including snoozes)'
    repeat:
      sequence:
        # Wait for before time and exit on trigger
        - wait_for_trigger: 
          - platform: template
            value_template: '{{ 
                  (abort_trigger_entity != ''none'' and states(abort_trigger_entity) == abort_trigger_state)
                  or
                  ( 
                    states(alarm_sensor) != ''unavailable'' 
                    and
                    (states(alarm_sensor)|as_timestamp - now()|as_timestamp) <= postpone_on_snooze * 60
                    and
                    (states(alarm_sensor)|as_timestamp - now()|as_timestamp) > 0
                  )
               }}'
          timeout:
            seconds: '{{ (states(alarm_sensor)|as_timestamp - now()|as_timestamp)|int + after_duration }}'

      until: '{{ 
            wait.remaining == 0 
            or
            (
              wait.trigger.entity_id == abort_trigger_entity
              and
              states(abort_trigger_entity) == abort_trigger_state
            )
        }}'


  # Execute Post-alarm actions
  - choose: 
    - conditions:
      - '{{ execute_after_actions_on_abort or wait.remaining == 0 }}'
      sequence: !input after_actions

  # Wait until trigger conditions are no longer true, to avoid restart after abort
  - wait_template: '{{ states(alarm_sensor) == ''unavailable'' or (states(alarm_sensor)|as_timestamp - now()|as_timestamp)|int > before_duration }}'
5 Likes