Heads up! Upcoming breaking change in the Template integration

If it works the way I described, it means it’s very generous in how it interprets/identifies entities but also means it’s equally generous in how many listeners it assigns.

I’m sort of hoping to be corrected on this point because if your template begins with states.sensor it will get listeners for all sensors in your system. That’s overly generous, especially if the rest of the template narrows it down to just a handful of sensors that you actually want to monitor.

really sorry but I completely missed that… will need some close eyes what has fundamentally changed in your new macro, but will add it now and restart. So you say I dont need the entity_ids now? Since they are explicitly named in the macro I presume?
thanks again!

It does make those count sensors super easy and makes the 0.104 group_all removal crap a simple 1 liner fix.

S H I T

:man_shrugging:

Don’t quote me just yet. That’s just my guess and it’s not based on firsthand experience or examination of the code.

You’ll need to access all the entities every shot if you want them as listeners. Your current template only access weekend entities on the weekend and weekday entities on the weekdays.

No, I understood that.
But … That is ONE possible interpretation of the statements made so …
Will await clarification

We live in interesting times …

yes, just tested: even with the new macro, I need all entity_ids listed for the large timestamp sensor to update and trigger updating the other sensors correctly.

The way I understand it (although I may be mistaken) with the current system, if you have any entities listed under entity_id you need to have them all listed as it overrides the automatic parsing, so does it work if you remove all the entities?
You’d possibly also need to reference states(‘sensor.time’) somewhere in the template as well.

If you iterate states.sensor, you will get a listener for all sensors on the system, and for the creation of new sensors. That’s not as bad as it sounds since we now have indexed listeners as of 0.113. Before 0.113, everything would listen for the state change events and then filter them out when they fired. We do a bit of optimization to avoid re-render templates that it doesn’t affect, but if the template iterates all the sensors it has to listen for all sensor state changes.

1 Like

Yes, sensor.time is among them.

Which makes me think: if what you say is correct, (not doubting you, it’s just I hadn’t realized that before) wouldn’t that require one to list all entity_id’s relevant to the template if sensor.time is listed?

If not it would only update once a minute?

Also, there is no change in behavior between either macro, so what would be the benefit using one or the other?

Yes (10 charachter minimum)

Edit: listing them tells it to “ONLY look at this list”

just as a fyi, Ive added the new macro in an _alt sensor, to be able to see if any difference exists: none… they both update exactly the same.

what’s more: this excercise has made clear that all sensors need both the triggering timestamp sensor, And sensor.time to update correctly. This can be easily established because the sensors in the screenshot show how long it will take for the next alarm to take place.
They don’t update without sensor.time, inspite of sensor.time being listed as trigging entity_id on sensor.next_alarm_timestamp, which has all needed entity_id’s and sensor.time listed…

This is obvious of course…sensor.time isn’t helpful on the timestamp sensor, because that is, well, a timestamp, which doesn’t change when time passes… all other sensors do need that time to shift…

leaving me with the question about the 2 macros: why the one or the other?

It looks small, but it feels “big”… I hope as_local() gets mentioned in the release notes so others outside this thread find it quickly (maybe a direct link to the example on the binary_sensor page you are adding).

Or maybe better yet, thread had lots of good info - perhaps release notes should just link to it?

You should be able to do a quick and dirty test using : -

Which will substitute until something better comes along

I just noticed this thread linked from the release notes and skimming through it, I didn’t really see this question answered. Forgive me if I missed it, it’s already a long thread.

A template like this (which I use to turn my amplifier on/off):

{{ is_state("media_player.samsungtv", "on") or is_state("media_player.apple_tv", "playing") }}

used to be recalculated whenever one of the two entities changed. However, if the TV is on, we know the template will always be true so updating the template when the Apple TV is (de)paused is a waste of effort. The Apple TV state cannot affect the result when the TV is on! With 0.115, the template is thus only recalculated when the TV changes state or if it is already off. The current state of the system is used to deduce which parts of the template can currently be ignored.

That is just a performance improvement (less template recalculations) but if we change it like this:

{{ is_state("media_player.samsungtv", "on") or is_state(state("input_select.media"), "playing") }}

the performance improvement becomes significant. We now watch the TV state, the media selector and the currently selected media player. The old way would always watch all possible media players.

Furthermore, previously you had to carefully list all possible input_select.media values as entity_id: on any template that used input_select.media as input like above. This is now completely automatic, a huge improvement in usability and much less error-prone.

Moving on, we can change the template like this:

{{ is_state("media_player.samsungtv", "on") or is_state(state("input_text.media"), "playing") }}

and we now have something that was impossible to do before. An input_text can contain any value so you cannot possibly list them all as entity_id: in advance.

So that’s the reasoning for the change. Everything is now faster, easier, smaller and it always works.

The downside is that we need to rework templates that rely on time to use a new workaround for periodic recalculation – which is what this thread was about.

(Another arguable downside is that interdependent templates will have to be untangled to not cause a CPU spike due to an essentially infinite loop. In essence, if template a is b+1 and template b is a+1 each template will now continuously update forever. This is actually correct but probably not very useful so I think code will be added to detect this and abort after a certain depth. This could not all be in place for the first release because we are still learning about such situations as people report templates that they use.)

4 Likes

Thank you for the explanation. It amazes me that this can be done at all, let alone improved.

So I’ve upgraded to 115 and I have a template sensor that calculates the difference between two dates. The way I achieved this previously was with the following:

platform: template
sensors:
  softener_salt_last_replaced:
    value_template: '{{ ((as_timestamp(now())-(states.input_datetime.softener_salt.attributes.timestamp)) | int /60/1440) | round(0) }}'
    unit_of_measurement: 'Days'
    entity_id: input_datetime.softener_salt, sensor.date
    friendly_name: 'Softener Salt'

So (if my understanding is correct) the above would only have updated when either of the listed entities changed state.
As I used as_timestamp(now(), which won’t auto-update in 115, and with the loss of listing the entity ids I have to find another way of doing this. Obviously the easy fix would be to change to something like the below (as already suggested in this thread) with the addition of reliability on sensor.date:

platform: template
sensors:
  softener_salt_last_replaced:
    value_template: >-
      {% set zilch = states('sensor.date') %}
      {{ ((as_timestamp(now())-(states.input_datetime.softener_salt.attributes.timestamp)) | int /60/1440) | round(0) }}
    unit_of_measurement: 'Days'
    friendly_name: 'Softener Salt'

However, as my overall intention was to calculate the difference between two dates I thought I could build sensor.date into the actual template like so:

platform: template
sensors:
  softener_salt_last_replaced:
    value_template: >-
      {{((as_timestamp(strptime(states('sensor.date'), '%d.%m.%Y'))-state_attr('input_datetime.softener_salt', 'timestamp')) /60/1440) | int}}      
    unit_of_measurement: 'Days'
    friendly_name: 'Softener Salt'

Is there a better way of doing the above? Or is it overkill? Would the addition of {% set zilch = states('sensor.date') %} be enough?

That is fine. Use what you like best, both will work equally well (and so will other variations).

more than that, would we need to set it only once in the value_template, to have it also trigger the other defined templates of the same template sensor? Ive asked in the release post here

or do we need to set that now in all individual sensors (since they are that, individual…)

eg:

      hour_icon:
        friendly_name: Hour icon
        entity_id: sensor.time
        value_template: >
          {% set word = ['skipthis','one','two','three','four','five','six','seven',
                         'eight','nine','ten','eleven','twelve','one'] %}
          {%- set hour = now().strftime('%-I')|int %}
          {%- set minute = now().strftime('%-M')|int %}
          {%- set index = hour if minute <= 30 else hour + 1 %}mdi:clock-time-{{word[index]}}
            {{- '-outline' if states('sun.sun') != 'above_horizon' }}

        icon_template: >
          {% set word = ['skipthis','one','two','three','four','five','six','seven',
                         'eight','nine','ten','eleven','twelve','one'] %}
          {%- set hour = now().strftime('%-I')|int %}
          {%- set minute = now().strftime('%-M')|int %}
          {%- set index = hour if minute <= 30 else hour + 1 %}mdi:clock-time-{{word[index]}}
            {{- '-outline' if states('sun.sun') != 'above_horizon' }}

        attribute_templates:
          Hour: >
            {{now().strftime('%-I')}}
          Minutes: >
            {{now().strftime('%-M')}}
          Addition: >
            {{0 if now().strftime('%-M')|int <= 30 else 1}}

would need the {% set x = states('sensor.time') %} in all templates…?