[z2m] Alert that a zigbee device is offline

I have activated the Z2M availability warning, it is going quite well. I would like to have an alert when one of my devices is offline. Something that would scroll through the status of all z2m devices without having to add them myself by hand when I add new devices.

Is it possible to do something automated to monitor all devices?

Look at this article: Managing Offline Devices in Zigbee2MQTT — Home Automation Guy

I used what was recommended in that article and it worked for me! :slight_smile: Thanks

  1. we create a helper: settings - devices and services - helpers - create helper - template - template of a sensor.
{% set result = namespace(sensors=[]) %}
{% for state in states.sensor | rejectattr('attributes.device_class', 'undefined') | selectattr('attributes.device_class', '==', 'timestamp') %}
    {% if 'last_seen' in state.entity_id and (states(state.entity_id) == 'unavailable' or ((as_timestamp(now()) - as_timestamp(states(state.entity_id))) > ((24 | int) * 60 * 60))) %}
        {% set result.sensors = result.sensors + [state.name | regex_replace(find=' last seen', replace='') ~ ' (' ~ relative_time(strptime(states(state.entity_id), '%Y-%m-%dT%H:%M:%S%z', 'unavailable')) ~ ')'] %}
    {% endif %}
{% endfor %}
{{ result.sensors | join('\n') | truncate(254, True) }}

  1. z2m - settings -advanced - ISO_8601

  1. File Editor - /homeassistant/zigbee2mqtt/configuration.yaml
device_options:
  homeassistant:
    last_seen:
      enabled_by_default: true

  1. Create automation and warning script:

  1. Reboot Home Assistant
1 Like

We can also have a card that shows the connection/disconnection status of all devices at the same time:

If you want to be warned every 10 minutes with a continuous warning that there are offline devices, you can do it like this automation :

In an automation as a trigger we will put that the condition is fulfilled:
minute 00
minute 10
minute 20
minute 30
minute 40
minute 50

And as an action we will put an if, which checks if there are devices online. If there are offline devices it warns us.

{% set result = namespace(sensors=[]) %}
{% for state in states.sensor | rejectattr('attributes.device_class', 'undefined') | selectattr('attributes.device_class', '==', 'timestamp') %}
    {% if 'last_seen' in state.entity_id and (states(state.entity_id) == 'unavailable' or ((as_timestamp(now()) - as_timestamp(states(state.entity_id))) > ((24 | int) * 60 * 60))) %}
        {% set result.sensors = result.sensors + [state.name | regex_replace(find=' last seen', replace='') ~ ' (' ~ relative_time(strptime(states(state.entity_id), '%Y-%m-%dT%H:%M:%S%z', 'unavailable')) ~ ')'] %}
    {% endif %}
{% endfor %}
{{ result.sensors | join('\n') | truncate(254, True) != ''}}

In this way we will have a check every 10 minutes if there are offline zigbee devices and its corresponding warning.

For anyone using appdaemon, here is an app I wrote that will notify on any unavailable entity, and not just zigbee devices.

Key features include:

  • Excluding entities when they contain a given string
  • Batching and limiting notifications, so you only get a few if hundreds are offline (such as when shutting down zigbee2mqtt)

In apps.yaml (with my own examples in exclude):

unavailable:
  module: unavailable
  class: UnavailableNotifier
  exclude:
    - device_tracker.
    - sensor.hp_laser
    # Lights attached to a physical switch
    - side_table

    # These are a one-way switch
    - switch.front_load_washer_power
    - switch.dryer_power
    - button.front_load_washer
    - button.dryer
    # Buggy in LG integration
    - switch.refrigerator_ice_plus

    # Camera drops wifi once or twice a day
    - camera.freezer_room
    - binary_sensor.freezer_room_motion_detected
    - camera.cat_food_camera
    - binary_sensor.cat_food_camera_motion_detected
    # We have Bluetooth on a USB 3 cable and AirThings requires a GATT connection
    # https://github.com/home-assistant/core/issues/116770
    - sensor.airthings
    - sensor.air_quality

And then in unavailable.py - note you for sure will need to change the notify service name, as I hadn’t bothered to make that a variable.

import appdaemon.plugins.hass.hassapi as hass


# noinspection PyAttributeOutsideInit
class UnavailableNotifier(hass.Hass):

    def initialize(self):
        self._exclude = self.args["exclude"]
        self._state_handle = self.listen_state(self.unavailable)
        self._unavailable = {}
        self._timer_handle = None

    def unavailable(self, entity, attribute, old, new, kwargs):
        for exclude in self._exclude:
            if exclude in entity:
                return

        if new == "unavailable" and not entity in self._unavailable:
            if len(self._unavailable) > 6 * 4:
                self.log(f"Skipping adding {entity} to the queue.")
                return

            self.log("Adding " + entity + " to the notification queue")
            self._unavailable[entity] = self.get_now_ts()
            if self._timer_handle is None:
                self._timer_handle = self.run_in(self.send, 15)

    def send(self, kwargs):
        if len(self._unavailable) > 0:
            to_notify = set()
            next_round = {}
            while len(to_notify) < 6 and len(self._unavailable) > 0:
                entity, added = self._unavailable.popitem()
                if added > self.get_now_ts() - 30:
                    next_round[entity] = added
                elif self.get_state(entity_id=entity) == "unavailable":
                    to_notify.add(entity)

            self._unavailable.update(next_round)

            if len(to_notify) > 0:
                self.log("Notifying on " + str(len(to_notify)) + " entities")
                entities = "- " + "\n- ".join(to_notify)
                self.notify(name="mobile_app_iphone", title="⚠ Unavailable Entities",
                            message=entities)
                self._timer_handle = self.run_in(self.send, 15)
                return
            else:
                self._timer_handle = self.run_in(self.send, 15)
                self.log(str(len(self._unavailable)) + " notifications remaining")
                return

        self._timer_handle = None

Hope this is helpful to someone else!

I think I got lost with the explanation, if you could make it a little more detailed what this code is for and how to install it, it would be perfect! thanks!

And the HA Addon:

This is very much for people comfortable with programming, who would just rather write Python than automation in a UI. If this is a rabbit hole you want to go down, I’d suggest starting with reading AppDaemon Tutorial for HASS Users — AppDaemon 4.4.3 documentation and going from there!

thanks a lot!