How to list multiple calendar event in a template

Okay, few step closer:

  1. I was manually adding the packages via SSH. Thanks for hinting towards the frontend. There I found the Log tab as well. It hinted on the token couldn’t be found. So:

  2. Created the long-lived access token and placed it into my secrets.yaml.

Now when I watch the log, all I get is:

2023-08-21 13:57:01.707038 INFO AppDaemon: Loading app hello_world using class HelloWorld from module hello
2023-08-21 13:57:01.710298 INFO AppDaemon: Loading app calendar using class calendar from module calendar
2023-08-21 13:57:01.712695 WARNING calendar: ------------------------------------------------------------
2023-08-21 13:57:01.713168 WARNING calendar: Unexpected error initializing app: calendar:
2023-08-21 13:57:01.714275 WARNING calendar: ------------------------------------------------------------
2023-08-21 13:57:01.718571 WARNING calendar: Traceback (most recent call last):
  File "/usr/lib/python3.11/site-packages/appdaemon/app_management.py", line 1035, in check_app_updates
    await self.init_object(app)
  File "/usr/lib/python3.11/site-packages/appdaemon/app_management.py", line 338, in init_object
    "object": app_class(
              ^^^^^^^^^^
TypeError: TextCalendar.formatyear() takes from 2 to 6 positional arguments but 8 were given
2023-08-21 13:57:01.718979 WARNING calendar: ------------------------------------------------------------
2023-08-21 13:57:01.834220 WARNING AppDaemon: Unable to find module calendar - initialize() skipped

The log began with downloading the resources which is good. Also it found the calendar as ‘all’ so, also good. Now I only get this issue.

I have not seen that error before, try uncommenting some of the self.log lines in calendar.py and then we can start to work out where it is getting up to

I uncommented line 36 self.log(_list) ; line 93 and 95 but It’s not logging.

ChatGPT to the rescue? It suggested to rename the module to my_calendar because calendar is also a build-in library.

So, that helped with the earlier issues. Now I’m getting the following error:

Error while loading calendar calendar.verjaardagen_2. Maybe connection problem

Do you have a google calendar setup with that name under Devices and Services in HA?

@gjohnson94 … we’ve got a success!

I did had to change my calendar to my subdomain and now it works. I found the calendar_events sensor and it’s giving multiple all_day_events .

Question now remains: How do I show a a list of the events summary on a dashboard?

So in summary:

  1. Create a long-live access token via profile (scroll all the way down)
  2. Place the access token in your secrets.yaml
  3. Change your apps.yaml file and name the module ‘my_calendar’ and check if the URL is correct (this will result eventually in an error in the AppDaemon log if it’s not correct).

EDIT

With the advent of Home Assistant version 2023.09.0, it’s now even easier to use calendar.list_events in a Trigger-based Template Sensor because it now supports an action section.

template:
  - trigger:
      - platform: time_pattern
        minutes: /30
    action:
      - service: calendar.list_events
         target:
          entity_id: calendar.gary
        data:
          duration:
            hours: 24
        response_variable: scheduled_events
    sensor:
      - name: Gary Scheduled Events
        unique_id: gary_scheduled_events
        state: "{{ scheduled_events.events | count() }}"
        attributes:
          scheduled_events: "{{ scheduled_events.events }}"
        icon: mdi:calendar

For historical reference, here’s the original post which used a separate automation for what now can all be done in a Trigger-based Template Sensor.

Original post

Here’s what you can do natively in Home Assistant using the recently added calendar.list_events service call.

Basically, an automation periodically gets upcoming events from your calendar and transfers them to a Template Sensor. Afterwards, you can access the upcoming events directly from the Template Sensor.


Automation

Create an automation that uses a Time Pattern Trigger to poll your calendar every 30 minutes, gets all upcoming calendar events for the next 24 hours, and posts them via a custom Home Assistant Event named gary_scheduled_events.

alias: Get Gary Scheduled Events
description: ""
trigger:
  - platform: time_pattern
    minutes: /30
condition: []
action:
  - service: calendar.list_events
     target:
      entity_id: calendar.gary
    data:
      duration:
        hours: 24
    response_variable: scheduled_events
  - event: gary_scheduled_events
    event_data:
      scheduled_events: "{{ scheduled_events }}"
mode: single

Trigger-based Template Sensor

Create a Trigger-based Template Sensor that uses an Event Trigger to receive your scheduled events, via gary_scheduled_events, and reports them in an attribute named scheduled_events. It also reports the number of scheduled events in its state property.

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

For your TTS macro, it should iterate through the list of calendar events found in the scheduled_events attribute of sensor.gary_scheduled_events.

The template will look something like this:

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

Reference

From the documentation for calendar.list_events

image


EDIT

Correction.

Changed this:

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

to this:

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

Wow thank you I will have a play and see what I can do, the other issue is the format of the time (reads out in military time) , I came across your post to convert the time however not sure where to add it, tried a few thing but failed :frowning: still leaning :slight_smile:
This is the post I found.

{%- if agenda.events %}
  {%- for event in 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 -%}'

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') %}