How to get device_class = window sensors in a template expression?

Hi - I am having some success with using template expressions to evaluate the number of people home and the number of lights on, eg:

{{ states.light | map(attribute='state') | select('eq', 'on') | list | length }}

However, this only works because all devices in the light domain are lights. What if I need a subset of a domain? I don’t seem to be able to figure out how to narrow the dataset to just those with device_class=window. I tried a bit of debugging:

{% for sensor in states.binary_sensor %}
  {{ sensor }}
  {{ sensor.entity_id }}
  {{ sensor.state }}
  {{ sensor.device_class }}
  {% if sensor.device_class == 'window' %}
    {{ sensor }} is a window
  {% endif %}
{% endfor %}

But I get output such as:

<template state binary_sensor.samsung_c522_contact=off; friendly_name=Terrace door, icon=mdi:window-closed, device_class=window @ 2020-06-29T13:07:24.299605+01:00>
  binary_sensor.samsung_c522_contact
  off

That is, sensor.entity_id is queryable, as is sensor.state, but sensor.device_class appears to be always empty. Any ideas?

You can use the attribute in order to get the device class.

{% for sensor in states.binary_sensor %}
  {% if sensor.attributes.device_class == 'window' %}
    {{ sensor.attributes.friendly_name }} is a window
  {% endif %}
{% endfor %}
2 Likes

Aha! Thank you.

The way the <template> output is formatted seems very confusing in that regard :-/

So ultimately my goal here was to count the number of windows open. This monstrosity is the best I could do:

{%
set windows %}{% 
  for sensor in states.binary_sensor %}{% 
    if sensor.attributes.device_class == 'window' and sensor.state == 'on'
      %}X{% 
    endif %}{% 
  endfor %}{% 
endset %}{{ 

windows | length }}

I actually put it all on one line in the config, but spread it out here to make it easier to read - though I can’t put any space outside of template tags because it would increase the length of the variable!

Paste this into the Template Editor and experiment with it:

{{ states.binary_sensor 
   | selectattr('attributes.device_class', 'eq', 'window')
   | selectattr('state', 'eq', 'on')
   | list | length }}

It can, of course, all be contained on one line but I’ve broken it up to improve legibility.

1 Like

Superb. I was trying selectattr but I think I didn’t quote the key.

1 Like

does not work anymore:

UndefinedError: ‘homeassistant.util.read_only_dict.ReadOnlyDict object’ has no attribute ‘device_class’

you have to add : | selectattr('attributes.device_class', 'defined')

{{ states.binary_sensor
   | selectattr('attributes.device_class', 'defined')
   | selectattr('attributes.device_class', 'eq', 'window')
   | selectattr('state', 'eq', 'on')
   | list | length }}
5 Likes

Thanks for the update but you’re responding to a post made over two years ago. At the time, it wasn’t necessary to ensure device_class was defined.

In terms of Home Assistant’s evolution, two years is an eternity and the vast majority of old examples in this forum are likely to be outdated or superseded by new methods.

You’re right. That is why I made an update. Because some people (including me) may have the same question today and need a working solution.

4 Likes

I would recommend to people who need a working solution that they be wary of using any two year old solution. For this particular example it’s a simple fix but for others it may require a completely different approach (due either to deprecation of an old method or the availability of a new and better method).

Thanks @TNT_Larsn that’s a useful bit of info. I still use this technique today.