Template sensor filtering by matching one of multiple attributes

Hello,

I’m trying to refine an existing template binary sensor I have. I am using the hass-amplifi custom integration which returns a list of all devices connected to WiFi. From this, I am trying to create a binary sensor which is enabled when any device is connected to the Guest SSID (which feeds into a “guest mode” sensor. These devices can be identified because their IP address begins with 192.168 instead of 172.20.

Here is the current template:

{{ states.device_tracker 
| selectattr('entity_id', 'match', 'device_tracker.amplifi.*') 
| selectattr('entity_id','match','device_tracker.amplifi_192_168_*')
| selectattr('state', 'eq', 'home') 
| list 
| count
 }}

Because of how the integration names entities, sometimes the entity ID contains the IP address, sometimes it contains the MAC address. What I would like to do is find all entities where EITHER 1) “192_168” is within the entity ID or 2) the attribute “ip” contains 192.168. I was able to do the latter with this:

{{ states.device_tracker 
| selectattr('entity_id', 'match', 'device_tracker.amplifi.*') 
| rejectattr('attributes.ip','undefined')
| selectattr('attributes.ip','match','192.168.*')
| selectattr('state', 'eq', 'home') 
| list 
| count
 }}

What I can’t figure out is how I combine these two templates so that it matches either the entity ID or the IP attribute. I found this thread which uses the search function instead of match, but I don’t think this works in my case as I’m trying to filter by either one of two attributes.

I have tried the below but this does not work:

{{ states.device_tracker 
| selectattr('entity_id', 'match', 'device_tracker.amplifi.*') 
| selectattr('attributes.ip','match','192.168.*') or selectattr('entity_id','match','device_tracker.amplifi_192_168_*')
| selectattr('state', 'eq', 'home') 
| list 
| count
 }}

This returns <generator object select_or_reject at 0x7f9f808fcdc0> which is not what I’m looking for haha. I’m assuming this is because selectattr is more like a filter than a condition.

I have considered changing this whole thing to a bunch of IF statements and potentially loops, but this solution seems so clean (and presumably is less CPU intensive) than that so I was trying to avoid it. If that is the only solution, so be it, but I thought it was worth asking here in case there was an easier way to achieve what I’m trying to do.

Thank you.

After playing around for the last hour or so, I’ve come up with this

{% set amplifi_devices = states.device_tracker 
| selectattr('entity_id', 'match', 'device_tracker.amplifi.*')
| selectattr('state', 'eq', 'home')
| list
 %}

 {% for device in amplifi_devices %}
   {% if device.attributes.ip == null %}
     {% if ('device_tracker.amplifi_192_168_' in device.entity_id) %}
       {{ true }}
     {% endif %}
   {% elif ('192.168.' in device.attributes.ip) %}
     {{ true }}
   {% endif %}
 {% endfor %}

While this appears to work in the template tab in Developer Tools and returns True albeit with lots of blank lines, when copied into the sensor template, the sensor remains off.

There must be a cleaner and lighter way to do this other than using For loops. Any pointers in the right direction would be massively helpful. Thanks

OK so immediately after posting my previous response, I looked again at the original body and thought, “why don’t I just stack these together and check both separately and combine them?”

So anyway, pasting this into the sensor does work correctly:

{% set total = states.device_tracker 
| selectattr('entity_id','match','device_tracker.amplifi_192_168_*')
| selectattr('state', 'eq', 'home') 
| list 
| count
 %}

{% set total = total + states.device_tracker 
| selectattr('entity_id', 'match', 'device_tracker.amplifi.*') 
| rejectattr('attributes.ip','undefined')
| selectattr('attributes.ip','match','192.168.*')
| selectattr('state', 'eq', 'home') 
| list 
| count
 %}

 {{ total }}

Getting the entire device_tracker domain twice is probably not great for performance and I suppose I could avoid this by setting the contents of the domain to a variable and running the filters against that instead, but this is OK for now. If anyone has any further improvements they can make to refine the code and improve performance, I’d be very grateful.

Hopefully this helps someone else if not. Cheers

EDIT: First entity_id filter was redundant, filtering by hostname only needs one filter