How to list multiple calendar event in a template

Hi Tara,
Thank you, I feel like I am almost there, I have the sensor created and it looks fine in the development tools, however when I test the macro in the templates tool it give me an error? - UndefinedError: ‘str object’ has no attribute ‘start’
Should the template generate the events in the tool?
This is the macro in case I have done something incorrect

{%- macro getGarysAgenda() -%}
  {% for e in state_attr('sensor.gary_scheduled_events', 'scheduled_events') %}
    {{ e.start}}: {{ e.summary }} {% endfor %}
{%- endmacro -%}

Post a screenshot of the sensor’s data, specifically its scheduled_events attribute, as it appears in the Developer Tools > States view.

I didn’t call for the macro, now I have a different error. :frowning:

I’m trying your approach (because I always prefer native).

I did the following:

Added the following automation to automations.yaml:

- id: "1692277556064"
  alias: Get Birthday events
  description: ""
  trigger:
    - platform: time_pattern
      minutes: /30
  condition: []
  action:
    - service: calendar.list_events
      target:
        entity_id: calendar.verjaardagen_2
      data:
        duration:
          hours: 24
      response_variable: scheduled_events
    - event: birthday_events
      event_data:
        scheduled_events: "{{ scheduled_events }}"
  mode: single

Added the Trigger-based template sensor to my configuration.yaml:

template:
  - trigger:
      - platform: event
        event_type: birthday_events
    sensor:
      - name: Birthday events
        unique_id: birthday_events
        state: "{{ trigger.event.data.scheduled_events.events | count() }}"
        attributes:
          scheduled_events: "{{ trigger.event.data.scheduled_events }}"
        icon: mdi:calendar

After running the automation, I see the sensor state in developer tools > States , but no events are being launched. What am I doing wrong?

Did you reload the templates in the development tools, and wait ofr 30min for it to obtain the data, for testing I update every minute.
image

Bingo! Now the events are there. I ran the automation but after running it didn’t fetched the data first.

Now the question remains: How do I show all the events on a dashboard?

Example of the attributes data:

scheduled_events: 
events:
  - start: '2023-08-22'
    end: '2023-08-22'
    summary: Robin test (YYYY)
  - start: '2023-08-22'
    end: '2023-08-22'
    summary: L test (YYYY)
  - start: '2023-08-22'
    end: '2023-08-22'
    summary: N test (YYYY)
  - start: '2023-08-22'
    end: '2023-08-22'

Good work, how come your date is formatted differently?
My output:
image

It’s because I have ‘all day’ events. I think your Garys Test (takes 30 mins) and Nurve Test for Gary (3 hours) make the difference and goes to timedate (YYYY-MM-DD:HH:MM:SS+Timezone). Because your baby girl (or gf/wife is 38 weeks pregnant?) is a ‘all day’ event it will only give back the YYYY-MM-DD.

Arr got ya, I didn’t realise you had all day events, I am trying to work out how to format the events to ready 9.30pm today at the moment it speaks out a mess of numbers :slight_smile:

I have been playing around with this template but cannot get it working. I use gmail to notify me of the output, but the script does not change the formatting, do you have any idea? I know some words are in German but I don’t think that should make any difference at the moment?

service: notify.gmail
data:
  target: [email protected]
  title: Daily agenda for {{ now().date() }}
  message: >-
    {%- if garys_agenda.events %}
      {%- for event in garys_agenda.events if event.start is defined -%}
        {%- set start = event.start | as_datetime | as_local -%}
        {%- set end = event.end | as_datetime | as_local -%}
        {%- if start > now() and start - now() < timedelta(days=1) %}     
          Am {{ tage[start.weekday()] }} den {{ start.strftime('%d/%m/%Y') }}
          {%- if end - start == timedelta(days=1) %} ganztägig
          {%- else %} um {{ start.strftime('%H:%M %p') }} bis {{ end.strftime('%H:%M %p') }}
          {%- endif %} ist {{ event.summary }}
          {%- if event.description is defined %}
          Hinweise, {{ event.description }}
          {%- endif -%}
          {%- if event.location is defined %}
          Ort, {{ event.location }}
          {% endif -%}
        {% endif -%}  
      {%- endfor %}
    {%- endif -%}' Garys agenda for today:  {% for event in garys_agenda.events
    %}  {{ event.start}}:  {{event.summary }}  {% endfor %}
enabled: true

The data in the scheduled_events attribute is not in the most convenient format and it’s due to something I forgot to include in the example I posted above (which I have now corrected).

In the Trigger-based Template Sensor, change this line:

scheduled_events: "{{ trigger.event.data.scheduled_events }}"

to this:

scheduled_events: "{{ trigger.event.data.scheduled_events.events }}"

Wait until the automation updates the scheduled_events attribute and you’ll see that the attribute’s data will be simplified to a list (as opposed to a dictionary). This simplification will allow this line in the macro to work correctly and eliminate the error message you had received.

{% for e in state_attr('sensor.gary_scheduled_events', 'scheduled_events') %}

I suggest you implement the small correction to the Trigger-based Template Sensor that I posted above. It will simplify the format of the data in the scheduled_events attribute to a list, like this:

scheduled_events: 
  - start: '2023-08-22'
    end: '2023-08-22'
    summary: Robin test (YYYY)
  - start: '2023-08-22'
    end: '2023-08-22'
    summary: L test (YYYY)
  - start: '2023-08-22'
    end: '2023-08-22'
    summary: N test (YYYY)
  - start: '2023-08-22'
    end: '2023-08-22'

You can use a Markdown Card containing this (after you make the suggested modification I described):

{% for e in state_attr('sensor.birthday_events', 'scheduled_events') %}
{{ e.start}}: {{ e.summary }}
{% endfor %}

I’ve applied the small changes and it works! Thanks a lot @123!

Next step: Create a notification on the same date when a start is the same as the current date at specific times. I want to populate a push notifications with title Birthday(s) today, and message the name(s) of the event(s). Any tips how to do this?

HI guys, I’ve struggled to find an answer across multiple posts and forums.

but I have persevered and combined multiple suggestions into a solution that works for me as a morning agenda for the day.

Step 1 - go to google calendar, click the 3 dots on the calendar you want, settings > scroll to bottom - copy ICAL Link

Step 2 - go to HAC > search for ICAL and download and install

Step 3 - Reboot HA

Step 4 - Go to Integrations > Add > ICAL

Step 5 - Paste your ICAL Link you copied earlier and set number of events to grab, I used 10 as I would never have more than 10 events to check, do note it checks multiple days, so if have only 5 tasks over a week, it will list them across the week for you

Step 6 - Wait for about 1-2 minutes for the sensors to populate

now you can built your template for your text to speech

here is my template I wrote … I only need 4 or so but you can adapt it for more if you like
the code has IF functions to determine if the event is today and alexa or google will say the event is at 8 today instead of the day of the week etc.

Its not perfect yet but its working!

Your next 4 events .. at {{ as_timestamp(state_attr('sensor.ical_carl_event_0' |string, "start")) | timestamp_custom('%H:%M') }} {% if (now().date() + timedelta(days=0))  | string  ==
 as_timestamp(state_attr('sensor.ical_carl_event_0' |string, "start")) |timestamp_custom('%Y-%m-%d')   %}Today {% else %} {{ as_timestamp(state_attr('sensor.ical_carl_event_0' |string, "start")) | timestamp_custom('%A') }} 
{% endif %}   
.. {{ state_attr('sensor.ical_carl_event_0' |string, "summary") }} ..
 and at {{ as_timestamp(state_attr('sensor.ical_carl_event_1' |string, "start")) | timestamp_custom('%H:%M') }}

{% if (now().date() + timedelta(days=0))  | string  ==
 as_timestamp(state_attr('sensor.ical_carl_event_1' |string, "start")) |timestamp_custom('%Y-%m-%d')   %}Today {% else %} {{ as_timestamp(state_attr('sensor.ical_carl_event_1' |string, "start")) | timestamp_custom('%A') }} 
{% endif %}   
 .. {{ state_attr('sensor.ical_carl_event_1' |string, "summary") }}
 then at {{ as_timestamp(state_attr('sensor.ical_carl_event_2' |string, "start")) | timestamp_custom('%H:%M') }} 

{% if (now().date() + timedelta(days=0))  | string  ==
 as_timestamp(state_attr('sensor.ical_carl_event_2' |string, "start")) |timestamp_custom('%Y-%m-%d')   %}Today {% else %} {{ as_timestamp(state_attr('sensor.ical_carl_event_2' |string, "start")) | timestamp_custom('%A') }} 
{% endif %}    .. {{ state_attr('sensor.ical_carl_event_2' |string, "summary") }}
 and finally at  {{ as_timestamp(state_attr('sensor.ical_carl_event_3' |string, "start")) | timestamp_custom('%H:%M') }} 

{% if (now().date() + timedelta(days=0))  | string  ==
 as_timestamp(state_attr('sensor.ical_carl_event_3' |string, "start")) |timestamp_custom('%Y-%m-%d')   %}Today {% else %} {{ as_timestamp(state_attr('sensor.ical_carl_event_3' |string, "start")) | timestamp_custom('%A') }} 
{% endif %}    .. {{ state_attr('sensor.ical_carl_event_3' |string, "summary") }}  

This code produces text like this

Your next 4 events at 08:30 Today blah blah
and at 09:30 Today blah blah
then at 19:30 Today blah blah
and finally at 09:00 Tuesday … blah blah

the . . in the code is a breather for alexa so they speaks normally instead of rattling it off like a robot :slight_smile:

I hope this helps you guys!

1 Like

Taras - Awesome - Just like magic, yep macro now works, learning a lot, reading a lot thank you.
I have spent many hours trying to get the day and date formatted from events using your code above, in what way do you implement it? The german makes it a little harder to understand for me :slight_smile:
But what I can gather is your redefining the output then will use another template to call the info? is that correct or am I off base?

are you responding to me or a different post? :slight_smile:

Sorry Carlos your post came in as I was typing to Taras, looking at yours now.

In case you missed it, it’s now possible to get events from a calendar natively; there’s no need to install any third-party applications.