Heads up! Upcoming breaking change in the Template integration

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

I can do unpredictable, but it’s counter-productive. Like some recent software changes.

/s

5 Likes

Yup, that will have to be the suggested workaround wherever once-a-day evaluation is desired

Kind of a shame considering now() is a datetime object with many useful methods that will now have to be replicated via a more long-winded technique. Nevertheless, it’s an acceptable workaround for the few who wish to preserve the old behavior.

Posting this link for everyone’s convenience:

https://strftime.org/

yes, that’s a true bummer.
will keep my backup at hand, so I can only take out the first line
{% set trigger = states('sensor.date') %}

to use that again.

FWIW, I will need to amend the first post of this thread to reflect the changes implemented in 0.116 and the upcoming change in 0.117. The suggestions currently offered in the first post are no longer valid.

The strptime method creates a datetime object:

{% set midnight = strptime(states('sensor.date'), '%Y-%m-%d') %}
{{ midnight.isoweekday() }}

@Mariusthvdb @123 @tom_l you don’t want to use as_timestamp. You want to use strptime(). as_timestamp assumes everything is UTC unless specified. The strptime method assumes local. the strptime method on a datetime object assumes local or utc depending on the object.

{{ strptime(x, format) }} # this is the method
{{ now().striptime(x, format) }} # this is the method on a datetime object

@tom_l here’s what you should do:

{% set weekday = strptime(states('sensor.date'), '%Y-%m-%d').strftime('%w') | int %}
{{ ( 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 ) }}

but you can simplify to

{% set day = strptime(states('sensor.date'), '%Y-%m-%d').strftime('%a').lower() %}
{{ is_state('input_boolean.zone_1_' ~ day, 'on') }}

I cant think of a way to do that for this though:

- platform: template
  sensors:
    roborock_tomorrow:
      friendly_name: "Roborock Tomorrow"
      value_template: >-
        {% set tomorrow = ( as_timestamp(states('sensor.date')) + 86400)|timestamp_custom('%a')|lower %}
        {{ is_state('input_boolean.vac_' ~ tomorrow, 'on') and ( is_state('automation.upstairs_scheduled_vacuum', 'on') or is_state('automation.downstairs_scheduled_vacuum', 'on') ) }}

FWIW, I’ve run this comparison of the two techniques and the as_timestamp method is always faster. :man_shrugging:

{% set tomorrow = (strptime(states('sensor.date'), '%Y-%m-%d') + timedelta(days=1)).strftime('%a').lower() %}
{{ is_state('input_boolean.vac_' ~ tomorrow, 'on') and ( is_state('automation.upstairs_scheduled_vacuum', 'on') or is_state('automation.downstairs_scheduled_vacuum', 'on') ) }}
1 Like

You’re welcome to use as_timestamp but you need to add your timezone to the date… and if you’re DST it can be a pain in the ass.

Came here to post this but ninja’d by Petro (and then some).

1 Like