There are a couple possible issues with the automation:
If this calendar will ever have overlapping or coincident events, you cannot reliably use the state of the calendar entity. In that case, you will need to use the calendar.get_events service call.
The method you are using in the template to get start_date returns a string, which you are comparing to a date object which will always be false. Instead, you need to compare similar data types:
...
{% set start_date = (calendar_event.start_time|as_datetime|as_local).date() %}
{% set today_date = now().date() %}
...
However, the Template trigger is very likely unneeded and should be removed. If your events are all-day events, the Template trigger is going to fire immediately after midnight… which won’t pass any of your condition sets. If your events are not all-day and do start at 7:30 or 10:30, they won’t pass any of your condition sets. So, the template trigger will likely never lead to an action, and the 2 cases where it would are already covered by the time triggers.
Automation configuration (If your calendar has overlapping events this will not solve the problem)
alias: Rolluik Sophie open
description: Rolluik Sophie open op basis van Google Agenda event, dag en tijd.
trigger:
- platform: time
at: "07:30:00"
id: normal
- platform: time
at: "10:30:00"
id: late
- platform: sun
event: sunrise
id: normal
condition:
- or:
- and:
- condition: trigger
id: late
- or:
- condition: template
value_template: >
{% set event_messages = ['Zomervakantie', 'Herfstvakantie',
'Kerstvakantie', 'Eerste Kerstdag', 'Tweede Kerstdag', 'Studiedag
Sophie', 'Eerste Paasdag', 'Tweede Paasdag', 'Hemelvaartsdag',
'Eerste Pinksterdag', 'Tweede Pinksterdag'] %}
{% set calendar_event = states.calendar.CALENDARNAME.attributes %}
{% if calendar_event.start_time is defined %}
{% set start_date = (calendar_event.start_time|as_datetime|as_local).date() %}
{% set today_date = now().date() %}
{{ calendar_event.message in event_messages and start_date == today_date }}
{% else %}
false
{% endif %}
- condition: time
weekday:
- sat
- sun
- and:
- condition: trigger
id: normal
- condition: sun
after: sunrise
- condition: time
after: "07:29:00"
weekday:
- mon
- tue
- wed
- thu
- fri
action:
- service: cover.open_cover
data: {}
target:
entity_id: cover.rolluik_sophie_2
mode: queued
Step 1: I created an input boolean (switch) for each room
Step 2: I created an automation which checks the Google Calendar event and IF event is active then the input boolean is set to “On” IF NOT then input boolean is set to “Off”
Step 3: I created an automation which checks every 5 minutes the state of the input boolean (on or off). In case the input boolean state is “On” AND the sun is above horizon then opens blind at 10.30.
In the same automation when the boolean state is “off” AND day is week AND sun is above horizon then opens blind at 07.30, if sun is not above horizon then wait until sun is above horizon and open blind, the 3thrd automation is when the boolean state is “off” AND day is weekend AND sun is above horizon then opens blind at 10.30, if sun is not above horizon then wait until sun is above horizon and open blind.
Tomorrow I will hopefully know if this works :), then I will share the yaml code.
I would suggest setting up a trigger-based template binary sensor to perform the calendar.get_events service and store the result instead of an automation and an input boolean.
There’s no reason to check every 5 minutes… in Home Assistant, continuous polling using the Time Pattern trigger is rarely the correct method to trigger an automation. The 3 events that should be your triggers have not changed from what I propose above… the only thing that has changed is the method you use to find whether it it’s a holiday.
The one thing to be aware of is to make sure that the calendar is checked earlier than the earliest sunrise in your location. Based on the holidays you listed, that means before 05:00, since the earliest annual sunrise in the Netherlands is usually around 05:02.
LOL, no my rooms don’t celebrate holiday’s but the person who lives in that room does
The trigger based template is the thing I can’t get to work.
You are true about the 5 minute timer. I could rebuild that to 04.30 AM (just to be sure) and since these are all-day events they don’t change during the day.
Hopefully I can an update tomorrow if this automation succeeded.
The exact format depends on what your goal for the sensor is… This is probably how I would approach it for your use:
template:
- trigger:
- platform: time
at: "01:00:00"
action:
- service: calendar.get_events
data:
start_date_time: "{{ now() }}"
end_date_time: "{{ today_at() + timedelta(days=1, minutes= -1) }}"
target:
entity_id: calendar.YOUR_CALENDAR
response_variable: agenda
- variables:
event_messages:
- Zomervakantie
- Herfstvakantie
- Kerstvakantie
- Eerste Kerstdag
- Tweede Kerstdag
- Studiedag Sophie
- Eerste Paasdag
- Tweede Paasdag
- Hemelvaartsdag
- Eerste Pinksterdag
- Tweede Pinksterdag
calendar_event_title: |
{{ agenda['calendar.YOUR_CALENDAR']['events']
| selectattr('summary', 'in', event_messages) | map(attribute='summary') | join }}
binary_sensor:
- name: Is it a Holiday
state: "{{ calendar_event_title != '' }}"
attributes:
holiday_title: "{{ calendar_event_title if calendar_event_title != '' else 'No Holiday' }}"
This gives you a binary sensor whose state you can use as a general condition (for rooms that celebrate all the holidays ) and the holiday_title attribute can be used to compare against room-specific lists when needed.
My automation didn’t go completely well… I forgot in the automation to check the boolean state so the blinds opend at 07.30 AM this morning and the boolean was “On”.
Since this morning the automation works like I wanted to.
Blinds open depending on Calendar event, weekdays and time.
I created the steps below for each room.
Still 3 steps:
Created an input boolean (switch) per room
Created an automation which checks Google Calendar event and IF event is active then the input boolean is to “On” else to “Off”
Code:
alias: Update Event ROOM Boolean
description: >-
Update input.boolean event_ROOM to "On" or "Off" based on Google
Calendar events
trigger:
- platform: time_pattern
minutes: "30"
hours: "4"
condition:
- condition: template
value_template: >
{% set event_messages = [
'Zomervakantie', 'Herfstvakantie', 'Kerstvakantie',
'Eerste Kerstdag', 'Tweede Kerstdag', 'Studiedag',
'Eerste Paasdag', 'Tweede Paasdag', 'Hemelvaartsdag',
'Eerste Pinksterdag', 'Tweede Pinksterdag'
] %} {% set calendar_event =
state_attr('calendar.CALENDARNAME', 'attributes') %} {% if
calendar_event and calendar_event.start_time %}
{% set start_time = as_timestamp(calendar_event.start_time) %}
{% set start_date = start_time | timestamp_custom('%Y-%m-%d', true) %}
{% set today_date = now().date() %}
{{ calendar_event.message in event_messages and start_date == today_date }}
{% else %}
{{ false }}
{% endif %}
action:
- target:
entity_id: input_boolean.event_ROOM
action: |
{% if is_state('calendar.CALENDARNAME', 'on') %}
input_boolean.turn_on
{% else %}
input_boolean.turn_off
{% endif %}
mode: single
3.I created an automation which checks the state of the input boolean (on or off). In case the input boolean state is “On” AND the sun is above horizon then opens blind at 10.30.
In the same automation when the boolean state is “off” AND day is week AND sun is above horizon then opens blind at 07.30, if sun is not above horizon then wait until sun is above horizon and open blind, the 3thrd automation is when the boolean state is “off” AND day is weekend AND sun is above horizon then opens blind at 10.30, if sun is not above horizon then wait until sun is above horizon and open blind.
The code I used:
alias: Blinds ROOM open
description: Blinds ROOM open based on Google Calendar event, day and time.
trigger:
- platform: time
at: "07:30:00"
condition: []
action:
- choose:
- conditions:
- condition: state
entity_id: input_boolean.event_ROOM
state: "on"
sequence:
- delay: "03:00:00"
- choose:
- conditions:
- condition: sun
after: sunrise
sequence:
- target:
entity_id: cover.blinds_ROOM
action: cover.open_cover
data: {}
- conditions:
- condition: sun
before: sunrise
sequence:
- wait_template: "{{ is_state('sun.sun', 'above_horizon') }}"
timeout: "03:00:00"
- target:
entity_id: cover.blinds_ROOM
action: cover.open_cover
data: {}
- conditions:
- condition: state
entity_id: input_boolean.event_ROOM
state: "off"
- condition: time
weekday:
- mon
- tue
- wed
- thu
- fri
sequence:
- choose:
- conditions:
- condition: sun
after: sunrise
sequence:
- target:
entity_id: cover.blind_ROOM
action: cover.open_cover
data: {}
- conditions:
- condition: sun
before: sunrise
sequence:
- wait_template: "{{ is_state('sun.sun', 'above_horizon') }}"
timeout: "03:00:00"
- target:
entity_id: cover.blind_ROOM
action: cover.open_cover
data: {}
- conditions:
- condition: state
entity_id: input_boolean.event_ROOM
state: "off"
- condition: time
weekday:
- sat
- sun
sequence:
- delay: "03:00:00"
- choose:
- conditions:
- condition: sun
after: sunrise
sequence:
- target:
entity_id: cover.blind_ROOM
action: cover.open_cover
data: {}
- conditions:
- condition: sun
before: sunrise
sequence:
- wait_template: "{{ is_state('sun.sun', 'above_horizon') }}"
timeout: "03:00:00"
- target:
entity_id: cover.blind_ROOM
action: cover.open_cover
data: {}
mode: single
If the condition block can only be passed on days that are holidays, when will the Input boolean ever be turned off by the automation? Do you have another automation to turn off the booleans?
Just be aware that waits and delays do not survive restart or reload, so it is generally not advisable to use prolonged waits in automations. The preferred method is to use multiple triggers, as shown in my examples above.
That part will not be executed on any day that is not a holiday, because of the Condition/“And If” block.
If you want it to handle both actions, you need to move the template out of the Condition block and use it to set a variable:
trigger:
- platform: time_pattern
minutes: "30"
hours: "4"
condition: []
action:
- variables:
holiday: |
{% set event_messages = [
'Zomervakantie', 'Herfstvakantie', 'Kerstvakantie',
'Eerste Kerstdag', 'Tweede Kerstdag', 'Studiedag',
'Eerste Paasdag', 'Tweede Paasdag', 'Hemelvaartsdag',
'Eerste Pinksterdag', 'Tweede Pinksterdag'
] %}
{% set calendar_event = state_attr('calendar.CALENDARNAME', 'start_time') %}
{% set event_message = state_attr('calendar.CALENDARNAME', 'message') %}
{% if calendar_event %}
{% set start_date = (calendar_event | as_datetime | as_local).date() %}
{% set today_date = now().date() %}
{{ 'on' if event_message in event_messages and start_date == today_date else 'off' }}
{% else %}
off
{% endif %}
- service: input_boolean.turn_{{ holiday }}
target:
entity_id: input_boolean.event_ROOM
mode: single
Just keep in mind that using the state object of a calendar entity will be unreliable any time the calendar has overlapping events… it may not be that big an issue since you are checking at 04:30, but if you experience issues with the blinds not opening at the right time that’s the first thing I would check.
I found the issue and corrected it above… in the automation you went back to the incorrect set statement for start_date that I posted the correction for in my first post…
Observe the following:
{% if calendar_event %}
{% set start_time = as_timestamp(calendar_event) %}
{% set start_date = start_time | timestamp_custom('%Y-%m-%d', true) %}
{% set today_date = now().date() %}
...
start_date is a string. today_date is a date object.
start_date == today_date will never be true, the data types must be the same for them to pass an equivalency test. The following is one way to correct the issue:
...
{% set start_date = (calendar_event | as_datetime | as_local).date() %}
{% set today_date = now().date() %}
....
I’m still strungeling with the same problem.
It seems not all events are being fetched, mainwhile also the date notation seems to be weird. I would expect to get the event of today
That is why I have said, multiple times, that using the state object of a calendar entity can be unreliable for what you are trying to do.
Usually the event that populates the state and attributes of the calendar entity will be the all-day event (if one exists), but there is no way to guarantee that will be the case if there are overlapping events. That is the whole reason for the trigger-based binary sensor I proposed in Post #7, using the calendar.get_events action allows us to retrieve all the events from the calendar and use templates to find the one we need.