Blueprint: Notify when Zigbee/Zwave/any battery device has gone offline

2024-02-21 UPDATE

I consider this blueprint deprecated, please click here for an updated and improved version

the below information is retained for historical purposes only

Explanation
This blueprint will alert you when any of your Zigbee or Zwave battery powered devices have fallen off the network, aka gone “Unavailable”.

It is not necessary to specify a list of devices to check, as this template draws heavily from the excellent work of Sbyx, who came up with the idea of scanning all devices which have a class of “battery”.

What defines a device as “unavailable”? This is somewhat subjective with battery powered Zigbee devices - and differs depending on the manufacturer. If you haven’t heard from your Cousin Vinney in 3 weeks, that doesn’t mean he’s dead - it might just mean he has nothing to say…

Similarly, to preserve battery, many devices only report in very infrequently - But they should report immediately in case of an Event - such as a water leak, or a door closing.

If you are running ZHA (the default HA Zigbee Integration), you can customise what you consider to be “unavailable” in your HA settings. Go to Settings->Devices->Zigbee(ZHA), and click “Configure”. You should see a setting “consider battery powered devices unavailable after (seconds)”. Personally, I set mine to 10800s (3 hours).

If you are running DeConz or Z2M, the process for setting the timeout will be different, and out of the scope of this help document.

This blueprint will scan your network at a time of day of your choosing, and notify you of any devices that are Unavailable at that time.

Usage

Click this badge to install the blueprint:
Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

You can specify sensors to exclude from the scan - be aware that selecting a device doesn’t work, you must expand and choose the specific sensor Entities you wish to exclude.

You can choose any actions to be run if sensor(s) are offline, for example speaking a list via TTS, or sending a message to your phone. The following example shows how to provide a list of the offline sensors:

message: ‘The following devices are unavailable {{sensors}}’

Note: if you use Telegram, then change {{ sensors }} to the following:

{{sensors|replace("_"," ")}}

Limitations & Notes

  • This blueprint does not check mains-powered devices, such as smart plugs. In practice, I rarely find these devices go offline.

  • This blueprint only checks your network once a day, so it’s possible your device may have been offline for a day, before you receive a notification.

  • This is my first ever blueprint, let me know if there are issues.

  • This works with the default HA Zigbee/ZWave integrations, but has not yet been tested with Zigbee2MQTT - would appreciate if someone can test and send feedback

  • Shoutout to @Sbyx

Changelog

  • 2022-02-19 First version created

Blueprint raw Yaml

blueprint:
  name: Zigbee/ZWave battery device has gone offline
  description: Report when a Zigbee or ZWave, or any battery device has gone offline
  #based on the work of Sybx @ https://community.home-assistant.io/t/low-battery-level-detection-notification-for-all-battery-sensors/258664
  domain: automation
  input:
    time:
      name: Time to test on
      description: Test is run at configured time
      default: '10:00:00'
      selector:
        time: {}
    day:
      name: Weekday to test on
      description: 'Test is run at configured time either everyday (0) or on a given
        weekday (1: Monday ... 7: Sunday)'
      default: 0
      selector:
        number:
          min: 0.0
          max: 7.0
          mode: slider
          step: 1.0
    exclude:
      name: Excluded Sensors
      description: Battery sensors (e.g. smartphone) to exclude from detection. Only entities are supported, devices must be expanded!
      default: {entity_id: []}
      selector:
        target:
          entity:
            device_class: battery
    actions:
      name: Actions
      description: Notifications or similar to be run. {{sensors}} is replaced with
        the names of sensors being low on battery.
      selector:
        action: {}
  source_url: https://gist.github.com/Tahutipai/971bf0e07e50ce6190e0dacd73262e2e
variables:
  day: !input 'day'
  exclude: !input 'exclude'
  sensors: >-
    {% set result = namespace(sensors=[]) %}
    {% for state in states.sensor | selectattr('attributes.device_class', 'defined') | selectattr('attributes.device_class', '==', 'battery') %}
      {% if "unavailable" in state | string  and not state.entity_id in exclude.entity_id %}
        {% set result.sensors = result.sensors + [state.name] %}
      {% endif %}
    {% endfor %}
    {% for state in states.binary_sensor | selectattr('attributes.device_class', 'defined') | selectattr('attributes.device_class', '==', 'battery') %}
      {% if "unavailable" in state | string and not state.entity_id in exclude.entity_id %}
        {% set result.sensors = result.sensors + [state.name] %}
      {% endif %}
    {% endfor %}
    {{result.sensors|join(', ')}}
trigger:
- platform: time
  at: !input 'time'
condition:
- '{{ sensors != '''' and (day | int == 0 or day | int == now().isoweekday()) }}'
action:
- choose: []
  default: !input 'actions'
mode: single

EDIT: Already getting feedback that people would prefer to be notified of mains-powered zigbee devices being offline as well. Which makes sense. I can’t find anyway in ZHA to get a list of all Zigbee devices. I guess one could just grab all entities that are “unavailable”, but that seems a little far reaching, albeit useful. I’m guessing most people just want to monitor their SmartSwitches? This is an assumption - so someone please tell me if its wrong
So I’ve added a test version of a blueprint that gets all battery devices, and ALL types of switches. This feels a little unclean designwise, but perhaps will work well in practice? I struggle to think of types of switches, other than physical SmartSwitches, that can go “unavailable”? If someone wishes to try that new blueprint, I would appreciate any feedback. Click below to install it:
Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

14 Likes

Thanks’ for sharing :slight_smile:

I also use @Styx blueprint for battery devices, and after excluding a few pesky devices, it worked a treat. However after adding your blueprint I get the following:

While the idea is sound, the information it’s providing back isn’t very helpful. I have no idea what each of the 10 or so “battery” devices are that might be offline given that no further information is provided.

I’l be removing this from my HA for now, but will be circling back to see if you get this resolved.

Thank you for sharing, appreciate the feedback.

The selection code is essentially the same as @Styx’s blueprint, as I borrowed very heavily from that, so there shouldn’t be any fundamental difference - except I have selected a different set of entities.

Thus, the most likely explanation I can see for this is: you have a number of entities on your system called “Battery” that are currently “unavailable”. The reason Styx’s blueprint would not show these devices, is that blue print only reports devices that are alive and on the network, and reporting a battery level lower than the threshold set by the user - as your entities are “unavailable”, they are therefor not reporting any battery level percentage.

i.e it sounds like you have a bunch of unavailable entities. perhaps they are from a previous integration you no longer use? Or old deleted devices from ZHA or something like that perhaps?

So, I made some debug code that provides more detail to might help us diagnose this, can you please post the following in to the Template section under Developer Tools, and post the results back here?

   {% set result = namespace(sensors=[]) %}
    {% for state in states.sensor | selectattr('attributes.device_class', 'defined') | selectattr('attributes.device_class', '==', 'battery') %}
      {% if "unavailable" in state | string  %}
        {% set result.sensors = result.sensors + [state] %}
      {% endif %}
    {% endfor %}
    Unavailable Sensors: 
    {{result.sensors|join('\n')}}
    {% set result = namespace(sensors=[]) %}
    {% for state in states.binary_sensor | selectattr('attributes.device_class', 'defined') | selectattr('attributes.device_class', '==', 'battery') %}
      {% if "unavailable" in state | string %}
        {% set result.sensors = result.sensors + [state] %}
      {% endif %}
    {% endfor %}
    Unavailable binary sensors: 
    {{result.sensors|join('\n')}}
Unavailable Sensors: 
    <template TemplateState(<state sensor.african_violet_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.625224-05:00>)>
<template TemplateState(<state sensor.areca_palm_desk_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.624655-05:00>)>
<template TemplateState(<state sensor.areca_palm_window_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.623744-05:00>)>
<template TemplateState(<state sensor.cactus_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.624312-05:00>)>
<template TemplateState(<state sensor.govee_14241_water_sensor_battery_level=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Govee-14241 battery level, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.626411-05:00>)>
<template TemplateState(<state sensor.govee_14275_water_sensor_battery_level=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Govee-14275 battery level, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.626756-05:00>)>
<template TemplateState(<state sensor.govee_50227_water_sensor_battery_level=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Govee-50227 battery level, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.627110-05:00>)>
<template TemplateState(<state sensor.govee_50303_water_sensor_battery_level=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Govee-50303 battery level, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.627450-05:00>)>
<template TemplateState(<state sensor.jade_plant_floor_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.625403-05:00>)>
<template TemplateState(<state sensor.jade_plant_lower_shelf_left_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.637095-05:00>)>
<template TemplateState(<state sensor.jade_plant_lower_shelf_right_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.625744-05:00>)>
<template TemplateState(<state sensor.jade_plant_top_shelf_left_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.625047-05:00>)>
<template TemplateState(<state sensor.jade_plant_top_shelf_right_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.624486-05:00>)>
<template TemplateState(<state sensor.jade_plant_window_left_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.624127-05:00>)>
<template TemplateState(<state sensor.jade_plant_window_right_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.625574-05:00>)>
<template TemplateState(<state sensor.living_room_humidifier_hygrometer_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Living Room Humidifier Hygrometer Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.620261-05:00>)>
<template TemplateState(<state sensor.spider_plant_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.624867-05:00>)>
<template TemplateState(<state sensor.thanksgiving_cactus_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.637992-05:00>)>

Looks like mostly my Xiaomi BLE plant sensors, and a few Govee water leak sensors I may have added through MQTT. Remind me: can I exclude with your blueprint? If so I can exclude the plants (because they’re otherwise reporting just fine, one just blew up my phone telling me it needed water!) …not sure about the Govee/MQTT devices. I think I’ve got them pulled in now via HomeKit, so I don’t think I need the MQTT variety.

I have excluded the plant sensors, and outright removed the Govee/MQTT devices. It’s set to run again in a bit over 20 minutes, so I’ll let you know how that goes.

I must have missed plants when I excluded, though I swear I counted 11.

Unavailable Sensors: 
    <template TemplateState(<state sensor.african_violet_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.625224-05:00>)>
<template TemplateState(<state sensor.areca_palm_desk_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.624655-05:00>)>
<template TemplateState(<state sensor.areca_palm_window_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.623744-05:00>)>
<template TemplateState(<state sensor.cactus_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.624312-05:00>)>
<template TemplateState(<state sensor.jade_plant_floor_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.625403-05:00>)>
<template TemplateState(<state sensor.jade_plant_lower_shelf_left_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.637095-05:00>)>
<template TemplateState(<state sensor.jade_plant_lower_shelf_right_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.625744-05:00>)>
<template TemplateState(<state sensor.jade_plant_top_shelf_left_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.625047-05:00>)>
<template TemplateState(<state sensor.jade_plant_top_shelf_right_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.624486-05:00>)>
<template TemplateState(<state sensor.jade_plant_window_left_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.624127-05:00>)>
<template TemplateState(<state sensor.jade_plant_window_right_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.625574-05:00>)>
<template TemplateState(<state sensor.living_room_humidifier_hygrometer_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Living Room Humidifier Hygrometer Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.620261-05:00>)>
<template TemplateState(<state sensor.spider_plant_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.624867-05:00>)>
<template TemplateState(<state sensor.thanksgiving_cactus_battery=unavailable; restored=True, state_class=measurement, device_class=battery, friendly_name=Battery, supported_features=0, unit_of_measurement=% @ 2023-02-22T20:22:15.637992-05:00>)

Edited, about 12 hours later: Ah crud. I think I missed the two areca palms! That explains it. Now I just need to smack around the tiny hygrometer to make it behave. Thanks for all the feedback!

1 Like

No I don’t. I use deCONZ. Before many others search their back off, better specify for which integration this can be expected (ZHA? ZB2MQTT?).

Good point! I have updated the document to specify that those instructions are for the built in Home Assistant Zigbee integration (ZHA) - those using an alternative integration (Z2M/DeConz) will have to find their own instructions, as I personally do not have either of those integrations.

If anyone reading this is running Z2M or DeConz, and knows how to adjust the “unavailable” timeout for those two integrations, if you can provide instructions for that I will edit the original post to contain those instructions.

I am using Z2M. You go to settings, and in that first settings options, select availability. Select availability (advaced) and then you have options to change the amount of time after which an active device will be marked as offline in minutes. Default is 25 hours (1500 minutes).

for me this code sends in notification as “unavailable” a lot more than just the battery powered devices.
but the debug code correctly filters and displays the only battery powered device that is offline.

so… what could be different between the debug code and the code that is run in automation?

image

Debug code output:

Unavailable Sensors: 
    <template TemplateState(<state sensor.tradfri_button1_battery=unavailable; state_class=measurement, unit_of_measurement=%, device_class=battery, friendly_name=Tradfri_Button1 Battery @ 2023-03-06T00:30:13.892090+02:00>)>
Unavailable binary sensors:

After some debugging, I noticed that the blueprint contains a bit more than the debug code provided. And the debug code is not really nice for printing in the template page.

The blueprint checks the sensors, the binary_sensors and then the switches. And it seems I have a number of offline switches → thus the long notification.
I just need to add quite a few switches in the exclusion list.

a more complete debug code that can be put in Developer tools->Template to understand what is going on::

Checking sensors...
{%- set result = namespace(sensors=[]) %}
    {%- for state in states.sensor | selectattr('attributes.device_class', 'defined') | selectattr('attributes.device_class', '==', 'battery') %}
      {%- if "=unavailable" in state | string  %}
        {%- set result.sensors = result.sensors + [state] %}
      {%- endif %}
    {%- endfor %}
    Unavailable Sensors: 
    {{result.sensors|join('\n')}}

    Checking binary_sensors...
    {%- set result = namespace(sensors=[]) %}
    {%- for state in states.binary_sensor | selectattr('attributes.device_class', 'defined') | selectattr('attributes.device_class', '==', 'battery') %}
      {%- if "unavailable" in state | string %}
        {%- set result.sensors = result.sensors + [state] %}
      {%- endif %}
    {%- endfor %}
    Unavailable binary sensors: 
    {{result.sensors|join('\n')}}

    Checking switches...
{%- set result = namespace(sensors=[]) %}
    {%- for state in states.switch | selectattr('state','eq','unavailable')%}
      {%- set result.sensors= result.sensors + [state] %}
    {%- endfor %}
    Unavailable switches:
    {{result.sensors|join('\n')}}
1 Like

Hi, It’s a great blueprint. Would it be possible to change it to run several times a day like on an interval. ? Would like to know as soon as possible if my ZHA devices goes offline.
Thanks.

well…yes, but since time_pattern has a lot of parameters (hour, minute, second, etc…) it would require adding as input in the blueprint a lot more fields.

Still, you can do it if you modify code of the blueprint on your setup.
there should be a yaml file in blueprints/automation/Tahutipai. In that file you need to replace:

trigger:
- platform: time
  at: !input 'time'

with something like:

trigger:
- platform: time_pattern
  minutes: "/5"

and it should trigger every 5 minutes…

This is great—thank you! I’m using the beta blueprint and I wanted to get alerts for a “mains connected” Sonoff S31 power plug, but it’s not showing up in the list of devices to exclude so I’m not sure that the beta blueprint is seeing it. It also seems to be including some automations and devices that I excluded. Any ideas?

Edit; I added entities and removed some old switches that looked like they were named similar to automations. I think the only issue is making sure the Sonoff S31 switches are included.

How would I change this to run at regular intervals?

If you are using ZHA then the following template sensor can provide also the offline mains powered devices:

{% set str = states.button | selectattr('attributes.device_class', 'eq', 'identify') | selectattr('state', 'eq', 'unavailable') | map(attribute='attributes.friendly_name') | list | join(', ') | replace(' Identify', '') %}
{% if str | length == 0 %}
  None!
{% elif str | length < 256 %}
  {{ str }}
{% else %}
  Too many!
{% endif %}

Thank you; did you modify the blueprint to include that? If so can you share the fully modified version?

No, I’ve just created a helper (template sensor). This way the changes are instant whenever a device goes offline the sensor is updated. You can then create an automation to trigger based on the state change and send notification/do other action.

Hi, I setup to run this check every day, but it doesn’t… it seems that this check is always false

{{ sensors != '''' and (day | int == 0 or day | int == now().isoweekday()) }}

If I check this code in the template i got:

UndefinedError: ‘day’ is undefined

How can I enable the “day” sensor?

Thanks

Is there any way to extract the area name of the entities contained in the {{sensors}} array - I’ve tried a few template options but they all return “None”.