Help in automation and arrays

Hi all,
I need some help to setup properly an automation. My goal is to check once a day if all my remote sensors are working. Those are available via MQTT (Zigbee2Mqtt bridge for Xiaomi sensors).
What I’ll do is to check the last update of the *_linkquality of the device. If greater than xx seconds it should then trigger something. Until here ok, i can check the last update like this:

{% set LastUpdateSecs = (as_timestamp(now()) - as_timestamp(states.sensor["0x00158d000486dcb3_linkquality"].last_updated))|int %}

And then check it:

{% if LastUpdateSecs > 3600 -%}
  Attention: last update:  {{ relative_time(states.sensor["0x00158d000486dcb3_linkquality"].last_updated) }} ago
{%- else -%}
  All ok; lasto  {{ relative_time(states.sensor["0x00158d000486dcb3_linkquality"].last_updated) }} ago
{%- endif %}

I would like to write better the list of the devices. Great would If I could select them from gui, something like this Low battery level detection & notification for all battery sensors Otherwise a help using an array to cycle through all the devices and notify only those that are not update since xx time.

Any help?

Thanks, Simon

Hi all,
I’m trying to create the automation by myself but I need some help.
How can i get all sensors that have the name like *linkquality? That should match, i.e.:

sensor.0x00158d0004521ef0_linkquality
sensor.0x00158d000477376f_linkquality
(...)

Than, having that list, how to cycle trough the list and check the last update date-time like above?

Thanks, Simon

Sorry, any suggestion please?
So I’ll try to continue by myself with the automation. Or in case point me to right documentation?
Thanks again!
Simon

I’d create an automation that makes a linkquality group…

- alias: Create Link Quality Group on Startup.
  trigger:
  - platform: homeassistant
    event: start
  action:
  - service: group.set
    data:
      object_id: linkquality
      entities: >
        {{ states.sensor | map(attribute='entity_id') | select('search', '_linkquality') | list }}

Then you can create your template that looks at all the link quality sensors

{% set ns = namespace(entities = []) %}
{% for e in expand('group.linkquality') %}
  {% if (now() - e.last_updated).seconds > 3600 %}
    {% set ns.entities = ns.entities + [ e.name ~ ' last updated ' ~ relative_time(e.last_updated) ] %}
  {% endif %}
{% endfor %}
{% if ns.entities | length > 0 %}
  Attention: {{ ns.entities | join(', ') }}
{% else %}
  All Okay
{% endif %}

Hi @petro
Thanks for the suggestion, but why this is not working? So doing all the stuff in the template?

{% set ns = namespace(entities = []) %}
{% for e in states.sensor | map(attribute='entity_id') | select('search', '_linkquality') %}
  {% if (now() - e.last_updated).seconds > 3600 %}
    {% set ns.entities = ns.entities + [ e.name ~ ' last updated ' ~ relative_time(e.last_updated) ] %}
  {% endif %}
{% endfor %}
{% if ns.entities | length > 0 %}
  Attention: {{ ns.entities | join(', ') }}
{% else %}
  All Okay
{% endif %}

I’m getting:
UndefinedError: 'str object' has no attribute 'last_updated'

This command works to export the devices as expected:

{{ states.sensor | map(attribute='entity_id') | select('search', '_linkquality') | list | join(', ') }}

Thanks, Simon

because you’re mapping the for loop to a entity_id, so the object no longer exists.

Neither creating the variable outside the for loop?

Thanks, Simon

this right here takes the state object converts it to an entity_id and selects the entity_id if it ends with _linkquality

You mean the command takes only the entity_id having that name, without any attribute? My test was to write all into the automation, without creating an alias, to apply it to the blueprint example, but seems a little outside my knowledges :slight_smile: wont ask you to write it, maybe I’ll opt to your alias option if I’m not able to get it working all in the same automation :wink:

Thanks, Simon

why don’t you want to use the method I already provided above? It does exactly what you want but it creates a supplemental group on top of the sensor. This allows the sensor to give you LIVE updates instead of being updates that can be late by ~1 minute.

There is no really reason, That’s fine, I’ll use your suggestions and try it.I was trying to apply all to the bloeprint above, but I can use it in an automation as well.
Thanks a lot @petro :slight_smile:
Simon

if you just want to change the blueprint

{% set ns = namespace(entities = []) %}
{% for e in states.sensor | selectattr('entity_id', 'search', '_linkquality') %}
  {% if (now() - e.last_updated).seconds > 3600 %}
    {% set ns.entities = ns.entities + [ e.name ~ ' last updated ' ~ relative_time(e.last_updated) ] %}
  {% endif %}
{% endfor %}
{% if ns.entities | length > 0 %}
  Attention: {{ ns.entities | join(', ') }}
{% else %}
  All Okay
{% endif %}

Hello again,
I’ve a strange behavuoir, trying your code and a single sensor, loog here:

{% set ns = namespace(entities = []) %}
{% for e in states.sensor | selectattr('entity_id', 'search', '_linkquality') %}
  {% if (now() - e.last_updated).seconds > 84600 %}
    {{ e.name }}
    {{ (now() - e.last_updated).seconds }}
    {% set ns.entities = ns.entities + [ e.name ~ ' last updated ' ~ relative_time(e.last_updated) ] %}
  {% endif %}
{% endfor %}
{% if ns.entities | length > 0 %}
  Attention: {{ ns.entities | join(', ') }}
{% else %}
  All Okay
{% endif %}


{% set LastUpdateSecs = (as_timestamp(now()) - as_timestamp(states.sensor["sensore_ambientale_01_linkquality"].last_updated))|int %}
{% if LastUpdateSecs > 84600 -%}
  Attention: last update {{ relative_time(states.sensor["sensore_ambientale_01_linkquality"].last_updated) }} ago
{%- else -%}
  All ok: last update {{ relative_time(states.sensor["sensore_ambientale_01_linkquality"].last_updated) }} ago
{%- endif %}

The output is:

All Okay

Attention: last update 10 days ago

So in your case there are no sensors that should match more than 1 day (84600secs), but in my single sensor, the specified sensor is not updating. I was expecting have the same result for that sensor in your code as well.

Ideas why?

EDIT

Look the output if I reduce the seconds to 1 hour (3600secs). Strange that the output changes and there are then sensors above 10 days without update. why that?

Camera Sensore Ambientale_linkquality
    10707
    

  
    Bagno Doccia Finestra linkquality
    17411
    

  
    Camera Porta Finestra linkquality
    8150
    

  
    Camera Finestra linkquality
    8692
    

  
    Soggiorno Sensore Ambientale linkquality
    10707
    
  
  Attention: Camera Sensore Ambientale_linkquality last updated 10 days, Bagno Doccia Finestra linkquality last updated 5 hours, Camera Porta Finestra linkquality last updated 2 hours, Camera Finestra linkquality last updated 2 hours, Soggiorno Sensore Ambientale linkquality last updated 10 days


Attention: last update 10 days ago

Hi @petro again.
I’ve found that this two commands doesn’t always return the right value based on the script above. Do you know why?
{% set LastUpdateSecs02 = (as_timestamp(now()) - as_timestamp(e.last_updated))|int %}
and
{{ (now() - e.last_updated).seconds }}
Mostly is the same value, but for my two sensors that I need to re-pair and reset, the update from your command is not equal to the LastUpdateSecs02 but cannot understand why. I would say that LastUpdateSecs02 is the correct one.
Ideas?
Thanks, Simon

If you’re using a sensor to display this information, then it’s the update delay that I mentioned above. Which is why I was urging you to use my original solution because it updates live. Without the group, it won’t update update live, it’ll be throttled to 1 update per minute.

Otherwise, if there are any errors related to the template in your logs, you’ll have to post them.

Ok, thanks @petro . Maybe I’ll move to your method.
I’ve only a last doubt. I cannot understand how to write the syntax in the template, this gives me an error:

variables:
  day: !input 'day'
  threshold: !input 'threshold'
  exclude: !input 'exclude'
  sensors: >-
    {% set result = namespace(entities = []) %}
    {% set threshold_secs = threshold * 60 * 60 * 24 %}
    {% for e in states.sensor | selectattr('entity_id', 'search', 'linkquality') %}
      {% set LastUpdateSecs = (as_timestamp(now()) - as_timestamp(e.last_updated))|int %}
      {% if LastUpdateSecs > threshold_secs %}
        {% set result.entities = result.entities + [ e.name ~ ' last updated ' ~ relative_time(e.last_updated) ] %}
      {% endif %}
    {% endfor %}
    {{ result.entities | join(', ') }}

it gives me

2022-04-12 16:22:43 ERROR (SyncWorker_5) [homeassistant.util.yaml.loader] while scanning for the next token
found character '\t' that cannot start any token

Or pointing me how to format that?

Thanks!

Simon

You’re mixing tabs and spaces, you can’t do that in yaml.

Again @petro it’s fine, copy and paste has introdiced TABs, nor with a yaml validator seems ok :slight_smile:

Thanks @petro !

Hello @petro and all.
I’ve decided to use your approach. Your group is created on startup and it’s easy to query the result from the template tab, with this:

{% set ns = namespace(entities = []) %}
{% for e in expand('group.linkquality') %}
  {% if (now() - e.last_updated).seconds > 14400 %}
    {% set ns.entities = ns.entities + [ e.name ~ ' last updated ' ~ relative_time(e.last_updated) ] %}
  {% endif %}
{% endfor %}
{% if ns.entities | length > 0 %}
  {% set message =  "Attention" + ns.entities | join(', ')  %}
{% else %}
  {% set message = "All Okay" %}
{% endif %}
{{ message }}

Now I’ve installed the scheduler (Scheduler card/custom component) to use it i.e. once a week to test the status and send me a message in case there are sensors not updated, with this:

service: notify.xefilbot
data:
  title: '*Update Status*'
  message: '{{ message }}'

I know the scheduler accept as trigger a script, so I would like to put the check above and the action above into a script that should be executed one a week.

Could you (or someone else) help me to put all that together? (check for uptime and send to telegram bot)

Thanks to all!!

Simon