Offline detection for Z2M devices with last_seen

Based on low battery level detection by Sbyx: Low battery level detection & notification for all battery sensors

Description

This blueprint checks at configured time for all devices that was last seen x hours (sensors in ‘unavailable’ state are also included) ago and fires action then (like notification). You can include list of devices in notification message. You can also exclude some devices from checking (use their ‘last seen’ sensor entity as exluded entity)

Example of notification bellow:

Code:

actions:
  - device_id: a2a0b972c39a402aa8547899f9d15ee7
    domain: mobile_app
    type: notify
    title: Urządzenie Zigbee niedostępne!
    message: '{{sensors}}'

Requirements

This blueprint is intended to work with Zigbee2MQTT devices that has ‘last seen’ sensors with ‘timestamp’ device_class (it is used to filter out sensors to check). It may work with other Zigbee integrations if there are also sensors with ‘last seen’ in name and ‘timestamp’ device_class.

You will need to enable ‘last_seen’ option in zigbee2mqtt configuration:

advanced:
  last_seen: ISO_8601_local

Remember also to enable ‘last seen’ sensors for all your Zigbee2MQTT devices (it is now disabled by default) in Home Assistant device page! You can also enable all ‘last seen’ sensors by default adding this to your Z2M configuration:

device_options:
  homeassistant:
    last_seen:
      enabled_by_default: true

Blueprint

Click the badge to import this Blueprint: (needs Home Assistant Core 2021.3 or higher)

Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

blueprint:
  name: Offline detection for Z2M devices with last_seen
  description: Regularly test all sensors with 'last_seen' in name and 'timestamp' device_class
    ('last seen' Z2M sensors) to detect offline and if so execute an action.
  domain: automation
  input:
    hours:
      name: Hours not seen
      description: Sensors not seen this amount of time are assumed to be offline.
      default: 24
      selector:
        number:
          min: 1.0
          max: 168.0
          unit_of_measurement: h
          mode: slider
          step: 1.0
    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: "'last seen' sensors (from devices that you want to exclude) to
        exclude from detection. Only entities with 'last seen' in name and 'timestamp'
        in device_class are supported, devices must be expanded!"
      default:
        entity_id: []
      selector:
        target:
          entity:
            domain: sensor
    actions:
      name: Actions
      description: Notifications or similar to be run. {{sensors}} is replaced with
        the names of sensors being offline.
      selector:
        action: {}
  source_url: https://gist.github.com/Mr-Groch/bf073b142b507e3b6f8154223f81803b
variables:
  day: !input 'day'
  hours: !input 'hours'
  exclude: !input 'exclude'
  sensors: "{% 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 not state.entity_id in exclude.entity_id and (states(state.entity_id) == 'unavailable' or ((as_timestamp(now()) - as_timestamp(states(state.entity_id))) > ((hours | 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(', ') }}"
trigger:
- platform: time
  at: !input 'time'
condition:
- '{{ sensors != '''' and (day | int == 0 or day | int == now().isoweekday()) }}'
action:
- choose: []
  default: !input 'actions'
mode: single
16 Likes

Awesome piece of work!
Thanks, initially I had some troubles getting it working.

But that had to do with the fact I dont have an automation.yaml but instead I included a whole directory.
This works:

automation mine: !include_dir_merge_list automations/
automation ui: !include automations.yaml

It’s only me who gets import error?

image

Import a blueprint
while scanning a simple key in "<unicode string>", line 7, column 1: </code></pre> ^ could not find expected ':' in "<unicode string>", line 8, column 1: <h2> ^

Same here.
Really wanted to test and use since this was one of the missing functions I have.
I hope this is can be solved

@pniewiadowski , @skloos68 you need to import url of blueprint gist, not url of this topic…

Clicking on import icon should work, if not import manally this url:

Does not work for me. When I try to create the automation it says “Message malformed. Missing input action”

Do you have succesfully imported and used any other blueprint? I’ve just deleted this blueprint on my local HA setup and imported it again succesfully.

Configuration → Blueprints → Import → Paste URL https://gist.github.com/Mr-Groch/bf073b142b507e3b6f8154223f81803b → Preview → Import → Create Automation → Fill all required fields → Save

You must have lqi sensors and last_seen option from Zigbee2MQTT enabled (see first post).

2 Likes

Hi,
Importation works, it’s the automation based on the blueprint that does not. When I save it it gives the error I mentioned.

Successfully used other blueprints.
Lqi are present on all sensors, last_seen is enabled
Thanks for your help

Can you give more details? Maybe something is logged to HA log, please give also screenshot or yaml what automation you are trying to create…

Ok I’ve tried again and apparently, when creating the automation using the blueprint, we need to define an action, otherwise it gives the error I mentioned. I’ve added a simple notification and now it saves without error.
Then I opened the blueprint’s code to see that the notification needed to refer to {{sensors}} to show the unresponsive devices. So that’s what I put in the notification, and it works like a charm.
I guess the blueprint cannot include a predefined notification since it depends on the user.
Maybe just add somewhere the steps needed for those who’ll encounter the same problem :wink:
Thanks a lot, it’s a useful automation !
Have a great day

2 Likes

Hello!

I enabled “last_seen” option in Z2M configuration. I checked the log, I saw the last_seen time.
I imported your automation from blueprint.
I made the rules, i did set 1 hour, all day (0), didnt make excloude sensors.
I did set notification in action section:

service: notify.push_uzenetkuldes
data:
title: A Zigbee eszköz nem elérhető
message: ‘{{sensors}}’

(I did set Pushover service before, it, I tired it, it work)

I saved it and enabled. But it do not work. I dissassembly one Xiaomi thermo sensor, it is not online 26 hours ago, but your script do it nothing.

Step result:
Result:

params:
domain: notify
service: push_uzenetkuldes
service_data:
title: A Zigbee eszköz nem elérhető
message: ‘’
target: {}
running_script: false
limit: 10

Step config:
service: notify.push_uzenetkuldes
data:
title: A Zigbee eszköz nem elérhető
message: ‘{{sensors}}’

I tired Low battery level detection & notification for all battery sensors and work it perfictly…

What is wrong? Please help me :slight_smile:

Paste this into dev tools, template:

{% set result = namespace(sensors=[]) %}
{% for state in states.sensor | selectattr('attributes.unit_of_measurement', '==', 'lqi') %}
{% if state_attr(state.entity_id, 'last_seen') != None and (as_timestamp(now()) - as_timestamp(state_attr(state.entity_id, 'last_seen'))) > ((1 | int) * 60 * 60) %}
{% set result.sensors = result.sensors + [state.name | regex_replace(find=' linkquality', replace='') ~ ' (' ~ relative_time(strptime(state_attr(state.entity_id, 'last_seen'), '%Y-%m-%dT%H:%M:%S%z')) ~ ')'] %}
{% endif %}
{% endfor %}
{{ result.sensors | join(', ') }}

If you see no result, you maybe have lqi sensors disabled (z2m update some time ago disabled those sensors by default…). If so you need to go to configuration, entities, check show disabled entities and search for linkquality - you should then enable all linkquality sensors for mqtt integration

1 Like

Thank you! Its works! I needed to enable linkquality on my all devices.

This automation can run once per day? It cant check my sensors every 6 or 12 hours?

Interesting. I can’t seem to see any Entities in Home Assistant showing “linkquality”.

Please can you let me know how you enabled linkquality for all of your devices? I’ve looked through the docs and can’t figure it out.

Thanks

Some recent z2m upgrade introduced hiding linkquality entities by default. You must enable each linkquality entity manually in devices

I agree. Is it possible to specify multiple times for automation to run or set an intervall like every three hours?

Is anyone else seeing this error? (I’m on 2021.12.9)

2022-01-29 18:56:48 WARNING (MainThread) [homeassistant.helpers.template] Template warning: 'strptime' got invalid input '2022-01-29T17:30:49.295Z' when rendering template '{% set result = namespace(sensors=[]) %}
{% for state in states.sensor | selectattr('attributes.unit_of_measurement', '==', 'lqi') %}
{% if state_attr(state.entity_id, 'last_seen') != None and (as_timestamp(now()) - as_timestamp(state_attr(state.entity_id, 'last_seen'))) > ((1 | int) * 60 * 60) %}
{% set result.sensors = result.sensors + [state.name | regex_replace(find=' linkquality', replace='') ~ ' (' ~ relative_time(strptime(state_attr(state.entity_id, 'last_seen'), '%Y-%m-%dT%H:%M:%S%z')) ~ ')'] %}
{% endif %}
{% endfor %}
{{ result.sensors | join(', ') }}' but no default was specified. Currently 'strptime' will return '2022-01-29T17:30:49.295Z', however this template will fail to render in Home Assistant core 2022.1

Notification does not show the sensor name


If you have the blueprint and other YAML code in the main message, the myBlueprints tool does not work.
I would suggest putting the other 2 yaml code segments onto a reply, or using a screenshot of those, or adding them as just text. Otherwise people will have problems importing the blueprint. (That or remove the myBlueprints thing completely.)
Before I moved my blueprint code to GitHub, I would load the main message with the blueprint code, then comment on it immediately if there were ‘helper’ yaml code segments that were needed.

The warning part, read this…
{{ result.sensors | join(', ') }}' but no default was specified. Currently 'strptime' will return '2022-01-29T17:30:49.295Z', however this template will fail to render in Home Assistant core 2022.1

@Mr_Groch

It’s a deprecated thing that will, I assume, become a breaking change…