This is how I dealt with that issue. Basically all the devices I want to monitor are listed in a group and using a similar sensor template. Probably not the slickest way this can be done but it works for me.
Happy to hear input from anyone else!
#################################################################################
## Offline Devices
## state: number of offline devices
## attribute: entity_ids: - comma separated list of unavailable device entity id's
## - updates every minute (sensor.time)
## - device list is group.devices_connected
#################################################################################
sensor:
- platform: template
sensors:
offline_devices:
entity_id: sensor.time
friendly_name_template: >
{% if states('sensor.offline_devices') | int == 0 %}
All Devices Online
{% else %}
Device Offline
{% endif %}
icon_template: >
{% if states('sensor.offline_devices') | int == 0 %}
mdi:server-network
{% else %}
mdi:server-network-off
{% endif %}
value_template: >
{% set devices = state_attr('group.devices_connected', 'entity_id') %}
{% set dev = namespace(value=0) %}
{% for entity_id in devices -%}
{% if states(entity_id) == 'unknown' %}{% set dev.value = dev.value + 1 %}
{% elif states(entity_id) == 'unavailable' %}{% set dev.value = dev.value + 1 %}
{% endif %}
{%- endfor %}
{% if dev.value | int > 0 %}
{{ dev.value }}
{% else %}
None
{% endif %}
attribute_templates:
entity_ids: >
{%- set devices = state_attr('group.devices_connected', 'entity_id') -%}
{%- set dev = namespace(value=0) -%}
{%- for entity_id in devices -%}
{% if states(entity_id) == 'unknown' or states(entity_id) == 'unavailable' %}
{%- if not dev.value == 0 -%}{{- ',' -}}{%- endif -%}
{% set dev.value = dev.value + 1 %}
{{- entity_id -}}
{%- endif -%}
{%- endfor -%}
##################################################################################
## System - Devices Connected
## - used to display offline devices in alert
## - used for binary_sensor.offline_devices state
##################################################################################
group:
devices_connected:
control: hidden
entities:
# media players
- media_player.all_speakers
- media_player.broadcast_speakers
- media_player.music_speakers
- media_player.dining_room_speaker
- media_player.bedroom_display
- media_player.bathroom_speaker
- media_player.garage_speaker
- media_player.living_room_tv
- media_player.bedroom_tv
- media_player.deck_tv
# alarm
- alarm_control_panel.house
# lights
- light.living_room_pot_lights
# fans
- fan.upstairs_bedroom_fan
- fan.office_fan
- fan.upstairs_bathroom_fan
# covers
- cover.garage_door_opener
# climate
- binary_sensor.upstairs_thermostat_connected
# nest protects
- binary_sensor.upstairs_nest_protect_online
- binary_sensor.downstairs_nest_protect_online
# cameras
- camera.side_drive
- camera.side_door
- camera.front_drive
- camera.front_door
- camera.front_yard
- camera.side_gate_front
- camera.side_gate_back
- camera.back_yard
- camera.back_door
- camera.patio_door
- camera.back_house
- camera.garage_inside
- camera.nws_radar
etc. etc.
binary_sensor:
- platform: template
sensors:
device_offline:
friendly_name: Device Offline
device_class: problem
icon_template: mdi:server-network-off
value_template: "{{ states('sensor.offline_devices') | int > 0 }}"
alert:
device_offline:
name: "Device Offline"
title: "Device Offline"
entity_id: binary_sensor.device_offline
state: 'on'
repeat:
- 5
- 60
can_acknowledge: true
skip_first: true # to avoid triggering on restart
message: "- {{ state_attr('sensor.offline_devices','entity_ids').split(',') | join('\n- ') }}"
done_message: "All devices are now online."
data:
actions:
- action: pause_device_offline_alert
title: "Pause Alerts"
icon: !secret PAUSE_BUTTON
tag: device_offline
timestamp: "{{ as_timestamp(now()) }}"
renotify: true
ttl: 43200 # 12 hours
priority: high
requireInteraction: true
silent: false
url: /lovelace/system
icon: !secret OFFLINE_ICON
image: !secret OFFLINE_IMAGE
badge: !secret OFFLINE_BADGE
notifiers: jason