Sorting responses from Calendar

Im really liking the ability to display a reminder of the days events, but have noticed that the response is not correctly sorted by time. Im using the following code:

  - service: calendar.list_events
    target:
      entity_id: calendar.xxx_yyy
    data:
      duration:
        hours: 24
    response_variable: agenda

and get a response like this

2023-07-10T10:30:00-04:00: Item 2
2023-07-10T08:00:00-04:00: Item 1
2023-07-10T14:30:00-04:00: Item 4
2023-07-10T12:30:00-04:00: Item 3

Ideally, id like it to be sorted by time to look like this

2023-07-10T08:00:00-04:00: Item 1
2023-07-10T10:30:00-04:00: Item 2
2023-07-10T12:30:00-04:00: Item 3
2023-07-10T14:30:00-04:00: Item 4

I tried adding this line but it fails ( agenda.events|sort )

Your agenda for today: <p>
{% agenda.events|sort %}
{% for event in agenda.events %}
{{ as_timestamp(event.start)|timestamp_custom ('%Y/%m/%d %H:%M') }} - {{ event.summary }}<br>
{% endfor %}
</p>

Anyone have a solution??

The statement {% agenda.events|sort %} isn’t really doing anything the way you have it set up. You need to either save your sorted list to a variable, or move your sort to the for statement so the list is sorted prior to being looped over:

Your agenda for today: <p>
{% for event in agenda.events|sort(attribute='start') %}
{{ (event.start|as_datetime).strftime('%Y/%m/%d %H:%M') }} - {{ event.summary }}<br>
{% endfor %}
</p>

EDIT: The calendar.list_events service shown in the original post has been deprecated and replaced by the action calendar.get_events.

action:
  - action: calendar.get_events
    data:
      start_date_time: "{{ now() }}"
      end_date_time: "{{ today_at('23:59:00') }}"      
    target:
      entity_id: calendar.example
    response_variable: agenda
1 Like

@ Didgeridrew
Thank you. That worked perfectly.

Thank you, I almost opened another issue for this, I was 99% of the way there, but I needed to add |sort(attribute=‘start’) and now I have this working perfectly!

1 Like

I take that back, it appears that what I have is looping through each calendar and listing each individual calendars events in order, not sorting all the events in order.

Here is my script.

data:
  data:
    push:
      thread-id: agenda
      url: /lovelace/calendar
  message: >-
    {% set calendars = expand('group.family_calendars') %} {% set
    calendar_looplength = namespace(value=0) %}  {% for x in calendars if
    (agenda[x.entity_id].events | count) > 0 %}  {%- set
    calendar_looplength.value = loop.length -%}  {% for event in
    agenda[x.entity_id].events|sort(attribute='start') %}{{
    (as_timestamp(event.start) | timestamp_custom('%H:%M')) }}: {{ event.summary
    }}{{"\n"}}{% endfor %} {% endfor %} {%- if calendar_looplength.value == 0
    %}Nothing to do Today!{%- endif %}
  title: Daily agenda for {{ now().date() }}
enabled: true
action: notify.ios_notifications

Nowhere in your template are the events (or their string outputs) combined together… you need to use the namespace to hold the results of the loops so that all the agenda items are output as a list that can be sorted. Here’s one way to do that:

{% set ns = namespace(cal_events=[]) %}
{%- for key, value in agenda.items() %}
  {%- for event in value.events %}
    {%- set ns.cal_events = ns.cal_events + [(as_timestamp(event.start) | timestamp_custom('%H:%M'))~': '~ event.summary] %}
  {%- endfor %}
{%- endfor %}
{{ ns.cal_events | sort | join('\n') if 
ns.cal_events | count > 0 else 'Nothing to do Today!'}}

Note: This template is designed for a single day agenda.

I’m only looking for a single day agenda, so this is PERFECT! Thank you!