Script to check "last seen" zigbee devices?

Thank you so much! Here is the correct code for me:

          {% for state in states -%}
            {%- if (state.attributes.last_seen and not (state.name | regex_search('update_available|linkquality|power_on_behavior|update_state'))) %}
              {%- if (as_timestamp(now()) - as_timestamp(state.attributes.last_seen) > (60 * 60 * 6) ) %}
                {{ ((as_timestamp(now()) - as_timestamp(state.attributes.last_seen)) / (3600)) | round(1) }} hours ago for {{ state.name }}
                
              {%- endif -%}
            {%- endif -%}
          {%- endfor %}

Now i receive:
Some Zigbee devices haven’t been seen lately…
11.0 hours ago for ikeae14bulb
11.0 hours ago for ikeae271
11.0 hours ago for ikeae273

That’s what i wanted! Thank you.

P.S.
It’s ignoring “_” symbol in device name. Is it possible to fix?

1 Like

Using the current dev branch of z2m, with commit c28731957ae109d88e28b2fcafa49d5cac4079f5
using this template (paste in a markdown card) shows the most recent seen and least recent seen.

{% set ns = namespace(found=false) %}
{% set ns.worst = 0 %}
{% set ns.best = 99999999 %}
{% for state in states if 'last_seen' in state.attributes -%}
{% set raw_secs = (as_timestamp(now()) - as_timestamp(state.attributes.last_seen)) | round(0) -%}
{% if raw_secs < ns.best %}
{% set ns.best = raw_secs %}
{% set ns.best_name = state.name %}
{% endif %}
{% if raw_secs > ns.worst %}
{% set ns.worst = raw_secs %}
{% set ns.worst_name = state.name %}
{% endif %}
{% endfor %}
{% set days = ns.best // (24*3600) -%}
{% set hours = (ns.best - 24*3600*days) // 3600 -%}
{% set minutes = (ns.best - 24*3600*days - 3600*hours) // 60 -%}
{% set seconds = (ns.best - 24*3600*days - 3600*hours - 60*minutes) -%}
{% if days > 0 -%}
{{ ns.best_name }}: Last seen {{ days }}{{ ((hours/24) | round(1) | string)[1:] }} days ago.
{% elif hours > 0 -%}
{{ ns.best_name }}: Last seen {{ hours }}{{ ((minutes/60) | round(1) | string)[1:] }} hours ago.
{% elif minutes > 0 -%}
{{ ns.best_name }}: Last seen {{ minutes }}{{ ((seconds/60) | round(1) | string)[1:] }} minutes ago.
{% elif seconds > 0 -%}
{{ ns.best_name }}: Last seen {{ seconds }} seconds ago.
{% endif -%}
{% set days = ns.worst // (24*3600) -%}
{% set hours = (ns.worst - 24*3600*days) // 3600 -%}
{% set minutes = (ns.worst - 24*3600*days - 3600*hours) // 60 -%}
{% set seconds = (ns.worst - 24*3600*days - 3600*hours - 60*minutes) -%}
{% if days > 0 -%}
{{ ns.worst_name }}: Last seen {{ days }}{{ ((hours/24) | round(1) | string)[1:] }} days ago.
{% elif hours > 0 -%}
{{ ns.worst_name }}: Last seen {{ hours }}{{ ((minutes/60) | round(1) | string)[1:] }} hours ago.
{% elif minutes > 0 -%}
{{ ns.worst_name }}: Last seen {{ minutes }}{{ ((seconds/60) | round(1) | string)[1:] }} minutes ago.
{% elif seconds > 0 -%}
{{ ns.worst_name }}: Last seen {{ seconds }} seconds ago.
{% endif -%}

More info here

1 Like

Use markdown, that is, asterisks (‘*’) surrounding your text.

{{“*”}}{{ state.attributes.friendly_name }}{{"*: "}}

1 Like

Thank you! Its working for me!
I changed {{ state.name }} to {{"*"}}{{ state.name }}{{"*"}}

Hi!
Is the last-seen attribute possible with all zigbee devices?
To enable it, simply enter in the zigbee2mqtt advanced configuration:
last_seen: ISO_8601_local ?

@OzGav Did you only use one automation or did you have to create template sensors?

Thanks

Not sure if all zigbee devices have the last_seen attribute but all mine do. Yes you can enter any valid option in the configuration I use last_seen: ISO_8601

The automation I show above is all I have done.

1 Like

You use the trigger at two set times (07:00 and 16:00). Is it possible to perform this check every 5 hours?

Could you show me the complete automation?
Thanks

alias: Zigbee Device Missing Alert
trigger:
  - platform: time
    at: '07:00'
  - platform: time
    at: '16:00'
condition:
  - condition: template
    value_template: |
      {% set ns = namespace(break = false) %} {% for state in states -%}
        {%- if state.attributes.last_seen %}
          {%- if (as_timestamp(now()) - as_timestamp(state.attributes.last_seen) > (60 * 60 * 20) ) and ns.break == false %}
            {%- set ns.break = true %}
            true
          {%- endif -%}
        {%- endif -%}
      {%- endfor %} 
action:
  - service: notify.my_telegram_direct
    data:
      message: >
        Some Zigbee devices haven't been seen lately... {% for state in states
        -%}
          {%- if (state.attributes.last_seen and not (state.name | regex_search('available|linkquality|power_on_behavior|state'))) %}
            {%- if (as_timestamp(now()) - as_timestamp(state.attributes.last_seen) > (60 * 60 * 20) ) %}
              {{ ((as_timestamp(now()) - as_timestamp(state.attributes.last_seen)) / (3600)) | round(1) }} hours ago for {{"*"}}{{ state.name }}{{"*"}}
              
            {%- endif -%}
          {%- endif -%}
        {%- endfor %}
mode: single

1 Like

for every 5 hours:

trigger:
  - platform: time_pattern
    hours: /5
1 Like

I am trying this:

- alias: ALERT Zigbee Offline Devices
  id: zigbee_device_missing_alert
  trigger:
    - platform: time
      at: "07:00"
    - platform: time
      at: "16:00"
  condition:
    - condition: template
      value_template: > 
        {% set ns = namespace(break = false) %}
        {% for state in states -%}
          {%- if state.attributes.last_seen %}
            {%- if (as_timestamp(now()) - as_timestamp(state.attributes.last_seen) > (5 * 60 * 60) ) and ns.break == false %}
              {%- set ns.break = true %}
              true
            {%- endif -%}
          {%- endif -%}
        {%- endfor %} 
  action:
    - service: notify.mobile_app_inanu
      data:
        message: >
          Alcuni dispositivi Zigbee potrebbero essere OFFLINE:
          {% for state in states -%}
            {%- if state.attributes.last_seen %}
              {%- if (as_timestamp(now()) - as_timestamp(state.attributes.last_seen) > (5 * 60 * 60) ) %}
                {{ ((as_timestamp(now()) - as_timestamp(state.attributes.last_seen)) / (3600)) | round(1) }} Ore fa - {{ state.name }}
              {%- endif -%}
            {%- endif -%}
          {%- endfor %}

But how can I do to display only the name of the entity in the notification message?
Now I see “Sirena battery low” and “Led Kitchen …” (I think the notification is cut with … from ios).

Can I display only “Siren” “Kitchen Led” (device name only) in the notification?

The above is a snippet from a post higher up. You need to add unique words in the regex search to filter out the duplicates

{%- if (state.attributes.last_seen and not (state.name | regex_search('linkquality'))) %}

Can you give me an example to only display the device name?

I have made some attempts but no more notifications arrive

This is perfect for me, but I can’t correctly line up the text in the notification…

            {%- macro GetDroppedZigbee() -%}
            {% for state in states.sensor -%}
            {%- if ("linkquality" in state.name and state_attr(state.entity_id, "last_seen") != None and (as_timestamp(now()) - as_timestamp(state_attr(state.entity_id, "last_seen")) > (5 * 60 * 60))) -%}
            {{ state.name | regex_replace(find=' linkquality', replace='', ignorecase=False) }} - Da {{ ((as_timestamp(now()) - as_timestamp(state.attributes.last_seen)) / (3600)) | round(0) }} Ore {{- '\n' -}}
            {%- endif -%}
            {%- endfor %}
            {%- endmacro -%}
            {{ GetDroppedZigbee() }}

It currently looks like this:

Immagine

But it should look like this:

With the @deadly667 method instead the notification arrives correctly aligned

Not sure…try just adding another blank line between these two lines.

Not working…

Unfortunately I still have problems with your template, it would be perfect to be able to adapt this part of the template to your version

   {%- if ("linkquality" in state.name and state_attr(state.entity_id, "last_seen") != None and (as_timestamp(now()) - as_timestamp(state_attr(state.entity_id, "last_seen")) > (24 * 60 * 60))) -%}
              {{ state.name | regex_replace(find=' linkquality', replace='', ignorecase=False) }} - {{ relative_time(strptime(state_attr(state.entity_id, "last_seen"), '%Y-%m-%dT%H:%M:%S%z')) }} ago {{- '\n' -}}
              {%- endif -%}

Currently I see “siren.battery”, but I would like to see only “siren” (device name, not entity name)

If you want the friendly name then you should be able to change state.name to state.attributes.friendly_name

But this must be either wrong or highly coincidental: all sensors updated at the same time.

I am experiencing the same: I get the same value for all sensors (last seen) which in my case is incorrect. It looks like some variable is stored somewhere that messes things up. Any ideas?

My YAML:

{{ ((as_timestamp(now()) - as_timestamp(states.sensor.rookmelder_1e_node_status.last_updated)) / (3600)) | round(1) }} uur
{{ ((as_timestamp(now()) - as_timestamp(states.sensor.rookmelder_bg_temperature.last_updated)) / (3600)) | round(1) }} uur 

Just an update since there are now sensors for the last seen values

- alias: Zigbee Device Missing Alert
  id: zigbee_device_missing_alert
  trigger:
  - platform: time
    at: '10:00'
  - platform: time
    at: '20:00'
  condition:
  - condition: template
    value_template: '{% set ns = namespace(break = false) %} 
      {% for state in (expand(states.sensor,states.binary_sensor,  states.light, states.switch) |selectattr(''entity_id'', ''search'', ''last_seen'')) -%} 
        {%- if (as_timestamp(now()) - as_timestamp(state.state) > (60 * 60 * 8)) and ns.break == false %} 
          {%- set ns.break = true %} 
          true 
        {%- endif -%} 
      {%- endfor %}'
  action:
  - service: notify.mobile_app_pixel_4a
    data:
      message: "Some Zigbee devices haven't been seen lately... {% for state in (expand(states.sensor,states.binary_sensor,
        states.light, states.switch) |selectattr('entity_id', 'search', 'last_seen')  -%} {%- if (as_timestamp(now()) - as_timestamp(state.state) > (60 * 60 * 8)
        ) %} {{ ((as_timestamp(now()) - as_timestamp(state.state)) / (3600)) | round(1)
        }} hours ago for {{ state.name }} {{'\r\n'}} {%- endif -%} {%- endfor %}"

2 Likes