Jinja: if count 1 > do x

Hi everybody,

I am trying to create an automation that will alert for open windows at a specific trigger.

If only one window is open, I want something like “please close window in area”, but if multiple windows are open, I would like “the following windows are open; please close all of them: area and area and area”.

I have this so far:

{% set fenster = ['binary_sensor.unten_kueche_fenster_contact', 'binary_sensor.unten_bad_fenster_contact', 'binary_sensor.unten_wohnzimmer_fenster_contact' ] %}

{% for each in fenster %}
{% if is_state(each, "on") %}
{{ area_name(each) }}
{% endif %}
{% endfor %}

Currently, this displays Unten/Bad, because only that window is open. So I would like please close window in Bad/Unten. But if all windows were open, this would be Unten/Bad, Unten/Kueche, Unten/Wohnzimmer, so I would like the following windows are open; please close all of them: Unten/Bad, Unten/Kueche, Unten/Wohnzimmer.

Also, if no windows are open at all, I would like to switch the action all together. I would du this via automation condition, but I don’t know, what to put there. Same goes for differentiating between phrase 1 (only one open window) and phrase 2 (at least two open windows).

I guess I could do some search & replace on the area_name, as - in this case - all windows will be on the ground floor (“Unten”), so this information doesn’t have to be mentioned.

Thank you in advance for your ideas :slight_smile:

{% set fenster = ['binary_sensor.unten_kueche_fenster_contact', 'binary_sensor.unten_bad_fenster_contact', 'binary_sensor.unten_wohnzimmer_fenster_contact' ] %}
{% set open = fenster | select('is_state', 'on') | map('area_name') | list %}
{% if open | count == 1 %}
  Please close window in {{ open | first }}
{% elif open | count > 1 %}
  Please close windows in {{ open[:-1] | join(', ') }} and {{ open[-1] }}.
{% else %}
  No windows are open
{% endif %}
1 Like

This will build a string of “window x, window y, window z” for each open window.
After it is a template to check that the string isn’t empty, it will only proceed if at least one of the sensors was ‘on’

  - variables:
      open_windows: |-
        {% set fenster = ['binary_sensor.unten_kueche_fenster_contact', 'binary_sensor.unten_bad_fenster_contact', 'binary_sensor.unten_wohnzimmer_fenster_contact' ] %}
        {{
          states.binary_sensor
          |selectattr('entity_id','in',fenster)
          |selectattr('state','==','on')
          |map(attribute='name')
          |join(', ')
          |lower
        }}
  - condition: template
    value_template: "{{ open_windows|length > 0 }}"
1 Like

Thank you, but this only returns TypeError: object of type 'generator' has no len().

Using that over the provided list will throttle the template. You want to always avoid using the states object or the states.<domain> object when you can.

Secondly, OP wants area name, not entity name.

This is identical to your template, but with optimizations

        {% set fenster = ['binary_sensor.unten_kueche_fenster_contact', 'binary_sensor.unten_bad_fenster_contact', 'binary_sensor.unten_wohnzimmer_fenster_contact' ] %}
        {{
          fenster
          |select('is_state','on')
          |map('state_attr', 'friendly_name')
          |join(', ')
          |lower
        }}
1 Like

Updated

That produces TypeError: 'list' object is not callable

post what you’re pasting because we aren’t calling the list anywhere.

EDIT: Nevermind, typo, fixed

Yes! Thank you, this works perfectly.

1 Like