Use template for entity_id (in automation trigger)

Hi,

I might have taken a wrong turn somewhere, but I got a bit confused messing with an automation. :sweat_smile:

I have an automation with the following trigger:

platform: state
entity_id: 
  - sensor.my_sensor_1
  - sensor.my_sensor_2
  - sensor.my_sensor_3
attribute: some_sensor_attribute
from: false
to: true

The entity_idā€™s should be dynamic and based on some filter criteria, I put the following together:

{{ states | selectattr('entity_id', 'match', '^(sensor).my_sensor_*') | list  }}

This perfectly evaluates into a list of respective entity_idā€™s, just how I wanted it to.
However, it doesnā€™t appear as if I can just go ahead and use that to base the entity_id value in my automation trigger on.

So this is not working:

platform: state
entity_id: "{{ states | selectattr('entity_id', 'match', '^(sensor).my_sensor_*') | list  }}"
attribute: some_sensor_attribute
from: false
to: true

I believe I also attempted converting it to a comma-separated string to no avail.

Any suggestions?
As I said, Iā€™m a bit lost, apologies in advance, if this doesnā€™t make any sense at all.

Cheers

1 Like

Correct, because a State Triggerā€™s entity_id option doesnā€™t support templates.

If your next question is ā€œWhatā€™s the workaround?ā€ the short answer is ā€œNoneā€. Thereā€™s no trigger that monitors a dynamic list of entities for a specific state-change in one of their attributes.

Why?

Does the list of sensors grow and shrink on a daily basis?

Yup, potentially it does. These sensors are dynamically created based on some external data sources (web API).

Wouldā€˜ve been nice to keep things dynamic, but if thereā€˜s no way to do it, thanks for letting me know.

1 Like

Which integration is this?

Yup, for instance the 17track integration generates dynamic entites for ech package tracked, so the question is relevant.
Maybe the workaround is beyond a simple template within an automation, but there should be oneā€¦ maybe some automation that generates automationsā€¦? :thinking:

1 Like

Yep, there is no trigger like that, but there is a workaroundā€¦ Template Trigger:

You have to manually create your trigger (cannot click the rules in a nice GUI), but it works :slight_smile:

Other people said that for them it may.

But I will say: even if it doesnā€™t on a daily basis, Iā€™d still like to automate it. Thatā€™s what HA is for: home automation. Iā€™d like some stuff to be dynamic, so I donā€™t have to manually correct everything when something changes. In the long term, keeping manual lists is slow and error-prone. Not that these kind of errors are life and death (and Spook helps), but still :wink:

Iā€™m familiar with a Template Trigger.

Please post an example of one that meets the stated requirements.

1 Like

Iā€™ve created 3 Toggles via Helpers:

  • input_boolean.test_toggle_1
  • input_boolean.test_toggle_2
  • input_boolean.test_toggle_3

Iā€™ve also created a Number Helper: input_number.test_toggles_being_on_count

The automation catches all the test toggles and triggers when they change state.

  • If the count increases ā†’ we know one+ of the inputs changed its state to on
  • If the count decreases ā†’ we know one+ of the inputs changed its state to off

There is a catch thoughā€¦ The template trigger is only evaluated once a minute ā€“ so the automation has ā€œone minute lagā€. If you change the state few times quickly, it will not notice it.

Templates that do not contain an entity will be rendered once per minute.
~ Automation Trigger - Home Assistant

alias: test_toggles
description: ""
trigger:
  - platform: template
    value_template: |-
      {{ 
        states 
        | selectattr(
          'entity_id', 
          'match', 
          '^(input_boolean).test_toggle_*'
        ) 
        | selectattr('state', 'eq', 'on')
        | list
        | count
        
        != 
        
        states('input_number.test_toggles_being_on_count')
        | int(0)
      }}
condition: []
action:
  - service: notify.persistent_notification
    metadata: {}
    data:
      message: |-
        test_toggles_being_on_count changed from {{
          states('input_number.test_toggles_being_on_count')
          | int(0) 
        }} to {{ 
          states
          | selectattr(
            'entity_id', 
            'match', 
            '^(input_boolean).test_toggle_*'
          ) 
          | selectattr('state', 'eq', 'on')
          | list
          | count
        }}
  - service: input_number.set_value
    metadata: {}
    data:
      value: |-
        {{ 
          states 
          | selectattr(
            'entity_id', 
            'match', 
            '^(input_boolean).test_toggle_*'
          ) 
          | selectattr('state', 'eq', 'on') 
          | list 
          | count 
          | float(0.0) 
        }}
    target:
      entity_id: input_number.test_toggles_being_on_count
mode: single

Same setup as above, just a different trigger: with Time Pattern trigger, the check is done every second ā†’ so there is no one minute lag ā†’ the reaction is instant :slight_smile:

alias: test_toggles
description: ""
trigger:
  - platform: time_pattern
    seconds: "*"
condition:
  - condition: template
    value_template: |-
      {{ 
        states 
        | selectattr(
          'entity_id', 
          'match', 
          '^(input_boolean).test_toggle_*'
        ) 
        | selectattr('state', 'eq', 'on')
        | list
        | count
        
        != 
        
        states('input_number.test_toggles_being_on_count')
        | int(0)
      }}
action:
  - service: notify.persistent_notification
    metadata: {}
    data:
      message: |-
        test_toggles_being_on_count changed from {{
          states('input_number.test_toggles_being_on_count')
          | int(0) 
        }}  to  {{ 
          states
          | selectattr(
            'entity_id', 
            'match', 
            '^(input_boolean).test_toggle_*'
          ) 
          | selectattr('state', 'eq', 'on')
          | list
          | count
        }}
  - service: input_number.set_value
    metadata: {}
    data:
      value: |-
        {{ 
          states 
          | selectattr(
            'entity_id', 
            'match', 
            '^(input_boolean).test_toggle_*'
          ) 
          | selectattr('state', 'eq', 'on') 
          | list 
          | count 
          | float(0.0) 
        }}
    target:
      entity_id: input_number.test_toggles_being_on_count
mode: single

I have to admit that when you suggested that a Template Trigger could be used as a ā€œworkaroundā€, I assumed you had a clever template in mind that could somehow detect specific state-changes. However, the first example doesnā€™t do that and relies on a helper to report when the current count (of a given state value) has changed from its previous value.

What it doesnā€™t do is detect specific state-changes, for example off ā†’ on as opposed to unavailable ā†’ on and merely filters state values for a specific state (on). Because itā€™s not actually detecting state-changes, it cannot provide a State object containing details about the state-change (whether thatā€™s needed or not depends on the application).

Itā€™s being throttled due to the templateā€™s use of states. Refer to the following section of the Template integrationā€™s documentation: Rate Limiting Updates

Donā€™t get me wrong, depending on the application, it can be a useful workaround; you have demonstrated a way to use a Template Trigger, with a helper, to trigger when the state of one of multiple entities (whose entity_id matches a specific pattern thereby making it dynamic) is a desired value.

As for the second example, it doesnā€™t use Home Assistantā€™s resources efficiently. By making Home Assistant evaluate the template every second, it saddles it with a continuous workload merely for the convenience of supporting a dynamic list of entities.


As a side-note, if the entityā€™s domain is known in advance then it can be used in the template to reduce its complexity. However, itā€™s still likely to be subjected to rate limiting (because it employs states).

{{ states.input_boolean 
  | selectattr('object_id', 'match', 'test_toggle_')
  | selectattr('state', 'eq', 'on') | list | count }}
1 Like

If we assume there are only 2 states of input_boolean (on and off) ā†’ then we can detect every specific change in this domain (on ā†’ off and off ā†’ on).

But youā€™re right, I forgot about unavailable ā†’ therefore this example can ā€œonlyā€ detect off/unavailable ā†’ on and on ā†’ off/unavailable.

I have a ā€œbetterā€ workaround coming: using groups instead of counting :wink: I already have it working for my ā€œautomated group of windows that are open for too longā€ (so that I can display its members in Lovelace AND use the addition/removal of members to trigger automations) ā†’ but I need to ā€œgeneralizeā€ it to make a nice example.

With groups you actually can detect any kind of change ā†’ itā€™s just a case of the amount of groups and automations youā€™re willing to create.

Anyway, the point being: there are workarounds. Might not be pretty, but it is possible ;-)\

Jokingly: I couldnā€™t resist not responding to someone being wrong on the internetz :smiley:
With a bit of truth: Iā€™ve had it figured out the automated groups thingy, so eventually I want to share the solution somewhere.

Yep, Iā€™m aware of that, but personally I almost never care.

Iā€™m always using the rule: ā€œmake it work, make it right, make it fast (enough)ā€. So performance has the lowest priority for me (unless it becomes a problem).

The checklist here: ā€œit worksā€, itā€™s not ā€œrightā€ (I donā€™t like the copy-paste, need to figure out some ways to get rid of duplication, probably macros or sth), it does not have performance impact on my setup (therefore no need to optimize, unless optimizing would be just for fun or learning).

How do I know ā€œthere is no performance impactā€? First, it actually checks every second (I donā€™t see any delays). Second:

Screenshot 2024-03-13 at 03.36.40

Notice the big spike at 4 AM ā†’ thatā€™s when Proxmox host is making backups. I wrote the post at around 3:30, so must have been testing the solution before that. You see ā€œa littleā€ higher CPU usage? I canā€™t be sure, but I guess this is all the (probably unnecessary) restarts Iā€™ve done while testing. Thatā€™s ~3% ā€“ around the usual of my normal CPU usage. I bet I can make a 100 of such automations and there will still be no problem.

And Iā€™m on a cheap 20$ terminal with 2 cores, 2 gb of RAM, with Proxmox host, HA VM, OMV VM, MQTT LXC and Z2M LXC. If Iā€™m starting having performance problems, Iā€™ll probably invest 20 more dollars for better gear and keep being lazy with optimizations :stuck_out_tongue:


Anyway, all depends on the exact requirements of course :slight_smile:

I was looking through some PRs in Home Assistantā€™s GitHub Core repository and noticed several code improvements designed to eke out just a little bit more performance.

I thought if only they knew how some users use resources wastefully to the extent of rendering those little nips and tucks completely worthless.

As for groups, I had devised a method of using them for the purpose of a quasi-dynamic list of entities and the ability to report which group member is responsible for the state-change. However, I recognize itā€™s a workaround; if itā€™s a kludge or a resource hog, itā€™s not something I recommend to others.

1 Like

Iā€™m a web developer. Performance issue? Just add another layer of caching (and buy more ram for memcached) :smiley:


I find trying to microoptimize mostly waste of time; just solve the core issues; pareto rule, 80/20, etc. Code quality is much more important to me (hence Iā€™m dissatisfied with my copy-pasting automation parts). Weā€™re back to ā€œrequirementsā€ā€¦

Respectfully, thatā€™s evident from the two examples posted above. Nevertheless, I encourage you to continue being creative in your approach to solving problems. It can lead to novel techniques.

2 Likes
#template sensor
template:
  - sensor:
      - unique_id: 46ca24eb-f0b4-4a0a-8997-26f906c87573
        name: Sensor Count
        state: >
          {{
            states.sensor
              | selectattr('object_id', 'match', 'my_sensor_')
              | selectattr('attributes.some_sensor_attribute', 'defined')
              | selectattr('attributes.some_sensor_attribute')
              | list
              | count
          }}
        attributes:
          entity_id: >
            {{
              states.sensor
                | selectattr('object_id', 'match', 'my_sensor_')
                | selectattr('attributes.some_sensor_attribute', 'defined')
                | selectattr('attributes.some_sensor_attribute')
                | list
            }}
# AUTOMATION
id: 6a055fcb-eed2-40b8-8302-a7cf703acdc6
alias: Some automation
trigger:
  - platform: state
    entity_id: sensor.sensor_count
    to: null
condition:
  - condition: template
    value_template: >
      {% set from = trigger.from_state.state %}
      {% set to = trigger.to_state.state %}
      {{ from | is_number and to | is_number and to | int > from | int }}
action:
  - variables:
      entity_added: >
        {{
          trigger.to_state.attributes.entity_id
            | reject('in', trigger.from_state.attributes.entity_id)
            | list
            | first
        }}

Thatā€™s how I would do it. The template sensor is throttled to once every second because it uses states.sensor but thatā€™s similar as using the time pattern trigger.