- sensor:
- name: Unavailable Entities
unit_of_measurement: entities
icon: "{{ 'mdi:check-circle' if is_state('sensor.unavailable_entities','0') else 'mdi:alert-circle' }}"
state: >
{%-set unavs=states|selectattr('state','in',['unavailable','unknown','none'])|rejectattr('domain','eq','group')|rejectattr('entity_id','in',state_attr('group.ignored_entities','entity_id'))|map(attribute='entity_id')|list-%}
{%-set result = namespace(sensors=[])-%}
{%-for unav in unavs if (device_attr(unav,'identifiers')|first)[0] not in state_attr('input_select.ignored_integrations','options')-%}
{%-set ign=namespace(found=False)-%}
{%-for wildc in state_attr('input_select.ignored_entities_wildcards','options')-%}
{%-if wildc in unav-%}
{%-set ign.found=True-%}
{%-endif-%}
{%-endfor-%}
{%-if not ign.found-%}
{%-set result.sensors = result.sensors + [unav]-%}
{%-endif-%}
{%-endfor-%}
{{result.sensors|count}}
attributes:
entities: >
{%-set unavs=states|selectattr('state','in',['unavailable','unknown','none'])|rejectattr('domain','eq','group')|rejectattr('entity_id','in',state_attr('group.ignored_entities','entity_id'))|map(attribute='entity_id')|list-%}
{%-set result = namespace(sensors=[])-%}
{%-for unav in unavs if (device_attr(unav,'identifiers')|first)[0] not in state_attr('input_select.ignored_integrations','options')-%}
{%-set ign=namespace(found=False)-%}
{%-for wildc in state_attr('input_select.ignored_entities_wildcards','options')-%}
{%-if wildc in unav-%}
{%-set ign.found=True-%}
{%-endif-%}
{%-endfor-%}
{%-if not ign.found-%}
{%-set result.sensors = result.sensors + [unav]-%}
{%-endif-%}
{%-endfor-%}
{{result.sensors}}
It’s working and I’m kinda proud of the exclusion of entire integrations, but the coding seems coarse and cumbersome. And it has a complete repetition for the entitiesattribute, wasting CPU cycles and whatnot…
Is there a more elegant way to do this?
That’s nice!
I borrowed some stuff of this sensor (still wanted to have excluded integrations so I had to stick with mine). The code duplication is gone!
This is how it looks like now:
#template
- sensor:
- name: Unavailable Entities
unit_of_measurement: entities
icon: "{{iif(states(this.entity_id)|int(0)>0,'mdi:alert-circle','mdi:check-circle')}}"
state: >
{%set ents=state_attr(this.entity_id,'entities')-%}
{%if ents!=none-%} {{ents|count}} {%else-%} 0 {%endif-%}
attributes:
entities: >
{%set gracetime=60-%}{#seconds; to not trigger if just short blips occur-#}
{#group.ignored_entities can't be empty - at least sensor.unavailable_entities should be in it!-#}
{%set unavs=states|selectattr('state','in',['unavailable','unknown','none'])|rejectattr('domain','eq','group')|rejectattr('entity_id','in',state_attr('group.ignored_entities','entity_id'))|rejectattr('last_changed','ge',(now().timestamp()-gracetime)|as_datetime)|map(attribute='entity_id')|list-%}
{%set result=namespace(sensors=[])-%}
{%for unav in unavs-%}
{% set ign=namespace(found=False)-%}
{# "device_attr(unav,'identifiers')" is needed to filter out 'None' values which would make the next statement error out-#}
{% if device_attr(unav,'identifiers') and (device_attr(unav,'identifiers')|first)[0] in state_attr('input_select.ignored_integrations','options')-%}
{% set ign.found=True-%}
{% endif-%}
{% if not ign.found-%}
{% for wildc in state_attr('input_select.ignored_entities_wildcards','options')-%}
{% if wildc in unav-%}
{% set ign.found=True-%}
{% endif-%}
{% endfor-%}
{% endif-%}
{% if not ign.found-%}
{% set result.sensors=result.sensors+[unav]-%}
{% endif-%}
{%endfor-%}
{{result.sensors}}
Just for completeness (if someone scratches their head like I did) the involved group and helpers:
#input_select:
ignored_entities_wildcards:
name: Wildcards for entities that should not be checked upon
options:
- '_identify'
- '_lqi'
- '_rssi'
- '.pws_'
initial: '_lqi'
icon: mdi:alarm-light-off
ignored_integrations:
name: Integrations whose entities should not be checked upon
options:
- 'browser_mod'
- 'mobile_app'
initial: 'mobile_app'
icon: mdi:alarm-light-off
Are the two input_selects referenced anywhere else in your system or just by this one Template Sensor?
If it’s just for this sensor then it would be simpler to define the exclusions in a list within the template itself. The same goes for the group.
For the for-loop that determines if any of the entity_id’s contain one of the wildcard phrases, I believe you may be able to achieve that using search (and eliminate the for-loop). I’ll experiment with it and let you know if it’s possible.
That would be great! The inner for loop really looks like 90’s Basic programming (w/o the spaghetti part).
And yes, this group and the input_selects are only used within this sensor.
I used input_selects b/c I had hoped they would be edible via UI (like selectors of blueprints), but… nada. So I could as well hardcode them into the sensor (as an array?), that’s right.
What I’m on still is the possibility of including a group of sensors with shore leave whose temporary unavailability should go unnotified (like a mower in winter), but that would need selectors too and they are not available outside of their respective blueprint.