Sensor-template for caldav-addon: sometimes working, mostly not

I use the Caldav addon from Github, which works very well so far. Now I want to output the upcoming 10 appointments from two calendars as a list for a display. These are to be published later via MQTT.
The template works in the developer mostly, but after restart I always get errors like TypeError: object of type 'NoneType' has no len().
My suspicion is that the error occurs because the data in the two calendars are not yet available after restart. But so far I haven’t managed to eliminate this error by a condition either.
Is my approach maybe just wrong to do the work via a sensor-template?

- platform: template
  sensors:
    events:
      friendly_name: "Termine"
      value_template: >-
        {% set ns = namespace() %}
        {% if state_attr("sensor.cal_gemeinsam", "data")|count > 0 %}
          {% set ns.nr_a = 0 %}
          {% set ns.nr_b = 0 %}
          {% set anzahl_a = state_attr("sensor.cal_gemeinsam", "data")|count %}
          {% set anzahl_b = state_attr("sensor.cal_familie", "data")|count %}
          {% set ns.anzahl = anzahl_a + anzahl_b %}

          {% if ns.anzahl > 10 %}
            {% set ns.anzahl = 10 %}
          {% endif %}

          {% for i in range(0, ns.anzahl) %}

            {% if ns.nr_a > anzahl_a - 1 %}
              {% set ns.datum_a = 'fertig' %}
            {% else %}
              {% set ns.datum_a = state_attr("sensor.cal_gemeinsam", "data")[ns.nr_a].startDate %}
            {% endif %}

            {% if ns.nr_b > anzahl_b - 1 %}
              {% set ns.datum_b = 'fertig' %}
            {% else %}
              {% set ns.datum_b = state_attr("sensor.cal_familie", "data")[ns.nr_b].startDate %}
            {% endif %}

            {% if ns.datum_a < ns.datum_b %}

              {% if state_attr("sensor.cal_gemeinsam", "data")[ns.nr_a].start_time == '00:00' %}
                {{ state_attr("sensor.cal_gemeinsam", "data")[ns.nr_a].start_day }}. {{ state_attr("sensor.cal_gemeinsam", "data")[ns.nr_a].start_month }}: {{ state_attr("sensor.cal_gemeinsam", "data")[ns.nr_a].summary }}
              {% else %}
                {{ state_attr("sensor.cal_gemeinsam", "data")[ns.nr_a].start_day }}. {{ state_attr("sensor.cal_gemeinsam", "data")[ns.nr_a].start_month }}, {{ state_attr("sensor.cal_gemeinsam", "data")[ns.nr_a].start_time }} Uhr: {{ state_attr("sensor.cal_gemeinsam", "data")[ns.nr_a].summary }}
              {% endif %}
              {% set ns.nr_a = ns.nr_a + 1 %}

            {% else %}

              {% if state_attr("sensor.cal_familie", "data")[ns.nr_b].start_time == '00:00' %}
                {{ state_attr("sensor.cal_familie", "data")[ns.nr_b].start_day }}. {{ state_attr("sensor.cal_familie", "data")[ns.nr_b].start_month }}: {{ state_attr("sensor.cal_familie", "data")[ns.nr_b].summary }}
              {% else %}
                {{ state_attr("sensor.cal_familie", "data")[ns.nr_b].start_day }}. {{ state_attr("sensor.cal_familie", "data")[ns.nr_b].start_month }}, {{ state_attr("sensor.cal_familie", "data")[ns.nr_b].start_time }} Uhr: {{ state_attr("sensor.cal_familie", "data")[ns.nr_b].summary }}
              {% endif %}
              {% set ns.nr_b = ns.nr_b + 1 %}

            {% endif %}

          {% endfor %}

        {% endif %}

Make your calendar data variables and provide a default empty list when that information is none.

Also, you can just add your calendar data together and iterate that, you don’t need to manage separate indexes. Lastly, you can truncate any list by slicing it using the slice syntax. [:10] → everything before the 10th index.

		{% set gemeinsam = state_attr("sensor.cal_gemeinsam", "data") | default([]) %}
		{% set familie = state_attr("sensor.cal_familie", "data") | default([]) %}
        {% if gemeinsam|count > 0 %}
		  {% set cals = gemeinsam + familie %}
		  {% for cal in cals[:10] %}
		    {% if cal.start_time == '00:00' %}
			  {{ cal.start_day }}. {{ cal.start_month }}: {{ cal.summary }}
			{% else %}
			  {{ cal.start_day }}. {{ cal.start_month }}, {{ cal.start_time }} Uhr: cal.summary }}
			{% endif %}
		  {% endfor %}

Wow, that’s significantly more elegant, thanks! The first 10 entries in the index now come from the first calendar, from position 11 I get the entries from the second calendar by this addition. If I see it correctly, I create one index per calendar and then sort them by date like in my script, right? Or can the index simply be sorted by a field?
I tried it this way, but it doesn’t have any affect:

		  {% set cals = gemeinsam + familie %}
          {% for cal in cals|sort(attribute='startDate') %}
          {% endfor %}

what does startDate contain?

Something like this: 2022-05-11T17:30:00.000Z
The comparison with “greater than” works.

Apart from that, I still get the message TypeError: object of type 'NoneType' has no len() as soon as the system reboots. But before that everything works fine in the template editor. Is there perhaps any way to delay a template?

when you reply, reply to the person not the thread.

		{% set gemeinsam = state_attr("sensor.cal_gemeinsam", "data") or [] %}
		{% set familie = state_attr("sensor.cal_familie", "data") or [] %}
        {% if gemeinsam|count > 0 %}
		  {% set cals = (gemeinsam + familie) | sort(attribute='startDate') %}
		  {% for cal in cals[:10] %}
		    {% if cal.start_time == '00:00' %}
			  {{ cal.start_day }}. {{ cal.start_month }}: {{ cal.summary }}
			{% else %}
			  {{ cal.start_day }}. {{ cal.start_month }}, {{ cal.start_time }} Uhr: cal.summary }}
			{% endif %}
		  {% endfor %}

Ups, sorry…
Now the entity remains empty, but maybe better than not available? I also changed the query to if true, it makes no difference. The dates of the calendars are not present the same, so I suspect that this template is executed only once and thus misses the dates from the calendars.
Once dates are present, it works (with sorting!) in the developer once I run template: reload. However, this step causes the entity to be completely deleted.

if it doesn’t create the entity, that means there’s an error in the logs

Correct! Invalid state encountered for entity ID: sensor.events. State max length is 255 characters.
For mqtt this would probably not be a problem, but is there a good solution to get around this limit? I don’t want to use node-red to keep the system as lean as possible.

You can put the info in an attribute

Hmm, could you give me a hint? Creating JSON?

No, put the template in an attribute instead of the state

I have read through the FAQ on templating and many posts on the forum, but only find ways to read attributes, not write them. Or is attribute_templates needed for this? I have made various attempts with something like:

- platform: template
  sensors:
    terminliste:
      value_template: >-
        something	
      attribute_templates:
        data: >-
          {% set gemeinsam = state_attr("sensor.cal_gemeinsam", "data") or [] %}

But so far without success. Probably it behaves similarly, as in this post. But he does not help me :frowning: