Template Guide: Days away from calendar event

Do the different pickups follow a set pattern? If there is a pattern, you can use templating to create a list of dates to populate a calendar using the calendar.create_event service with a Repeat for each action.

Here are a couple examples: HA - Create calendar events for all trash nights · GitHub

Yes, that’s true if you want to count the number of days to any event after the next event. If you just want the next event, then you can use 1 calendar.

create multiple calendars or use the custom integration that pulls future events out of HA.

EDIT: Drew’s solution gets around that by creating the calendars for you it seems.

@Didgeridrew - Yes, trash is every Friday and recycling is every other Friday. This is the one that trips me up as everyone on my street gets it wrong… but Petro mentioned this solution also creates multiple calendars and I’d like to avoid that given I am using a Google calendar for all house/family events and I would end up with many sub-calendars (name?) making the feature less usable… right now I can select “Kids” to see theirs, or “House” to see maintenance, and so on.

@petro - Can you point me to the integration? I only see these in HACS:

I already have the Google Calendar Integration installed for this calendar. By any chance, is that the one you were referring to?

I have trash and recyclables on the same calendar, however I don’t separate the two. I just notify myself on the events that day.

Sorry, I don’t remember what it was called or where I saw it.

1 Like

Off topic maybe, but I use the excellent Waste Collection Schedule plugin (in HACS) to do what you want: GitHub - mampfes/hacs_waste_collection_schedule: Home Assistant integration framework for (garbage collection) schedules

If your community is listed, I suggest using it! If not listed, you can add it.

1 Like

The method I proposed only creates events, not new calendars. It’s been a while since I used Google Calendar regularly, but my understanding is that the calendar.create_event service still works with HA-connected Google calendars.

1 Like

When you first set it up with your code example, does the sensor only become available after midnight?

Honestly, I don’t remember. I’ll have to look at it in the morning. Until then, you might want to check out the macro library I made that just does the calculations for you.

I modified your code for my instance and the statement example works for me, but for some reason the list example does not. Not sure why. This also relates to my prior question about the date. The sensors I created showed unavailable.

Yeah, it had an issue in it. Updated original post

1 Like

@petro I used your helpful example (1st post) to create two date sensors that calculate days to next event in the calendars for trash and recycling. It all works as expected but I keep getting an error in the logs that I can’t decipher.

Templates:

- sensor:
    - name: "Trash Day"
      icon: "mdi:trash-can-outline"
      state: >
        {% set midnight = today_at() %}
        {% set event = state_attr('calendar.trash', 'start_time') | as_datetime | as_local %}
        {% set delta = event - midnight %}
        {% if delta.days == 0 %}
          Bring trash in!
        {% elif delta.days == 1 %}
          Put trash out!
        {% elif delta.days <= 5 %}
          Friday
        {% elif delta.days > 5 %}
          Next Week
        {% endif %}

#Controls image of trash can even though for now it is the same one for the 3 states
- sensor:
    - name: "Trash"
      icon: "mdi:trash-can-outline"
      state: >
        {% set midnight = today_at() %}
        {% set event = state_attr('calendar.trash', 'start_time') | as_datetime | as_local %}
        {% set delta = event - midnight %}
        {% if delta.days == 0 %}
          0
        {% elif delta.days == 1 %}
          1
        {% elif delta.days > 1 %}
          2
        {% endif %}

Error in log:

Logger: frontend.js.latest.202305033
Source: components/system_log/__init__.py:257
First occurred: 10:46:45 (6 occurrences)
Last logged: 15:49:57

https://xxxxxx.ui.nabu.casa/frontend_latest/14845--QdpkFp3oUQ.js:5:56702 Uncaught TypeError: Cannot read properties of null (reading 'sensor.trash_day')
https://xxxxxx.ui.nabu.casa/frontend_latest/14845--QdpkFp3oUQ.js:5:56702 Uncaught TypeError: Cannot read properties of null (reading 'sensor.recycling_day')

Could it be complaining about a missing default? If so, I could not find anything on how and where to add one. Do you have any suggestion on what to do?

That’s a ui error, has nothing to do with your templates

@petro Those sensors also control what images is displayed in glance cards so maybe I have an error there. I will look there, thanks!

I would like to reuse the sensor state for the attributes, but I can’t get it to work.

As an example, I have two sensors. The first works without reusing the ‘event’ in the attribute ‘days’.

- platform: template
  sensors:
    bday_test_1:
      value_template: >
        {% set t = now() %}
        {% set midnight = today_at() %}
        {% set event = state_attr('calendar.test', 'start_time') | as_datetime | as_local %}
        {{ event }}
      attribute_templates:
        days: >-
          {% set t = now() %}
          {% set midnight = today_at() %}
          {% set event = state_attr('calendar.test', 'start_time') | as_datetime | as_local %}
          {% set delta = event - midnight %}
          {{ delta.days }}
        text: >-
          {% if this.attributes.days == 0 %}
            heute
          {% elif this.attributes.days == 1 %}
            morgen
          {% elif this.attributes.days == 2 %}
            übermorgen
          {% else %}
            in {{ this.attributes.days }} Tagen
          {% endif %}

The second example does not work for the attribute ‘days’ with this.state → {% set delta = this.state - midnight %}. I would like to reuse the ‘event’ respectively the states value.

- platform: template
  sensors:
    bday_test_2:
      value_template: >
        {% set t = now() %}
        {% set midnight = today_at() %}
        {% set event = state_attr('calendar.test', 'start_time') | as_datetime | as_local %}
        {{ event }}
      attribute_templates:
        days: >-
          {% set midnight = today_at() %}
          {% set delta = this.state - midnight %}
          {{ delta.days }}
        text: >-
          {% if this.attributes.days == 0 %}
            heute
          {% elif this.attributes.days == 1 %}
            morgen
          {% elif this.attributes.days == 2 %}
            übermorgen
          {% else %}
            in {{ this.attributes.days }} Tagen
          {% endif %}

Here you can see the result of both sensors:

Thanks in advance for the help.

1 Like

States are strings and attribute resolution order is not guaranteed. The only guarantee is that state will be resolved before attributes. At most, you can use the states in your attributes, but you have to convert it to a datetime object. You’ll also have to perform the math in both attributes.

Makes sense, thanks for your explanations.

This was great! Much simpler than the way I was trying. Nicely done!

I’ve been using the template for a while and until a few days ago allworked perfectly - But since the last update of HA, my calendars don’t have the “start_time” attribute anymore (despite upcoming events being correctly displaced on the calendar view in HA).

The calendar only have “friendly_name” and “offset_reached” attributes.

Is that just me? Any advice what could cause this? Thanks!

I implemented the example at the top,

But when it gets to the day after the event, its finding the previous event instead of the next event, so my days goes to -1

Does anyone know how to force it to only search forward

{% set t = now() %}
      {% set midnight = today_at() %}
      {% set event = state_attr('calendar.bin_collection', 'start_time') | as_datetime | as_local %}
      {% set recycling = is_state_attr('calendar.bin_collection', 'message', "Green Bin") %}
      {% set delta = event - midnight %}
      {% if recycling %}
        Recycling
      {% else %}
        Waste
      {% endif %}
      {% if delta.days == 0 %}
        Today
      {% elif delta.days == 1 %}
        Tomorrow
      {% else %}
        In {{ delta.days }} Days
      {% endif %}

Exactly what I needed! :+1: :bowing_man: