Script repeat for_each against all climate entities (TRVs)

I’m trying to write a script to handle automation for my TRVs, so I want to iterate through a for_each loop on each one and check for specific attributes and act on that.
How would I form the for_each loop as I don’t want to hard-code the entities into the script.

I currently have:

mode: single
icon: mdi:heating-coil
alias: radiator-autoboost
sequence:
  - repeat:
      for_each: 
        - "test"

I believe where - “test” is I need to create a dynamic entry towards climate. entities.
Then in the sequence I need to then ask climate.pi_heating_demand and check the value.
How would I carry this out?

psuedo-code:
Loop through all climate entities in my HA
For each entry query the climate.pi_heating_demand and if is a specific numeric/float then carry out an action

Loop through all climate entities is easily done but what is climate.pi_heating_demand? That’s the entity_id of one specific climate entity. What is its relation to all other climate entities?

Or do you mean that each one of your climate entities has an attribute named pi_heating_demand?

Apologies, bit confusing!
Yes I want to loop through all climate entities, so that’s the first ask on how the “for_each” would look.

All of my climate entities all have pi_heating_demand which is what inside the loop I will be checking the value of

So I would be checking in this case climate.bedroom_radiator_thermostat pi_heating_demand is equal to 7 then (do another action)

Copy-paste the following template into the Template Editor and confirm it lists the entity_id of all climate entities whose pi_heating_demand is greater than or equal to 7.

{{ states.climate
  | selectattr('attributes.pi_heating_demand', '>=', 7)
  | map(attribute='entity_id') | list }}

If it works then you can adjust the test to meet your requirements, using whatever operator is appropriate: ==, >, >=, <, <=, !=

Then you can use it in the repeat for_each

mode: single
icon: mdi:heating-coil
alias: radiator-autoboost
sequence:
  - repeat:
      for_each: "{{ states.climate | selectattr('attributes.pi_heating_demand', '>=', 7) | map(attribute='entity_id') | list }}"
      sequence:
        ... etc ...

Ahh, I see, that makes sense. Unfortunately it looks like the data from climate isn’t playing:

{{ states.climate
  | selectattr('attributes.pi_heating_demand', '>=', 7)
  | map(attribute='entity_id') | list }}

Results in:

UndefinedError: 'homeassistant.util.read_only_dict.ReadOnlyDict object' has no attribute 'pi_heating_demand'

That likely means you have at least one climate entity that doesn’t have that attribute, you can add a selection clause to limit the rest of the template to just those that do:

{{ states.climate
  | selectattr('attributes.pi_heating_demand', 'defined')
  | selectattr('attributes.pi_heating_demand', '>=', 7)
  | map(attribute='entity_id') | list }}

Ahh! I didn’t realise one of my TRVs was a different manufacturer! Yes that’s exactly why.
Yes that modification works as expected and I get a list returned:

[
  "climate.bedroom_radiator_thermostat",
  "climate.living_room_radiator_thermostat",
  "climate.leahs_radiator_thermostat"
]

So that can be used in the script loop component? Like this:

mode: single
icon: mdi:heating-coil
alias: radiator-autoboost
sequence:
  - repeat:
      for_each: "{{ states.climate | selectattr('attributes.pi_heating_demand', 'defined') | selectattr('attributes.pi_heating_demand', '>=', 7) | map(attribute='entity_id') | list }}"

How would I then refer to the current iteration in an if statement to determine if the selected state attribute is a set value?
Thanks!

Yes. The for_each key will accept templates that return simple values, lists, or mappings/dictionaries.

The template already selects for the pi_heating_demand attribute’s value in selectattr('attributes.pi_heating_demand', '>=', 7)… if you wanted to check other attribute values of the entity you could add them to the template or use template conditions:

mode: single
icon: mdi:heating-coil
alias: radiator-autoboost
sequence:
  - repeat:
      for_each: |
        {{ states.climate | selectattr('attributes.pi_heating_demand', 'defined') 
        | selectattr('attributes.pi_heating_demand', '>=', 7) 
        | map(attribute='entity_id') | list }}
      sequence:
        - condition: template
          value_template: "{{ is_state_attr(repeat.item, 'example_attribute', 'Affirmative Value') }}" 
        - service: climate.set_temperature
          target:
            entity_id: "{{ repeat.item }}"
          data:
            temperature: 24
            hvac_mode: heat

Easily fixed. Just need to filter out climate entities lacking the attribute. Didgeridrew has already shown how to do that.

Use repeat.item as demonstrated in the documentation for repeat.


NOTE

For future reference, if you click this Reply button, I receive a notification that you replied to me.

I do not receive a notification if you click this Reply button.

Anyways, by now you probably realize that there’s no need for a Jinja for-loop, like you originally requested, and all that’s needed is a simple template to extract a list of climate entities that meet your requirements.

For that matter, what are the exact requirements for the value of pi_heating_demand?

Thank you both, after replying i’d figured a solution that does pretty much what I want. (Thanks @123 for the info on the reply buttons, interesting and odd behaviour that! I’ve done a global reply since replying to both of you this time)

Here is the code I’ve gone for:

mode: single
icon: mdi:heating-coil
alias: radiator-autoboost
sequence:
  - repeat:
      for_each: >-
        {{ states.climate | selectattr('attributes.pi_heating_demand',
        'defined') | selectattr('attributes.pi_heating_demand', '>=', 7) |
        map(attribute='entity_id') | list }}
      sequence:
        - service: logbook.log
          data:
            name: radiator-valuecheck
            message: "{{ repeat.item }}"
        - service: input_boolean.turn_on
          target:
            entity_id: input_boolean.radiator_autoboost
          data: {}

(I’m creating this as a script that I’ll call as required, it will be used to request more heat from my boiler should a TRV be requiring heat)
The pi_heating_demand comes from Danfoss TRVs via ZHA and when pi_heating_demand is set to a non-zero value then the TRV is requesting heat (There is an issue with the climate entity heat demand so I’m using this method)

If you mean the button shown in the following screenshot then that’s the one that does not send me a notification.

FWIW, I would have to subscribe to this topic in order to receive a notification for anything posted to it. I respond to hundreds of topics and if I were to subscribe to all of them I would be overwhelmed with notifications.

Does the value have to be greater than or equal to 7 or simply greater than 0?

The example I had provided used >= 7 only because that’s the value I saw in the screenshot you posted here. That’s why I had asked what was the exact requirement because my choice of using 7 as the threshold was merely for testing purposes. If it only needs to be greater than 0 then change the test to this:

selectattr('attributes.pi_heating_demand', '>', 0)