How to select lowest and highest temperature from a group of entity?

Hi everyone,
i have a template sensor that returns me the entity name of the heatpump in the room with the lowest/higher room.
At the moment it is defined like this:

###########################
# PROSSIMA PDC DA AVVIARE #
########################### 
- sensor:
      - unique_id: pdc_da_avviare
        name: 'Prossima PDC da avviare'
        state: >
            {%- set d = [
            {'unit': 'climate.daikin_soggiorno',
            'state': states('climate.daikin_soggiorno'),
            'temp': states('sensor.temperatura_pt') | float(100)},
            {'unit':'climate.daikin_camera_matrimoniale',
            'state': states('climate.daikin_camera_matrimoniale'),
            'temp': states('sensor.temperatura_camera') | float(100)},
            {'unit':'climate.daikin_camera_christian',
            'state': states('climate.daikin_camera_christian'),
            'temp': states('sensor.temperatura_camera_christian')|float(100)},
            {'unit':'climate.daikin_camera_micol',
            'state': states('climate.daikin_camera_micol'),
            'temp': states('sensor.temperatura_camera_micol')|float(100)},
            {'unit':'climate.daikin_camera_thomas',
            'state': states('climate.daikin_camera_thomas'),
            'temp': states('sensor.temperatura_camera_thomas')|float(100)}
            ] %}
            
            {{ (d | selectattr('state', 'eq', 'off') | sort(attribute = 'temp') | first)['unit'] }}

I would like to do the same thing but from a group ( group.condizionatori ) dynamically containing them, rather than having to manually specify them.
How can i do that?
Thanks

I’ve never tried to template the entities on a Min/Max but have you tried that yet and make the type “mean”?

You could do it more easily if you had a more consistent naming scheme. One way to do it would be to use Areas:

{% set ex_group = expand('group.condizionatori') %}
{% set min = ex_group | map(attribute='state') | map('float', 100) | min | string %}
{% set min_area = area_id( ex_group | selectattr('state', 'eq', min) | map(attribute='entity_id') | first) %}
{{ area_entities(min_area) | select('search', 'climate\.') | first }}
1 Like

The fact is that i do not need the lowest/highest temperature but the name of the heatpump associated to that room, so a min/max sensor would not give me that info

I tried with your code but i get No first item, sequence was empty.
As for the naming scheme i did not really understand the hint, could you explain me better?

Make sure all your sensors and climate entities have an assigned Area and that they match for each sensor-climate pairing.

Three of the pairs in your example have well matched names. For example,
“climate.daikin_camera_christian” and “sensor.temperatura_camera_christian”. This makes it easier to template because we can use string manipulation instead of having to go through an Area matching process.

If you fix the entity ID’s for the master bedroom and living room temperature sensors so that they following the same pattern as the other three, you could use the following:

template:
  - sensor:
      - unique_id: pdc_da_avviare
        name: 'Prossima PDC da avviare'
        state: >
          {% set t_min = expand('group.condizionatori') 
          | map(attribute='state') | map('float', 100) | min | string %}
          {{ state_attr('group.condizionatori', 'entity_id')
          | select('is_state', t_min) | first | replace('sensor.temperatura', 'climate.daikin') }}
        availability: >
          {% set t_min = expand('group.condizionatori') | map(attribute='state') | map('float', 100) | min | string %}
          {{ (state_attr('group.condizionatori', 'entity_id') | select('is_state', t_min) | first) is defined }}

That data point is actually supplied as an attribute (min_entity_id or max_entity_id) when using the “Combine the state of several sensors” helper (formerly known as Min/Max).

EDIT: Added availability template

1 Like

Okay, after some workarounds i managed to do in a similar way to your proposal… the only issue is that if i have a single element in group.condizionatori, t_min is not set.
Using developer tools i get No first item, sequence was empty. as before

You’ll have to share your work-arounds… I cannot reproduce that issue with the template I supplied.

1 Like

I created a template sensor retrieving me the sensor with the lowest temperature from a group containing all the temperature sensors (in a dynamic group).
Here’s the code:

- sensor:
    - unique_id: stanza_piu_fredda
      name: Stanza piĂą fredda
      state: >
        {% set t_min = expand('group.sensori_temperatura') 
        | map(attribute='state') | map('float', 100) | min | string %}
        {{ state_attr('group.sensori_temperatura', 'entity_id')
        | select('is_state', t_min) | first }}

but if group.sensori_temperatura has a single entity, i get that error

That seems problematic … what happens if … between this:

{% set t_min = expand('group.sensori_temperatura') 
        | map(attribute='state') | map('float', 100) | min | string %}

And this:

{{ state_attr('group.sensori_temperatura', 'entity_id')
        | select('is_state', t_min) | first }}

The temp changes? Or worse, two have the same value and your “first” is not the “first” you thought it was.

I cannot test, too hard without same equipment … but I would create a list of sensors with your t_min and take the first one, and not a list of values and then look it up again.

1 Like

@patosette This might be the cause of the problem with single-entity groups.
Try setting the value of expand('group.sensori_temperatura') to a variable at the start to act as a static source of truth.

{% set source = expand('group.sensori_temperatura') %}
{% set t_min =  source | map(attribute='state') | map('float', 100) | min | string %}
{{ source | selectattr('state','eq', t_min) | map(attribute='entity_id') | list | first }}

More sorting criteria could be added to the final expression, but that was not in OP’s brief.

2 Likes

Yes.

More sorting criteria could be added to the final expression, but that was not in OP’s brief.

But I was not thinking of it entering in with identical temps, I was thinking like it could have only one meet the criteria and then two could (on the delay). Your solution is the correct one, make a list of all the sensors and then act on them without “re-looking” up values.

1 Like

After letting a sensor based on a group with a single entity run for a while it did produce very unstable results… where a sensor using the same template, but based on a group with more than one entity produced a stable output.

I also tested using the “Combine the state of several sensors” helper (a.k.a. Min/Max) with a Template sensor that tracks the min_entity_id attribute. This method returned stable results both in groups with a single entity and multiple entities.

To use that that approach with your template sensor would be as follows:

template:
  - sensor:
      - unique_id: pdc_da_avviare
        name: 'Prossima PDC da avviare'
        state: >
          {{ state_attr('sensor.MIN_MAX_EXAMPLE', 'min_entity_id') | first | replace('sensor.temperatura', 'climate.daikin') }}

EDIT:

After allowing these to run overnight, the multi-entity template also showed an unstable output.

1 Like

The only issue about your solution is that i’m using this sensor to decide which heatpump to start from a group with the heatpumps i want to start.
Using a min/max sensor i have to set a static number of entities to track, so i could have as a result a min_entity_id outside from the rooms i’m interested in, so i’d need to shift to the second lowest, or third etc…
The solution i’m now using (a dynamic group, containing only the temperature sensors i’m interested to) seems to be easier to work with, a part from the case where i want to automatize a single heatpump (or n-1 heatpumps have already turned on) and so the group has a single entity.

Nice point, i did not think about that… you have also to consider that i use this to start my house’s heatpumps, so it’s not a real matter if i start before the room with 17.81°C or the one with 17.9°C, i’m more interested in starting the one at <18°C rather than the one at >19°C, but i’ll take the hint and i’ll try to work on it as soon as the system is working as i would like, it will be a fine tuning. Thanks!

Two final options… since these are indoor, metric temperatures and unlikely to span below 10 or above 99, you can probably get away with just sorting the states as strings instead of the two-step process to get an actual numeric minimum.

template:
  - sensor:
      - unique_id: pdc_da_avviare
        name: 'Prossima PDC da avviare'
        state: >
          {{ expand(state_attr('group.sensori_temperatura','entity_id')
          | select('has_value')) | sort(attribute='state') 
          | map(attribute='entity_id') | first | replace('sensor.temperatura', 'climate.daikin') }}

For the highest value you would need to reverse the sort as follows:

| sort(attribute='state', reverse=true)

Or you could use a namespace and for loop:

{% set ns = namespace(items=[]) %}
{% for e in state_attr('group.sensori_temperatura','entity_id') | select('has_value') %}
   {% set ns.items = ns.items + [{'ent': e, 'state': states(e) | float(None)}] %}
{% endfor %}
{{ ns.items | rejectattr('state', 'none') | sort(attribute='state') | map(attribute='ent') | first 
| replace('sensor.temperatura', 'climate.daikin') }}
1 Like

This seems to work amazingly well! Thanks for your patience!

1 Like