Select('is_device_attr', 'manufacturer') using 'in' or 'search'

From this thread (which is old so am posting here) I wrote the following:

{% set select_models = [
  'Hue dimmer switch',
  'Hue motion sensor',
  'Hue motion outdoor sensor',
  'Heating thermostat remote control',
  'Soil sensor'
  ] %}
{{ states.sensor
  | selectattr('attributes.device_class', 'eq', 'battery')
  | map(attribute='entity_id')
  | select('is_device_attr', 'manufacturer', 'Philips')
  | list
  | join('\n')
}}

Is there any way I can relace:

| select('is_device_attr', 'manufacturer', 'Philips')`

With something like:

| select('is_device_attr', 'manufacturer', 'in' select_models)`

or even:

| select('is_device_attr', 'manufacturer', 'search', '(Hue|thermostat|Soil')`

(I know those lines won’t work, but is the easiest way for me to describe what I am looking for).

For context, I am trying to get a count of devices with low AA,AAA batteries as they can have a lower % than other batteries before needing to be replaced. So my endgame is something like this:

{% set select_models = [
  'Hue dimmer switch',
  'Hue motion sensor',
  'Hue motion outdoor sensor',
  'Heating thermostat remote control',
  'Soil sensor'
  ] %}
{% set entities = states.sensor
  | selectattr('attributes.device_class', 'eq', 'battery')
  | map(attribute='entity_id')
  | select('is_device_attr', 'manufacturer', 'Philips')
  | list
%}
{{ expand(entities)
  | map(attribute='state')
  | map('int', -1)
  | select('le', states('input_number.aa_battery_low')|round(20))
  | list
  | count
}}

I don’t think you can do it without looping.

{% set select_models = [
  'Hue dimmer switch',
  'Hue motion sensor',
  'Hue motion outdoor sensor',
  'Heating thermostat remote control',
  'Soil sensor'
  ] %}
{% set entities = states.sensor|selectattr('attributes.device_class','eq','battery')|map(attribute='entity_id') %}
{% set ns = namespace(list=[]) %}
{% for e in entities %}
  {% if device_attr(e,'model') in select_models %}
    {% if states(e)|int <= states('input_number.aa_battery_low')|int(0) %}
      {% set ns.list = ns.list + [e] %}
    {% endif %}
  {% endif %}
{% endfor %}
{{ ns.list|count }}
1 Like

Brilliant - will try that out - thanks!

what does the following line do?

  {% if d %}

edit: Did you just remove it?

if it’s a device. This is a pythonism.

if "value" #if statement passes because the string has characters
if "" # if statement fails because string is empty

That if statement is making sure the entity has a device.

1 Like

Yes, sorry. Found ways to optimise it further after posting.

Managed without looping:

{% set select_models = [
  'Hue dimmer switch',
  'Hue motion sensor',
  'Hue motion outdoor sensor',
  'Heating thermostat remote control',
  'Soil sensor'
  ] %}
{% set entities = states.sensor
                  |selectattr('attributes.device_class','eq','battery')
                  |map(attribute='entity_id')|list %}
{% set models = entities|map('device_attr','model') %}
{{ zip(entities,models)
     |selectattr(1)
     |selectattr(1,'in',select_models)
     |map(attribute=0)
     |map('states')
     |map('int')
     |select('le',states('input_number.aa_battery_low')|int(0))
     |list
     |count }}
2 Likes

thanks for explaining!

…I have some research to do!

zip is explained here:

It creates a list of (entity, model) pairs. “Attribute 0” is the entity; “attribute 1” is the model.

{{ zip(entities,models)
     |selectattr(1)                      # filters out pairs with no model
     |selectattr(1,'in',select_models)   # filters to your model list
     |map(attribute=0)                   # extracts entities
     |map('states')                      # get their states
     |map('int')                         # convert to number
     |select('le',                       # test against threshold
              states('input_number.aa_battery_low')|int(0))
     |list
     |count }}
1 Like

The zip() function can be used to iterate over multiple collections in one operation.

nice!