How to list multiple calendar event in a template

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.

If that’s what you want to do then it can be done without the use of calendar.list_events. What you described can be achieved with a Calendar Trigger.

If you mean the example in this post, then read the post prior to it. You’ll see I took someone else’s example (containing German text) and simplified its templates.

You’ll need to explain what you want exactly.

I would like to format the event times, when the TTS reads it out so that Tuesday @ 4pm etc at the moment I have
image

For determining if a date is today, tomorrow, in X days, etc then you may want to consider using these custom macros:

1 Like

Okay thanks, I will have a read

Thanks for the tip!

I used a different approach, because I would like to send multiple notifications. I’m now using this automation at a given time:

automation:
  - alias: "Notify Events for Today"
    trigger:
      platform: time
      at: "08:00:00"
    action:
      service: notify.your_notification_service
      data:
        title: "Today's Events"
        message: >-
          {% set today = now().strftime('%Y-%m-%d') %}
          {% set events_today = state_attr('sensor.gary_scheduled_events', 'scheduled_events') | selectattr('start', 'eq', today) | list %}
          {% for e in events_today %}
          {{ e.summary }}
          {% endfor %}

This works like a charm!

Next step is cleaning up code (using correct names for this service) and I’ll put a ‘how to’ on this topic.

automation:
  - alias: "Notify Events for Today"
    trigger:
      platform: time
      at: "08:00:00"
    action:
      service: notify.your_notification_service
      data:
        title: "Today's Events"
        message: >-
          {% for e in state_attr('sensor.robin_scheduled_events', 'scheduled_events')
            | selectattr('start', 'eq', now().strftime('%Y-%m-%d')) %}
          {{ e.summary }}
          {% endfor %}
1 Like

Thanks guys for the inspiration, I could not figure out the easy time approach, I resolved it by just inserting a timestamp similar to Robin.

    Garys Agenda for today: {% for e in
    state_attr('sensor.garys_agenda','scheduled_events') %}
      {{ as_timestamp(e.start) | timestamp_custom ('%A %H:%M %p') }}: {{ e.summary }} {% endfor %}

    Christines Aganda for today: {% for e in
    state_attr('sensor.christines_agenda', 'scheduled_events') %}
      {{ as_timestamp(e.start) | timestamp_custom ('%A %H:%M %p') }}: {{ e.summary }} {% endfor %}
1 Like

Just one thing left for me to polish it a little, just have to work out the code to do the following:
if day = now then “Today” not the day of the week.

I finally got day changed to today and tomorrow, I am not sure if there is a better way to do it? I would be interested if there was a better way, however this seems to work okay. The only issue I cant resolve is the line spaces in between each event. See Garys agenda below as apposed to Christines agenda
image

    Gary you have {{states('sensor.garys_agenda')}} items in your Agenda: {% for
    e in state_attr('sensor.garys_agenda','scheduled_events') %}
      {% set start = e.start | as_datetime | as_local %}
      {% if start.strftime('%A') == now().strftime('%A') %}Today at {{ as_timestamp(e.start) | timestamp_custom ('%H:%M %p')}} {{ e.summary }}{%else%}{% if start.strftime('%A') > now().strftime('%A')%}Tomorrow at {{ as_timestamp(e.start) | timestamp_custom ('%H:%M %p')}} {{ e.summary }}{% endif %}{% endif %}{% endfor %}

The blank lines seen in the output are due to this line in your template.

      {% set start = e.start | as_datetime | as_local %}

It’s represented by a blank line for each iteration of the for-loop.

You can suppress it by adding hypens to the braces, like this:

      {%- set start = e.start | as_datetime | as_local -%}

Reference:
Jinja2 - Whitespace control

Assuming your sensor is constrained to containing events exclusively for today and tomorrow, you can use this streamlined version:

Gary you have {{ states('sensor.garys_agenda') }} items in your Agenda:
{% for e in state_attr('sensor.garys_agenda','scheduled_events') %}
{%- set start = e.start | as_datetime | as_local -%}
{{ ['Today', 'Tomorrow'][(start.date() - now().date()).days] }} at {{ start.strftime('%H:%M %p') }} {{ e.summary }}
{% endfor %}

Thanks Taras, I did notice the {%- in a few posts, but didn’t understand the significance? Will give it a go.
Will also give the new code a go and try to understand it.

On a side note: I see you helping a number of individuals throughout the community - you must know this stuff inside out, you not only give instruction but provide insight as well, thank you and good work from the whole community.

1 Like

This is a list containing two items:

['Today', 'Tomorrow']

List items are indexed starting with zero. Therefore this will display the first item in the list (Today).

['Today', 'Tomorrow'][0]

This displays the second item in the list (Tomorrow).

['Today', 'Tomorrow'][1]

Subtracting two datetime objects produces a timedelta object. One of the properties of a timedelta object is days. In other words, the timedelta object’s value is reported as the number of days.

(start.date() - now().date()).days

If the difference between start.date() and now().date() is 0 then it means the event starts today. If the difference is 1 then it starts tomorrow. We use this difference value to get the associated item from the list.

{{ ['Today', 'Tomorrow'][(start.date() - now().date()).days] }}
1 Like

Thank you for the explanation, helps a lot especially in the future,
By adding the streamline ver, I realise now why my original ver wasn’t pulling in the next day, I only defend 2 in the list, however your solution brings in the whole list and defines 2 names. Yours is streamlined but also a better solution as if I have items in the third day I can see them as below:
image
I have been playing around with if statements trying to get the items after tomorrow to default back to the day “Monday” etc? No success so far. Also I have been looking into “carriage returns” something so obvious seems difficult, say I want a “carriage return” after the first line, how do you do that?

It’s 8 days and dozens of posts later and I have run out of free time for this topic. Hopefully someone else can assist you. Good luck.

1 Like

No problem, thank you for all your help

image

something is wrong here

Invalid config for [sensor.template]: [sensor] is an invalid option for [sensor.template]. Check: sensor.template->sensor. (See ?, line ?).

Yes it’s because you tried to configure a Trigger-based Template Sensor using a mixture of the formats for both a legacy and modern Template Sensor.

  • There are two ways to configure a Template Sensor, using either modern or legacy format.

  • There’s only one way to configure a Trigger-based Template Sensor and that’s using modern format.

Modern format Template entities are configured under the template: key and use different option names from legacy format. For example, modern format doesn’t use platform: template.