Trigger-based template sensor using time_pattern not updating

I have a truly bizarre one here…

I have a trigger-based template sensor using a time pattern that’s supposed to update every minute, but it isn’t. It used to work fine, as far as I can tell. I only noticed this issue yesterday after a restart. I didn’t upgrade or perform any other updates. I made some config changes to my configuration, but not to this. HA Core 2024.3.1.

Here’s the sensor’s config:

  - trigger:
    - platform: time_pattern
      hours: "*"
      minutes: "*"
      seconds: 0
    - platform: state
      entity_id:
        - number.capacity_point_1
        - number.capacity_point_2
        - number.capacity_point_3
        - number.capacity_point_4
        - number.capacity_point_5
        - number.capacity_point_6
    sensor:
      - name: "Capacity Charge Point"
        unique_id: "12b69471-fdbc-4f9a-9a75-960545211e3e"
        state: >-
          {%- from 'resources.jinja' import get_current_entity_id -%}
          {{ states(get_current_entity_id('number.capacity_point_')) }}
        attributes:
          current_entity_id: >-
            {%- from 'resources.jinja' import get_current_entity_id -%}
            {{ get_current_entity_id('number.capacity_point_') }}
        # not really, but we get dynamic icons this way
        device_class: battery
        unit_of_measurement: "%"

This is suppose to trigger every hour of every minute or when one of the listed entities changes. All this really does is to pick the correct entity ID’s value, since these entities have a value for different timeslots of the day. I use this sensor purely for display purposes to show me the current value.

Here’s the macro:

{# https://www.home-assistant.io/docs/configuration/templating/#reusing-templates #}

{#
Get the index for the current work mode slot and add it to an entity ID prefix.

:param entity_id_prefix: An entity ID prefix (i.e. including the domain).

:returns: An entity ID after adding an integer to the prefix.
#}
{%- macro get_current_entity_id(entity_id_prefix) -%}
    {%- set time = now().strftime('%H:%M') -%}
    {#- these times must match the work mode timers on the inverter -#}
    {#- could use a map too; whatever -#}
    {%- if '01:00' <= time < '05:00' -%}
        {{ entity_id_prefix }}1
    {%- elif '05:00' <= time < '08:00' -%}
        {{ entity_id_prefix }}2
    {%- elif '08:00' <= time < '13:00' -%}
        {{ entity_id_prefix }}3
    {%- elif '13:00' <= time < '17:00' -%}
        {{ entity_id_prefix }}4
    {%- elif '17:00' <= time < '21:00' -%}
        {{ entity_id_prefix }}5
    {%- else -%}
        {#- 21:00-01:00 -#}
        {{ entity_id_prefix }}6
    {%- endif -%}
{%- endmacro -%}

At 13:00 today (it is now just after 14:00), the value of 15% was supposed to change to 50%.

Here’s the current template sensor value:

And here are the individual sensor values:

Same data using the dev tools:

When I evaluate the template in the dev tools, it works as expected. It uses the correct entity ID and it gets the correct value (the third value is the current template sensor value, which is incorrect):

I have no idea how to even debug this further without getting into some code.

Any reason you’re doing it this way?

This will be the same without a trigger:

    - sensor:
      - name: "Capacity Charge Point"
        unique_id: "12b69471-fdbc-4f9a-9a75-960545211e3e"
        state: >-
          {%- from 'resources.jinja' import get_current_entity_id -%}
          {{ states(get_current_entity_id('number.capacity_point_')) }}
        attributes:
          current_entity_id: >-
            {%- from 'resources.jinja' import get_current_entity_id -%}
            {{ get_current_entity_id('number.capacity_point_') }}
        # not really, but we get dynamic icons this way
        device_class: battery
        unit_of_measurement: "%"

the now() in your macro will force the template to update once a minute on the minute. Whatever state you grab for the main state will force updates from just that entity. When it switches to a new entity based on time, the template will listen to that new entity (instead of all entities at all times).

Outside that, your time_pattern is odd. I’d just have

    - platform: time_pattern
      minutes: "/1"

I think I somehow thought the dynamically created entity IDs (number.capacity_point_*) wouldn’t be detected and thus subscribed to for changes, but given what you’re saying, I see I might’ve been wrong there. The one thing I did miss is that I have now() in there.

I think, for clarity (since the macro cannot be seen while looking at this piece of config), I might keep the time pattern to make it clear (to my future self) that it’s how it will be evaluated. The counter to that would be, should I want a lower resolution of updates (say every 5 min), then it will still update every minute due to the use of now(). I need to think this over.

You’re right about the time pattern too: That’s simpler and more cron-like. I think I copy and pasted this from an older example I had somewhere when I created this (and it’s also used in the docs).

Still, why wouldn’t it work?

Way back in the day, the template engine would parse the template and look for entity_id’s.

About 4 years ago, templates were rewritten. When the states function is called, the template will register a listener for the entity_id that the states function is calling.

Not sure, I don’t use the '*' for time_patterns.

1 Like

Thanks, Petro.

FYI

Templates will update once a minute if you have the following functions in the template:

now()
today_at()
relative_time()

Templates will update when a state changes if you use

closest()
distance()
states.xxx.xxx
states()
state_translated()
states_attr()
is_state()
is_state_attr()
expand()
has_value()

Templates will render at most once per second if you use

states.<domain>

Templates will render at most once per minute if you use the states object without specifying a domain or full entity_id, e.g.

states 
5 Likes

To provide a bit more feedback:

Even using this simple time pattern didn’t work:

    - platform: time_pattern
      minutes: "/1"

I removed it completely and went with Petro’s triggerless sensor definition, which works.

I still stumped why it worked before and why a forced trigger (granted, it’s redundant) would stop the sensor from updating.

There may be a bug with this, I’d suggest writing it up as an issue.

1 Like

Trigger-based template sensor using time_pattern not updating · Issue #114195 · home-assistant/core (github.com)

This might’ve been a PEBKAC issue. I’ve closed the bug report. See details there.

Excellent summary that deserves addition to the documentation: Rate Limiting Updates.


I’ve bookmarked your post in order to direct others to it whenever there’s a question about when and why a template is evaluated.

2 Likes

I guess I should double check that list of methods that creates state listeners then. I was going off memory. I’m 90% sure it’s complete.

The time functions are correct, same with the rate limiters.

The new ones for me (regarding how they influence evaluation) are relative_time() and has_value().

Yes, has_value was a bug. I added the minutely updates to today_at and relative_time at the same time because it was stupid having to use now() with either of those to get the template to update.

1 Like

It’s a great summary. I bookmarked it too for future use.

(Thanks, Petro.)

1 Like

This has been added as one of the Cookbook items.
Please review and edit for any changes there. I also suggest using that page as a referral.
I basically copied that post and included attribution, then added the cookbook tag and added a link in the cookbook index.
At What Rates Do Templates Render & Update.

Thanks @parautenbach for the suggestion!

1 Like