Event Scheduler Integration (release v1.0.0)

Hi all,

I was missing this feature in Home Assistant, so I spent some time figuring out how to make a custom component.

The integration allows Home Assistent events to be scheduled for future delivery. For example, if you have an automation that listens to reminder events, you could schedule an event to trigger that automation in the future. This is more flexible than a fixed time trigger, or even a time pattern.

Please let me know any feedback and code (architecture) reviews you have!

Use

The Event Scheduler integration offers 3 services:

  • event_scheduler.upsert_event: Add or Update an event to be fired at a specific time.
  • event_scheduler.remove_event: Remove a scheduled event.
  • event_scheduler.fire_events: Fire the events that were scheduled at or before the current time.

The documentation for the fields in each service can most easily be viewed through the developer tools ā†’ services UI. Specifically you can view the description in the GUI view and the fields documentation in the YAML view (HA quirk).

I have a normal automation (so not included in the custom component) that calls event_scheduler.fire_events every minute (which is good enough for my use case).

Install

You can most easily install the integration through HACS if you add it as a custom repository (3 dots in the top right corner ā†’ custom repositories).

Alternatively you can copy the (custom_component/)event_scheduler folder to your config/custom_components folder.

2 Likes

Hi. I am not understanding how this integration works. Can you give an example of an automation before using this integration and one adapting this integration??

Sure, here is a simplified example of how I use it to trigger a TTS reminder every 30 minutes after a calendar event in my ā€˜dagplanningā€™ has started (daily schedule tasks). This specific example automation will never stop, but thatā€™s part of what I removed for simplicity.

The closest approximation I could make without this integration, was to make boolean helper variables for each item in my calendar and set them to true if the TTS needs to occur. That also required a time pattern automation trigger to check the state of those helper variables at predefined times. In short, it requires more setup than simply adding an item to my calendar and all reminders happen at a predefined time (e.g. xx:00 and xx:30) rather than any timedelta after the calendar item.

I hope this clarifies my use case, but Iā€™m sure there are many others.

alias: Calendar Dagplanning Reminders
description: ""
trigger:
  - id: calendar_event_start
    platform: calendar
    event: start
    offset: "0:0:0"
    entity_id: calendar.dagplanning
  - id: tts_reminder
    platform: event
    event_type: calendar_dagplanning_reminder
condition: []
action:
  - choose:
      - conditions:
          - condition: trigger
            id: calendar_event_start
        sequence:
          - variables:
              calendar_event_name: "{{trigger.calendar_event.summary}}"
              calendar_event_id: "{{name | trim | lower | replace(' ', '_')}}"
              reminder_id: calendar_dagplanning_{{calendar_event_id}}
          - service: event_scheduler.upsert_event
            data:
              id: "{{reminder_id}}"
              time: "{{ now() + timedelta(minutes=30) }}"
              type: calendar_dagplanning_reminder
              data:
                calendar_event_name: "{{calendar_event_name}}"
      - conditions:
          - condition: trigger
            id: tts_reminder
          - condition: state
            entity_id: person.jelle_jan
            state: home
        sequence:
          - variables:
              calendar_event_name: "{{trigger.event.data.calendar_event_name}}"
              calendar_event_id: "{{name | trim | lower | replace(' ', '_')}}"
              reminder_id: calendar_dagplanning_{{calendar_event_id}}
          - service: script.unified_tts
            data:
              target: all
              message: "Remember {{calendar_event_name}}:
          - service: event_scheduler.upsert_event
            data:
              id: "{{reminder_id}}"
              time: "{{ now() + timedelta(minutes=30) }}"
              type: calendar_dagplanning_reminder
              data:
                calendar_event_name: "{{calendar_event_name}}"
mode: queued
max: 10

I found a different and much simpler example. This automation shows an app notification to empty the laundry, 1 hour and 5 minutes after I scan an NFC tag.

The difference is that instead of inserting a delay action, I store the upcoming event and the automation can finish immediately after.

There are 2 benefits that come to mind, one obvious and one less so.

  1. The event will still happen even if Home Assistant is restarted during the waiting period. Restarts happen often enough that itā€™s a concern, for example when a new version of a HACS integration is released.
  2. Less obviously, itā€™s now very easy to ā€œinterruptā€ the waiting time by removing the scheduled event. This is useful if you want to schedule a TTS reminder that happens unless the app notification is acknowledged quickly enough.

Before
Note that I have a separate automation that listens to notification events

alias: Wasmachine Done Notification
description: ""
trigger:
  - platform: tag
    tag_id: 1541f541-6c6e-41d1-9ee9-b09c7f888888
condition: []
action:
  - delay:
      hours: 1
      minutes: 5
      seconds: 0
      milliseconds: 0
  - event: notification
    event_data:
      message: Wasmachine Klaar
mode: single

After

alias: Wasmachine Done Notification
description: ""
trigger:
  - platform: tag
    tag_id: 1541f541-6c6e-41d1-9ee9-b09c7f888888
condition: []
action:
  - service: event_scheduler.upsert_event
    data:
      id: wasmachine_klaar_notification
      time: "{{now() + timedelta(hours=1, minutes=5)}}"
      type: notification
      data:
        message: Wasmachine Klaar
mode: single
1 Like

Hello. Thanks for the examples. Will study this in bit more detail when I have some free time. So you are saying with the after example above, the automation will continue even after HA restarts?? That would be a plus.

More or less. The nuance is that the automation can stop/finish and the event will be picked up and fired off atnote the scheduled time. That could trigger the same or a different automation.

Note: The way Iā€™ve implemented it now, the event is not fired off exactly at the scheduled time, but when the event_scheduler.fire_events service is called after that. I do that every minute in a separate automation right now. Itā€™s a bit ugly, but close enough to be usable for my current purposes, and I hope usable for others too.

FWIW, the current way to schedule something in the future would be to use a Local Calendar (or Google Calendar). In the following example, when the tag is scanned, a calendar event is created for one hour and five minutes later in calendar.notifications.

alias: Wasmachine Done Notification
description: ""
trigger:
  - platform: tag
    tag_id: 1541f541-6c6e-41d1-9ee9-b09c7f888888
condition: []
action:
  - variables:
      future: "{{ ((now() + timedelta(hours=1, minutes=5)) | string)[:16] }}"
  - service: calendar.create_event
    data:
      summary: "Wasmachine Klaar"
      start_date_time: "{{ future }}"
      end_date_time: "{{ future }}"
    target:
      entity_id: calendar.notifications
mode: single

A separate automation, employing a Calendar Trigger, can monitor calendar.notifications and send a notification, containing the text in summary at the scheduled time

The advantage of your custom integration is that you can use service calls to programmatically insert/update/remove events whereas currently thereā€™s only the calendar.create_event service call available for Local and Google calendars.

Nice comparison!

Another benefit compared to local calendars is that you can easily pass complicated data structures, rather than maybe trying to put them into the description field and hope that it can fit enough data (havenā€™t looked into that).

Also, itā€™s not always necessary to catch the scheduled event with your own automation. It could just as easily be a call_service event.

FWIW, in a Calendar Event, you can pass data structures as JSON.

Thatā€™s where Calendar Events currently have the advantage because thereā€™s no need for such an ā€˜Event Schedulerā€™ automation (itā€™s handled internally).