Binary Sensor based on Calendar

Hi everyone,

first of all I am new to HA and still juggling with all the vocabulary. But I’m making my way through it. So please be kind, if I look in the wrong direction.

What I want is a binary sensor that is on, if a certain event in a calendar is currently going on.

I was able to create a template, based on this question:

{{ is_state('calendar.my_calendar', 'on') and
is_state_attr('calendar.my_calendar', 'message', 'Event 1') }}

This one works, but only if Event 1 is the only (or first) event in the calendar. As soon as I have more active events at the same time and I am looking for a different one then it won’t work.

So let’s say today I have three events, Event 1, Event 2, and Event 3. They all have different start and end times but they may have some overlap.

Let’s assume that right now, Event 1 and Event 3 are ongoing. The sensor above is working.

If I change the code above to

{{ is_state('calendar.my_calendar', 'on') and
is_state_attr('calendar.my_calendar', 'message', 'Event 3') }}

the state of the sensor is off, even though Event 3 is going on right now.

Can someone please help me, to solve this issue?

You need to read the calendar events:
Calendar - Home Assistant

1 Like

Use trigger-based template binary sensors:

template:
  - triggers:
      - trigger: calendar
        entity_id: 'calendar.my_calendar'
        event: start
      - trigger: calendar
        entity_id: 'calendar.my_calendar'
        event: end
    actions:
      - variables:
          message: "{{ trigger.calendar_event.summary }}"
    binary_sensor:
      - name: Event 1 Active
        state: |
          {% if message != "Event 1" %}
            {{ this.state | default('off', true) }}
          {% else %}
            {{ 'on' if trigger.event == 'start' else 'off' }}
          {% endif %}
      - name: Event 2 Active
        state: |
          {% if message != "Event 2" %}
            {{ this.state | default('off', true) }}
          {% else %}
            {{ 'on' if trigger.event == 'start' else 'off' }}
          {% endif %}
      - name: Event 3 Active
        state: |
          {% if message != "Event 3" %}
            {{ this.state | default('off', true) }}
          {% else %}
            {{ 'on' if trigger.event == 'start' else 'off' }}
          {% endif %}

Be aware that, at first, these sensors will have a state of “unknown” until an event starts or ends.

Thanks for your reply. What happens with the sensor if Event 1 and Event 2 are acitve at the same time?

Unlike a state-based template sensor, like the one in the original post, a trigger-based sensor only updates when the trigger fires. Each calendar event will produce their own distinct trigger event. Each sensor’s state should only change when the message matches what is in their state template otherwise it will keep its current value (that’s what this.state is).

1 Like

Ok, thanks a lot. I think I understand how it works. For some reason it does not do, what it’s supposed to do. I think the trigger works, but message is not set correctly.
The behaviour I watched was:
Create the template → new Sensors are there, but “unknown”.
As soon as any event in the calendar starts, sensors are in the state “off”.
Later, Event 1 starts. But the sensor “Event 1 active” does not change its state. Is there a way to debug this? Where can I see the content of the variable message?

I don’t think that’s the issue, but you can add a logging action or notification action to the actions block after the variables definition.

That’s normal, as mentioned in my previous post.

That is also normal for the first run if the event’s summary/message did not match any of the one’s being watched for. This is due to “off” being set as the default in all the templates. After that, the sensors’ states should change when their respective events occur.

Another option, as @Hellis81 linked to previously, wold be to perform the calendar.get_events action then search the response for your events.

Yes, the behaviour with “unkown” state and “off” if the current event is not the one being watched for, is clear to me.
But even if the specific event occours, none of the sensors will turn to “on”. That is why i asked, how to read the content of message. I’ll try out, how far I get with logging actions and notificaton actions - thanks a lot!

I’ve tested the sensors and they are working as expected for me:


The most common reason for Calendar event triggers seemingly not working when you are starting out is failure to understand the 15 minute rule when testing…

Automations - Calendar

There are some work-arounds: Is there any life hack for using calendar for events less than 15 minutes in the future? - #2 by Didgeridrew

Oh wow - the 15 minute rule. I did not know about that one. Now everything works as expected. Thank you so much for your help!
One questions regarding the 15 minute rule comes up my mind: does this mean, that the events have to be at least 15 minutes long, for the sensor to be turned off correctly at the end of the event?

Nope, they can be only a minute long if you want.

Thanks for you help - for me this topic is now solved.

Ok, i still have a question.

This sensor is turned on, if event.summary is exactly “Event 1”. Sometimes I may have entries like “Event 1 (additional info here)”. The sensor should still work. How is that possible?

You’ll need to change to a search or match instead of a simple comparison.

{% if message is not search("Event 1") %}

search will pass if “Event 1” is anywhere in the summary while match would require that the summary starts with “Event 1”:

# Both match and search would work for this:
"Event 1: Play the radio"

# Only search would work for this:
"Set up Event 1"

Both are case sensitive by default, but can be made case insensitive…

{% if message is not match("Event 1", ignorecase=True) %}

Thank you so much. :handshake:

Hi, everyone.
I tried to extend my sensory by delay_on and delay_off. Event 1 and Event 2 are all-day-events that occur alternately. So, Monday is Event 1, Tuesday Event 2 and so on.
Here is the code:

  - triggers:
      - trigger: calendar
        entity_id: 'calendar.my_calendar'
        event: start
      - trigger: calendar
        entity_id: 'calendar.my_calendar'
        event: end
    actions:
      - variables:
          message: "{{ trigger.calendar_event.summary }}"
    binary_sensor:
      - name: Event 1
        state: |
          {% if message != "Event 1" %}
            {{ this.state | default('off', true) }}
          {% else %}
            {{ 'on' if trigger.event == 'start' else 'off' }}
          {% endif %}
        delay_on:
          hours: 8
        delay_off:
          hours: 8
      - name: Event 2
        state: |
          {% if message != "Event 2" %}
            {{ this.state | default('off', true) }}
          {% else %}
            {{ 'on' if trigger.event == 'start' else 'off' }}
          {% endif %}
        delay_on:
          hours: 8
        delay_off:
          hours: 8

In my understanding both sensors should change their states at eight in the morning. Today at eight, one sensor turned off, but the other one never turned on. Does anyone have an idea what is wrong here?
Thanks a lot!

I would try it with an offset on the triggers instead.

I thought about that. What if I need different offsets/delays for different sensors. Should I use different templates for them? If yes, is it possible to have multiple templates with the exact same trigger?

You currently have multiple template binary sensors with the exact same trigger, but I think I get what you’re asking… Yes, you can repeat triggers as many times as you want. If you need different offset for other sensors, set them up under their own trigger. You can also have triggers with different offsets in the same block of configuration, but you would need to account for the offsets in your template using the available trigger variable data.

So, I would do something like this?

  - triggers:
      - trigger: calendar
        entity_id: 'calendar.my_calendar'
        event: start
        offset: "08:0:00"
      - trigger: calendar
        entity_id: 'calendar.my_calendar'
        event: end
        offset: "08:0:00"
    actions:
      - variables:
          message: "{{ trigger.calendar_event.summary }}"
    binary_sensor:
      - name: Event 1
        state: |
          {% if message != "Event 1" %}
            {{ this.state | default('off', true) }}
          {% else %}
            {{ 'on' if trigger.event == 'start' else 'off' }}
          {% endif %}
      - name: Event 2
        state: |
          {% if message != "Event 2" %}
            {{ this.state | default('off', true) }}
          {% else %}
            {{ 'on' if trigger.event == 'start' else 'off' }}
          {% endif %}

and

  - triggers:
      - trigger: calendar
        entity_id: 'calendar.my_calendar'
        event: start
      - trigger: calendar
        entity_id: 'calendar.my_calendar'
        event: end
    actions:
      - variables:
          message: "{{ trigger.calendar_event.summary }}"
    binary_sensor:
      - name: Event 3
        state: |
          {% if message != "Event 3" %}
            {{ this.state | default('off', true) }}
          {% else %}
            {{ 'on' if trigger.event == 'start' else 'off' }}
          {% endif %}