Jinja2 Expert Help Needed

I need help from any Jinja2 experts out there. Here is my situation…

I want to create a template sensor that list down all entities from a group that has state = open.

I have added a bunch of sensors into a group call entrypoints.

Then I created a template sensor with this value template…

{% for entity in states.group.entrypoints.attributes.entity_id %}
{%- if is_state(entity, 'open') %}
{{ entity }}
{%- endif %}
{%- endfor %}

When I run it, the sample result is…

sensor.front_door
sensor.living_room_window
sensor.back_door
sensor.kitchen_window
sensor.master_bedroom_window_a
sensor.master_bedroom_window_b
sensor.balcony_door

My question is, how do I make it list down the friendly name of each entities?

maybe {{ states.sensor.sensor_id.attributes.friendly_name }} ??

thanks but it is not correct.

Works for me in “Developer Tools” → “Templates”

1 Like

You mean like this?

{% for entity in states.group.entrypoints.attributes.entity_id %}
{%- if is_state(entity, 'close') %}
{{ states.sensor.sensor_id.attributes.friendly_name }}
{%- endif %}
{%- endfor %}

It gives me this error “Error rendering template: UndefinedError: ‘None’ has no attribute ‘attributes’

I wish I can do this…

{% for entity in states.group.entrypoints.attributes.entity_id %}
{%- if is_state(entity, 'open') %}
{{ getattr(entity, 'friendly_name') }}
{%- endif %}
{%- endfor %}

No, it was just example… replace sensor_id with your own sensor id.

Try

{{ states[entity.split('.')[0]][entity.split('.')[1]].name }}

name will be friendly_name if it is set, otherwise it is generated from the entity_id.

3 Likes

Thanks. It works!

@dale3h

How to split each entities with a comma and the last one with an “and”?

I tried…

{% for entity in states.group.entrypoints.attributes.entity_id %}
{%- if is_state(entity, 'open') %}
{%- if loop.last %} and {% else %}, {% endif -%}
{{ states[entity.split('.')[0]][entity.split('.')[1]].name }}
{%- endif %}
{%- endfor %}

It gives me…

, Front Door, Back Door, Kitchen Window, Master Bedroom Window A, Master Bedroom Window B and Balcony Door

I think the solution is to add each friendly name in {%- if is_state(entity, 'close') %} into an array first. But my understanding on Jinja is still very basic. Your help will be greatly appreciated. Thanks.

Does the following achieve what you’re after?

{% for entity in states.group.entrypoints.attributes.entity_id %}
{%- if is_state(entity, 'open') %}
{%- if loop.last %} and {% elif loop.first %}{% else %}, {% endif -%}
{{ states[entity.split('.')[0]][entity.split('.')[1]].name }}
{%- endif %}
{%- endfor %}

No. It doesn’t. It sometimes add comma before the entity or the ‘and’ doesn’t appear before the last item.

The problem is loop.last and loop.first are in reference to the entities regardless of its states.

Yes I get it now. Maybe append each open entity to a list first and then work with that list. I can’t test it at the moment (and I’m not really an expert - so I’m sure it could be done more elegantly) - but something like this should work:

{% set openentities = [] %}
{% for entity in states.group.entrypoints.attributes.entity_id %}
{%- if is_state(entity, 'open') %}
{% set x = openentities.append(states[entity.split('.')[0]][entity.split('.')[1]].name) %}
{%- endif %}
{%- endfor %}
{% for openentity in openentities %}
{%- if loop.last %} and {% elif loop.first %}{% else %}, {% endif -%}
{{ openentity }}
{%- endif %}
{%- endfor %}

thanks. but it gives this error…

Error rendering template: SecurityError: access to attribute ‘append’ of ‘list’ object is unsafe.

i think we are getting nearer.

Sorry - I don’t why that happens in Home Assistant. When I run this python code in IDLE:

from jinja2 import Template

Templatex = Template ('{% set openentities = [] %} ' \
                      '{% for entity in mydata %}' \
                      '{% if 1 == 1 %}' \
                      '{% set x = openentities.append(entity) %}' \
                      '{% endif %}' \
                      '{% endfor %}' \
                      '{% for openentity in openentities %}' \
                      '{%- if loop.last %} and {% elif loop.first %}{% else %}, {% endif -%}' \
                      '{{ openentity }}' \
                      '{%- endfor %}')

myinput = ["Front Door", "Back Door", "Kitchen Window", "Master Bedroom Window A", "Master Bedroom Window B", "Balcony Door"]
mystring = Templatex.render(mydata=myinput)

print mystring

I get:

Front Door, Back Door, Kitchen Window, Master Bedroom Window A, Master Bedroom Window B and Balcony Door

1 Like

It’s OK. Thanks for your help anyway.

If you want loop.last to work properly I believe you need to add a filter to your for loop.

Something like

{% for entity in states.group.entrypoints.attributes.entity_id if states(entity, 'open') %}
  {% if loop.last %}, and {% elif loop.first %}{% else %}, {% endif %}
  {{ states[entity.split('.')[0]][entity.split('.')[1]].name }}
{% endfor %}
2 Likes

Wow! Thanks. It works with this…

{% for entity in states.group.entrypoints.attributes.entity_id if is_state(entity, 'open') %}
{%- if loop.last %} and {% elif loop.first %}{% else %}, {% endif -%}
{{ states[entity.split('.')[0]][entity.split('.')[1]].name }}
{%- endfor %}

@nordlead2005

How to count the number of entities that has the state open?

I wish to have something like this…

If only one entity in the loop, it outputs something like… “Front Door is open”.

If more than one entity… “Front Door, Master Bedroom Window B and Balcony Door are open”

if there are 10 entities in the loop… “All doors and windows are open