Heads up! Upcoming breaking change in the Template integration

I’m still confused by all of this tbh, and the main issue I’m having is with this one…

sensor:
  - platform: template
    sensors:
      unavailable_entities:
        friendly_name: Unavailable Entities
        value_template: "{{states|selectattr('state', 'in', ['unavailable', 'unknown', 'none'])
            |rejectattr('entity_id', 'in', state_attr('group.entity_blacklist', 'entity_id'))
            |rejectattr('entity_id', 'eq' , 'group.entity_blacklist')
            |map(attribute='entity_id')|list|length }}"
        attribute_templates:
          entities: "{{states|selectattr('state', 'in', ['unavailable', 'unknown', 'none'])
              |rejectattr('entity_id', 'in', state_attr('group.entity_blacklist', 'entity_id'))
              |rejectattr('entity_id', 'eq' , 'group.entity_blacklist')
              |map(attribute='entity_id')|list|join(', ') }}"
        unit_of_measurement: items

What I want is for this to react to every state change in my system, set the sensors state to the number of unavailable entities, and set the attribute ‘entities’ to a comma separated list of the entity_ids that are unavailable.

If I must compromise on update frequency, then I would much prefer once every second. Currently it is once per minute.

I would rather not use an automation to do this as the current logic of my system is to wait until all entities are available before turning on my automations, and I would prefer not to make an exception just for this sensor (for OCD reasons if nothing else).

What would be the best way to adapt this sensor to update every second, or even better update with every state change as desired please?

(I clicked the reply arrow on petro’s post but this is meant for everyone, not a specific reply to him, sorry!)

you could use the python script I posted and use an automation to trigger on event state_changed.

As far as I understand it all now, that wouldn’t only be the best, but also the only way… you might not want it, but following Amelchios schedule, there’s no other way of using states, and have factual updating

hence my fist bullet in the reply to that, was especially aimed at your needs :wink:

1 Like

Oh ignore me. I’m already doing it that way. I got confused. I thought that was being depreciated.

2 Likes

Appreciate the suggestion, although I fear I’ve missed the python_script you’re talking about somewhere in the haze of all of this. Let’s call that a fallback option for now and see if anyone can think of a way to just adapt the template to fulfil the requirements :slightly_smiling_face:

but what about the timezone difference:

+1!

btw here’s the link:

1 Like

There is no current way to fix the sensor, an automation is the only way to get what you want.

(For completeness, here is an example I posted earlier: Heads up! Upcoming breaking change in the Template integration - #434 by amelchio)

1 Like

this makes it update every 2 seconds:

  - alias: Trigger per 2 seconds
    id: Trigger per 2 seconds
    trigger:
      platform: time_pattern
      seconds: /2
    action:
      delay:
        seconds: 0

and this in place of now()

{{strptime(as_local(state_attr('automation.trigger_per_2_seconds','last_triggered')), '%Y-%m-%d') }}
{{state_attr('automation.trigger_per_2_seconds','last_triggered')}}

on a specially made automation. I guess we could also use an automatic state_change automation to trigger these per state change.

or will this ‘hack’ also be carved out?

edit

just stumbled on this quote, used for the introduction of the observer plugin in Supervisor 249:

says it all …

The same minority that is most active and provides a large part of the help here in the forums. Just saying.

4 Likes

Thanks :slightly_smiling_face:

Yeah, I think that automation is going to be my preference then (I was holding off moving to it whilst I was watching all the changes and then got confused), although the condition only looks for ‘new_state’, can I presume that the opposite of that is ‘old_state’ so that it also updates when the entities come back online?

I’ll implement this at the weekend.

Do it with an automation, I know you don’t want to but it’s pretty easy.

- alias: Unavailable Group Updates
  trigger:
    platform: event
    event_type: state_changed
  action:
    service: group.set
    data:
      object_id: "unavailable_entities"
      entities: >
        {{states|selectattr('state', 'in', ['unavailable', 'unknown', 'none'])
                |rejectattr('entity_id', 'in', state_attr('group.entity_blacklist', 'entity_id'))
                |rejectattr('entity_id', 'eq' , 'group.entity_blacklist')
                |map(attribute='entity_id')|list|join(',') }}

then your template sensor

sensor:
  - platform: template
    sensors:
      unavailable_entities:
        friendly_name: Unavailable Entities
        value_template: "{{expand('group.unavailable_entities) | count}}"
        attribute_templates:
          entities: "{{expand('group.unavailable_entities) | map(attribute='entity_id') | list | join(', ')}}"
        unit_of_measurement: items

But you probably don’t need the list in the sensor because you now have the group with the list…

sensor:
  - platform: template
    sensors:
      unavailable_entities:
        friendly_name: Unavailable Entities
        value_template: "{{expand('group.unavailable_entities) | count}}"
        unit_of_measurement: items
1 Like

Thank you. I have corrected second/minute in my post to prevent misleading others.

That’s word-play. Here’s what you said:

I agree it is no longer simple to understand. The good news is that it is simple to use so a lot less people will have to understand it now.

Again, one should usually not have to think about this.

As for the following opinion:

Look around. This forum is filled with technical support questions asking why Home Assistant behaves the way it does. Quite a few people don’t merely shrug off Home Assistant’s behavioral quirks.

3 Likes

this of course is a viable option, but, viewing this from the minimizing-processor-impact effort, you now have created both a group and sensor, which both will be tracked on all state changes of the containing states.
Or, all states even, considering this:


You wont have that using the python script scenario, which does seem a significant difference. Advantage if you like.

Nicely done, employing all the new features introduced in 0.115.


It’s clear that some Template Sensors will have to be re-designed due to the new way templates are evaluated. This thread’s purpose is how to adapt one’s templates to the deprecation of entity_id. Over the course of this thread, it has been a struggle to convince the development team that some functionality was lost in 0.115 … and how do we adapt to it.

To their credit, they did address some of the deficiencies with changes in 0.116 and with more changes coming in 0.117.

I believe the sum of these changes will address most of the identified issues and maintain good overall performance (I look forward to confirming that in 0.117). The two exceptions are:

  • Some applications will require more complex solutions.
    Templates like the one used by the ‘unavailability sensor’ will have to be re-engineered in the manner demonstrated by Petro or like Mariusthvdb did using a python_script. Yes, it becomes more complicated than in the past but the development team feels this represents a minority of applications. Time will tell.

  • No daily template evaluations.
    There will be no practical way of ensuring a template is evaluated just once a day. If you use now() anywhere in the template, it will be evaluated once a minute. In a separate GitHub discussion, balloob stated that the extra processing (1440 times a day vs once) is not a significant amount of daily overhead, even for an RPi. In 0.117, keep an eye on CPU usage and see if the prediction proves to be true.

So how many times a day is this going to update and is there a better way of doing it?

- platform: template
  sensors:
    zone_1_day_active:
      friendly_name: Irrigation Day Active
      value_template: >-
        {% set update = states('sensor.date') %}
        {{ ( is_state('input_boolean.zone_1_mon', 'on') and now().weekday() == 0 )
        or ( is_state('input_boolean.zone_1_tue', 'on') and now().weekday() == 1 )
        or ( is_state('input_boolean.zone_1_wed', 'on') and now().weekday() == 2 )
        or ( is_state('input_boolean.zone_1_thu', 'on') and now().weekday() == 3 )
        or ( is_state('input_boolean.zone_1_fri', 'on') and now().weekday() == 4 )
        or ( is_state('input_boolean.zone_1_sat', 'on') and now().weekday() == 5 )
        or ( is_state('input_boolean.zone_1_sun', 'on') and now().weekday() == 6 ) }}

I have many such sensors.

EDIT: Like this perhaps?

- platform: template
  sensors:
    zone_1_day_active:
      friendly_name: Irrigation Day Active
      value_template: >-
        {% set weekday = as_timestamp(states('sensor.date'))|timestamp_custom('%w') %}
        {{ ( is_state('input_boolean.zone_1_mon', 'on') and weekday == 1 )
        or ( is_state('input_boolean.zone_1_tue', 'on') and weekday == 2 )
        or ( is_state('input_boolean.zone_1_wed', 'on') and weekday == 3 )
        or ( is_state('input_boolean.zone_1_thu', 'on') and weekday == 4 )
        or ( is_state('input_boolean.zone_1_fri', 'on') and weekday == 5 )
        or ( is_state('input_boolean.zone_1_sat', 'on') and weekday == 6 )
        or ( is_state('input_boolean.zone_1_sun', 'on') and weekday == 0 ) }}

Based on my newfound understanding, I believe it will update minimally once a minute, due to the presence of now().

It will also update whenever any of the input_booleans change state (which is probably far less often given that you are using them to set the irrigation schedule).

You will be able to remove the reference to sensor.date because now() supersedes it in terms of frequency.

So having more than one reference to now() is still only going to update 1439 times more often than needed?

I’ve edited my post to show a method that removes all reference to now()

Should do the trick.

Yes, if you can perform the date/time calculation without employing now() then the evaluation frequency will be determined by the other entities within the template. In your case, that would be sensor.date, so just one evaluation per day.

It’s not as neat as using now().weekday() but at least it allows you to constrain the template’s evaluation frequency. Of course, all bets are off if the template employed states.DOMAIN.

BTW, I think this template achieves the same desired outcome:

- platform: template
  sensors:
    zone_1_day_active:
      friendly_name: Irrigation Day Active
      value_template: >-
        {% set today = as_timestamp(states('sensor.date'))|timestamp_custom('%a') | lower %}
        {{ is_state('input_boolean.zone_1_' ~ today, 'on') }}
1 Like

I knew you were going to find a neater way of doing it. So predictable. :slight_smile:

Thank you.

3 Likes

fwiw, here’s a translation of my earlier posted template that used the sensor.date as trigger for the now()…

      dayofyear:
        friendly_name: Day number
        value_template: >
          {{as_timestamp(states('sensor.date'))|timestamp_custom('%j')}}

      weekofyear:
        friendly_name: Week number
        value_template: >
          {{as_timestamp(states('sensor.date'))|timestamp_custom('%-U')}}

      dag:
        friendly_name: Dag
        value_template: >
          {% set dagen =
            { 'Mon': 'Maandag',
              'Tue': 'Dinsdag',
              'Wed': 'Woensdag',
              'Thu': 'Donderdag',
              'Fri': 'Vrijdag',
              'Sat': 'Zaterdag',
              'Sun': 'Zondag'} %}
          {% set day = as_timestamp(states('sensor.date'))|timestamp_custom('%a') %}
          {% set dag = dagen[day] if day in dagen else state %}
          {{dag}}

      maand:
        friendly_name: Maand
        value_template: >
          {% set maanden =
            { '01': 'Januari',
              '02': 'Februari',
              '03': 'Maart',
              '04': 'April',
              '05': 'Mei',
              '06': 'Juni',
              '07': 'Juli',
              '08': 'Augustus',
              '09': 'September',
              '10': 'Oktober',
              '11': 'November',
              '12': 'December',} %}
          {% set month = as_timestamp(states('sensor.date'))|timestamp_custom('%m') %}
          {% set maand = maanden[month] if month in maanden else state %}
          {{maand}}

      vandaag:
        friendly_name: Vandaag
        value_template: >
          {{states('sensor.dag')}} {{states('sensor.current_day')}} {{states('sensor.maand')}} {{states('sensor.year')}}

      today:
        friendly_name: Today
        value_template: >
          {{as_timestamp(states('sensor.date'))|timestamp_custom('%A %-d %B %Y')}}

      current_day:
        friendly_name: Current day
        value_template: >
          {{as_timestamp(states('sensor.date'))|timestamp_custom('%-d')}}

      year:
        friendly_name: Year
        value_template: >
          {{as_timestamp(states('sensor.date'))|timestamp_custom('%Y')}}

      days_current_month:
        friendly_name: Days current month
        value_template: >
          {% set month =  as_timestamp(states('sensor.date'))|timestamp_custom('%m') %}
          {% if month in ['1','3','5','7','8','10','12'] %} 31
          {% elif month in ['4','6','9','11'] %} 30
          {% else %} {{'29' if states('sensor.year')|int//4 == 0 else '28'}}
          {% endif %}

      remaining_days:
        friendly_name: Remaining days
        value_template: >
          {% set this = strptime(states('sensor.date'), '%Y-%m-%d') %}
          {% set next = this.month + 1 if this.month + 1 <= 12 else 1 %}
          {% set last = this.replace(month=next, day=1) %}
          {{(last.date() - this.date()).days}}

      past_days:
        friendly_name: Past days
        value_template: >
          {% set this = strptime(states('sensor.date'), '%Y-%m-%d') %}
          {% set next = this.month + 1 if this.month + 1 <= 12 else 1 %}
          {% set first = this.replace(day=1) %}
          {{(this.date() - first.date()).days}}
1 Like