GENWiki

Premier IT Outsourcing and Support Services within the UK

User Tools

Site Tools


opensource:leveraging_caldav_to_handle_appointments

The CalDAV Integration is Cool

So if, like me you are using an CalDAV compatible calendar (syno caldav for me) but most providers export this, then you can integrate it with home assistant for reminders, either on the dashboard, or even as announcements, or reminders to your phone (notwithstanding that you'd probably already have the calendar on your phone).

The basic premise is handled within Home assistant using the calendar domain, and we can access this with service calls, to, for example calendar.get_events which as you'd expect, get's events.

However, handling those events isn't as simple as you'd think, for me anyway, but we can do it.

To achieve what we want, a useable inventory of events for the day, we're going to use a custom template - We could code this in the UI but it would be messy and hard to read so we'll code it directly into our custom_templates.yaml. [If you don't have a custom_templates.yaml - get one and call it from configuration.yaml like template: !include custom_templates.yaml]

The Template (Which is an event really)

In our custom_templates, we're going to code:

  1. - trigger:
  2.   platform: time_pattern
  3.   hours: "/1"
  4.   action:
  5.   - service: calendar.get_events
  6.   target:
  7.   entity_id: calendar.richard
  8.   data:
  9.   start_date_time: "{{ now().strftime('%Y-%m-%d 00:00:00') }}"
  10.   end_date_time: "{{ now().strftime('%Y-%m-%d 23:59:59') }}"
  11.   response_variable: scheduled_events_richard
  12.   sensor:
  13.   - name: Scheduled Events 24h
  14.   unique_id: scheduled_events_24h
  15.   state: "{{ scheduled_events_richard['calendar.richard'].events | count() }}"
  16.   attributes:
  17.   scheduled_events_richard: "{{ scheduled_events_richard['calendar.richard'].events }}"
  18.   icon: mdi:calendar

IMPORTANT: my calendar is called 'richard', you're probably won't be so replace all occurrences of richard. with whatever your calendar is called.

This template, will trigger hourly on the hour, will call the service to get the day's events (calculating start/end dates to be today 00:00:00 to today 23:59:59) and stick them in a response variable called scheduled_events_richard. You don't need to change this if you don't want to, it won't affect your calendar and actually if you're only pulling one calendar then you could just call it 'scheduled_events' - but if you do change it, be sure to change it in the sensor section below.

The sensor section, then counts the number of events, storing that in the 'state' of 'Scheduled Events 24h' and then adds attributes to that sensor for the actual events. Here's an example of what that sensor might look like :

  1. icon: mdi:calendar
  2. friendly_name: Scheduled Events 24h
  3. scheduled_events_richard:
  4.   - start: "2024-02-21T09:00:00+00:00"
  5.   end: "2024-02-22T10:00:00+00:00"
  6.   summary: Something really important
  7.   - start: "2024-02-20"
  8.   end: "2024-02-21"
  9.   summary: Deago’s birthday

Remember, this is for my code, if you're not called Richard and change the code above, it'll have something different in here.

Using the sensor data

So, now we've isolated the calendar entries into a sensor that we can use anywhere, let's use it.

  1. {% if states('sensor.scheduled_events_24h')|int > 0 %}
  2. {{ 'Your Appointments for today are ' }}
  3. {% for state in state_attr('sensor.scheduled_events_24h','scheduled_events_richard') %}
  4. {% if "T" in state['start'] %}
  5. {{ 'at '~as_timestamp(strptime(state['start'],'%Y-%m-%dT%H:%M:%S%z'))|timestamp_custom("%H:%M") + ' you have ' + state['summary'] }}
  6. {% else %}
  7. {{ 'Today you have ' + state['summary'] }}
  8. {% endif %}
  9. {% endfor %}
  10. {% else %}
  11. {{ 'You Have No Appointments today' }}
  12. {% endif %}

Here, in this template we first check to see if you've actually got anything to do today, and if not we simply return 'You have No Appointments today', but if we do (remember the count of appointments is stored in the 'state', we return 'Your Appointments for today are '

Then we iterate through the sensor's attributes, and we check to see if there's a 'T' in the 'start' attribute. This is because for 'ALL DAY' events the calender entry will simply have a date and no time, and we need to handle these differently because we're going to convert the time for normal timed events into a sensible time. Its important to remember that this is the behaviour or MY CalDAV provider, yours my be different and return all times in your locale, or maybe return times for all day events - those adjustments you'll need to make yourself if so.

If there's a 'T' then we construct the line:

'at '~as_timestamp(strptime(state['start'],'%Y-%m-%dT%H:%M:%S%z'))|timestamp_custom("%H:%M") + ' you have ' + state['summary']

Its not as bad as it looks, trust me. The ~ is like a + but it can add anything together string, number, time whatever which is why we use it here. We get the time from the attribute where it stored as a string into a 'timestamp' variable, then we render that timestamp into just %H:%M which is just Hours and Minutes. state['summary'] is the actual text of the event, like 'take a walk' 'eat a mars bar' 'write a tutorial'.

This is of course an example, so hack it around to do what you need. The one possible issue you may hit if you're not at GMT or UTC is that the timezone offset will need to be handled. In a timestamp, the timezone offset is written like

2022-02-21T18:20:37+01:00

And as_timestamp will (should) take account of the +01:00 and add an hour to the time when you render it back out with timestamp_custom, but there are no guarantees because it really depends on the locale of your calendar and your home assistant as to whether we're going to need to adjust this. In my testing, as_timestamp handles the TZ Offset just fine.

https://www.home-assistant.io/docs/configuration/templating/#time

/home/gen.uk/domains/wiki.gen.uk/public_html/data/pages/opensource/leveraging_caldav_to_handle_appointments.txt · Last modified: 2024/02/21 19:07 by genadmin

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki