Automate ZwaveJS Ping Dead Nodes?

I have a different logic when to ping my devices, so I use it differently (my devices do actually become “dead” from the system perspective, as they lose power during high tariff, so I ping them right after the tariff changes back). I have no need for the template sensor, as my trigger point is unrelated.

Regardless, I believe my code can be used basically as is in the template sensor entity_id attribute section, replacing the original:

        attributes:
          entity_id: >-
            {% set dead_nodes = integration_entities('zwave_js') | select('match', 'sensor\..*node_status')| select('is_state', 'dead') | list -%}
            {% set ns = namespace(buttons=[]) -%}
            {% for e in dead_nodes -%}
            {% set device_id = device_id(e) -%}
            {% set button = device_entities(device_id) | select('match','button\..*_ping') | first -%}
            {% set ns.buttons = ns.buttons + [button] -%}
            {% endfor -%}
            {{ ns.buttons }}
1 Like

Brilliant - had a dead node I tested this on today and it’s the first time it worked all year. I’ll post my sensor template and automation YAML shortly for others to use in case it’s helpful.

2 Likes

So, I followed the process here as far as directory structure goes:

In the packages directory that is referenced inside configuration.yaml, I have a ping_zwave.yaml file with the following below. This ping_zwave.yaml is just your sensor to detect what nodes are dead. You could include unavailable, unknown in line 14, but I don’t run into those states ever, and pinging those nodes with those states will not resolve the problem anyway.

ping_zwave.yaml

template:
  - sensor:
      - name: "Dead ZWave Devices"
        unique_id: dead_zwave_devices
        unit_of_measurement: entities
        state: >
          {% if state_attr('sensor.dead_zwave_devices','entity_id') != none %}
            {{ state_attr('sensor.dead_zwave_devices','entity_id') | count }}
          {% else %}
            {{ 0 }}
          {% endif %}
        attributes:
          entity_id: >-
            {% set dead_nodes = integration_entities('zwave_js') | select('match', 'sensor\..*node_status')| select('is_state', 'dead') | list -%}
            {% set ns = namespace(buttons=[]) -%}
            {% for e in dead_nodes -%}
            {% set device_id = device_id(e) -%}
            {% set button = device_entities(device_id) | select('match','button\..*_ping') | first -%}
            {% set ns.buttons = ns.buttons + [button] -%}
            {% endfor -%}
            {{ ns.buttons }}

In the Automation GUI, I setup an automation like this:

If you’re into the YAML, here’s the backend of that GUI automation:

- id: '1669759724675'
  alias: Ping Dead ZWave Devices
  description: ''
  trigger:
  - platform: state
    entity_id:
    - sensor.dead_zwave_devices
  condition:
  - condition: template
    value_template: '{{ int(states.sensor.dead_zwave_devices.state) > 0 }}'
  action:
  - service: button.press
    target:
      entity_id: '{{ state_attr(''sensor.dead_zwave_devices'',''entity_id'') }}'
  mode: single
4 Likes

@Karson Not sure why, but with this code, the sensor shows 0 dead devices even though I have 2.

Is the device marked as dead in ZJS-UI, or listed as something else? Line 14 I limited down to just dead, so if it’s showing as anything else it won’t be filtered on.

I thought I’d share my Node Red flow to Ping dead or unavailable z-wave nodes:

[{"id":"415cebd80b1d1d0d","type":"server-state-changed","z":"92da3f90.2062d","name":"Zwave device dead|unavailable|unknown >1 minute?","server":"5c29d263.09d2ac","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"_node_status","entityidfiltertype":"substring","outputinitially":false,"state_type":"str","haltifstate":"dead|unavailable|unknown","halt_if_type":"re","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"for":"1","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":1290,"y":100,"wires":[["f9fd6509d9b89269"],[]]},{"id":"58abebe4e616a04c","type":"template","z":"92da3f90.2062d","name":"Render Template","field":"template","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{=<% %>=}}\n{{ device_entities(\"<% payload %>\") }}","output":"str","x":1970,"y":100,"wires":[["354ed32f1d7bbafc"]]},{"id":"354ed32f1d7bbafc","type":"api-render-template","z":"92da3f90.2062d","name":"Get all entities","server":"5c29d263.09d2ac","version":0,"template":"","resultsLocation":"payload","resultsLocationType":"msg","templateLocation":"template","templateLocationType":"msg","x":2160,"y":100,"wires":[["28cf4bbbc0322eb7"]]},{"id":"655be19debc68002","type":"api-render-template","z":"92da3f90.2062d","name":"Get Device ID","server":"86158645.d19e98","version":0,"template":"","resultsLocation":"payload","resultsLocationType":"msg","templateLocation":"template","templateLocationType":"msg","x":1780,"y":100,"wires":[["58abebe4e616a04c"]]},{"id":"28cf4bbbc0322eb7","type":"function","z":"92da3f90.2062d","name":"Find ping entity","func":"var str = msg.payload; // assuming the original string is in the \"payload\" property of the message object\nvar parts = str.split(\"'\");\n\nfor (var i = 0; i < parts.length; i++) {\nif (parts[i].includes(\"_ping\")) {\n    return { ping: parts[i], original: msg}; // returning the result as a string in the \"payload\" property of the message object\n}\n}\n\n// If no element is found containing the substring _ping, return an empty string\nreturn { ping: \"\", original: msg};","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":2340,"y":100,"wires":[["a2e2687ac643954b"]]},{"id":"a2e2687ac643954b","type":"api-call-service","z":"92da3f90.2062d","name":"Ping z-wave device","server":"5c29d263.09d2ac","version":5,"debugenabled":false,"domain":"button","service":"press","areaId":[],"deviceId":[],"entityId":["{{ping}}"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[{"property":"data","propertyType":"msg","value":"data","valueType":"msg"}],"queue":"none","x":2530,"y":100,"wires":[["45065c7f31993dd7"]]},{"id":"f9fd6509d9b89269","type":"template","z":"92da3f90.2062d","name":"Render template","field":"template","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{=<% %>=}}\n{{ device_id(\"<% data.entity_id %>\") }}","output":"str","x":1590,"y":100,"wires":[["655be19debc68002"]]},{"id":"0e263a6ef3cf35e3","type":"ha-wait-until","z":"92da3f90.2062d","name":"wait untill available","server":"5c29d263.09d2ac","version":2,"outputs":2,"entityId":"{{original.data.entity_id}}","entityIdFilterType":"exact","property":"state","comparator":"is_not","value":"dead|unavailable|unknown","valueType":"re","timeout":"60","timeoutType":"num","timeoutUnits":"seconds","checkCurrentState":true,"blockInputOverrides":true,"outputProperties":[],"x":1370,"y":220,"wires":[[],["e01bc2ee131d8510"]]},{"id":"e01bc2ee131d8510","type":"calculator","z":"92da3f90.2062d","name":"limit+1","inputMsgField":"limit","outputMsgField":"limit","operation":"sum","constant":"1","round":false,"decimals":0,"x":1530,"y":180,"wires":[["9ad4b90e09a36a0d"]]},{"id":"9e75f5158d501394","type":"switch","z":"92da3f90.2062d","name":"limit<=200?","property":"limit","propertyType":"msg","rules":[{"t":"lte","v":"200","vt":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1830,"y":180,"wires":[["0e263a6ef3cf35e3"],["b8d5d79e4fa25ba6"]]},{"id":"45065c7f31993dd7","type":"change","z":"92da3f90.2062d","name":"limit=0","rules":[{"t":"set","p":"limit","pt":"msg","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":1210,"y":180,"wires":[["0e263a6ef3cf35e3"]]},{"id":"a75ab77c82fb9f37","type":"change","z":"92da3f90.2062d","name":"Define parameters","rules":[{"t":"set","p":"who","pt":"msg","to":"jane","tot":"str"},{"t":"set","p":"NotifyType","pt":"msg","to":"normal","tot":"str"},{"t":"set","p":"title","pt":"msg","to":"payload&\" unavailable\"","tot":"jsonata"},{"t":"set","p":"message","pt":"msg","to":"payload&\" z-wave module is unavailable. Many Pings didn't solve the problem\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":2450,"y":180,"wires":[["371b4f1197629d30"]]},{"id":"9ad4b90e09a36a0d","type":"api-call-service","z":"92da3f90.2062d","name":"Ping device","server":"5c29d263.09d2ac","version":5,"debugenabled":false,"domain":"button","service":"press","areaId":[],"deviceId":[],"entityId":["{{ping}}"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1670,"y":180,"wires":[["9e75f5158d501394"]]},{"id":"b8d5d79e4fa25ba6","type":"api-current-state","z":"92da3f90.2062d","name":"get friendly name","server":"5c29d263.09d2ac","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"{{original.topic}}","state_type":"str","blockInputOverrides":true,"outputProperties":[{"property":"data2","propertyType":"msg","value":"","valueType":"entity"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"for":0,"forType":"num","forUnits":"minutes","x":2030,"y":180,"wires":[["2bf1e2f979441455"]]},{"id":"2bf1e2f979441455","type":"change","z":"92da3f90.2062d","name":"Define friendlyname","rules":[{"t":"set","p":"payload","pt":"msg","to":"data2.attributes.friendly_name","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":2240,"y":180,"wires":[["a75ab77c82fb9f37"]]},{"id":"454cac184e19551e","type":"comment","z":"92da3f90.2062d","name":"Revive z-wave module","info":"","x":1200,"y":60,"wires":[]},{"id":"5c29d263.09d2ac","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":false,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true},{"id":"86158645.d19e98","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]

It triggers whenever a node_status entities gets a problematic state. In that case it will fetch the parent device, for that parent device then get the list of entity_id’s, search amongst those for the ping entity, then call the ping entity. If that doesn’t help it will try many more times. If that still doesn’t solve it, you can at the end add your code to notify yourself.
ChatGPT helped me with generating the function node :slight_smile:

5 Likes

I also encountered this invalid slug zwave-ping problem, which I initially thought was related to a power outage bad SD card.

thanks to all for developing this code :grinning:

You sir made my day! Thanks :slight_smile:

1 Like

Glad that it can help you! It took me some time to make so this increases my return on investment :grinning_face_with_smiling_eyes:

Same here. I have several but the sensor shows 0.

If I run the template in dev tools it does show me all the ping buttons.
Leaving that open, going to zwavejs in another tab, pressing Ping there, I can see the result update. So it would appear the count is not updating?

Update: no, not that since entity_id is empty:

entity_id: []
unit_of_measurement: entities
friendly_name: Dead ZWave Devices

Strange that the template updates itself in dev tools but the sensor doesn’t.

As a test I added a trigger to the sensor for every 5 minutes. This successfully updated the entity_id list but the State value never changed from 0. Nor did the entity_id list change if I manually ping the nodes.
After another 5 minutes though, it did update the entity_id list and then it updated the State value to 4. At that time though I’d already pinged them all so the entity_id was empty.

Odd.

soooo, does anyone know the cause of the devices going dead? i implemented this because every once in a while, specially after some sort of reboot, a large number of my devices go dead. Not all, but a majority. sometimes the ping works, sometimes it doesn’t and i have to walk around the house pressing buttons on the devices for them to come back on. it’s really strange and there is no discernible pattern. Most reboots are just fine, just once in a while everything comes crashing down. I do have a 700 series stick, and have it patched to 7.17.2. Just trying to see if anyone has an idea on what’s going on…

1 Like

I have same problem. Patched to 7.17.2 and currently trying to implement ping script to mitigate as it keeps on occurring - well mainly for more distant z-wave devices (Aeotec ZW).

The problem is Z-wave 700 is hot garbage compared to Z-wave 500. Many will defend it but there’s really no excuse for the hoops we have to jump through just to get Z-wave 700 “working”.

The difficulty with 700 series stability lies in challenge of:

  1. Knowing the difference between the Z-wave JS integration, Z-wave JS addon, and Z-wave JS UI addon.
  2. Capturing logs at the time of failure
  3. Enabling and collecting the necessary logs.
  4. Having someone who actually knows what to look for within the logs determine the cause of the failure.

Step 0 is self explanatory. Spend any time in the #zwave Discord channel and you’ll know exactly why Step 0 exists.

Step 1 is a point of failure because by default, logging is not enabled at the necessary level regardless of the addon being used. In most cases, the initial report of dead nodes dies after someone asks, “What do the logs say?”

Step 2 is another point of failure. Unless you are running Z-waveJS UI from the get go, which many aren’t, by the time you experience step 1, you’ve subsequently been told to “Install JS UI” because logging is better/easier/faster.

Step 3, IMHO, is the single, most challenging point of failure because there are so few people who actually fit that description. Additionally, the people who do fit that description are making an educated guess based on your description. Much of their troubleshooting is reliant upon the strength of your communication abilities.

And if you fail to communicate your problem effectively, chances are you’ll end up being given one or more of the following summations:

  • RF Interference
  • Poor Network Construction
  • Lack of a USB extension cable/USB Hub
  • USB Passthrough is unstable (on everything except VMWare)

If you’re still having trouble, or if you’ve been met with any of the above, do yourself a favor and downgrade. If any of the above summations follow you to the 500 series stick, at least you’ll have eliminated Z-wave 700 as the cause. I’m willing to bet that won’t be the case.

But I digress…

To show that I’m not just a salty Z-wave user, I will contribute something useful to this thread. Here is an automation I created to notify me when a Z-Wave node goes dead. It includes a template that “should” provide the entity_id of the dead node, which should hasten the speed in which you can collect logs for sharing. I haven’t been able to test this automation as I haven’t had a dead node since I downgraded to Z-wave 500.

Please note - This automation assumes that you’ve set up one of the many notification services that exist for Home Assistant. I use Pushover.

alias: Zwave Node is dead!
description: ""
trigger:
  - platform: numeric_state
    entity_id: sensor.dead_zwave_devices
    above: "0"
    for:
      hours: 0
      minutes: 0
      seconds: 1
condition: []
action:
  - service: notify.pushover
    data:
      message: >-
        Zwave Node {{ state_attr('sensor.dead_zwave_devices','entity_id') }}
        just went dead or unavailable.
      title: Dead Zwave Node
mode: single

EDIT 1/23: For the first time since I downgraded back to Z-wave 500, my dead node notify automation kicked off. Here’s an example of what it looks like when a node goes dead.

As you can see, the notify automation now includes the node name. Hopefully this proves helpful to others.

3 Likes

Excellent job with this, worked perfectly. Well done to all involved :+1:t4:

Did you use a palette? i get “Unknown: calculator”

Yes I used this one: node-red-contrib-calc (node) - Node-RED
All that node does is to increase msg.limit by 1 so you can use that using existing nodes as well. I was just being lazy by using the simple calculator node :):slight_smile:

1 Like

Thanks, forgive me as I dont use node red often but i imported your flow and i deployed it and got a bunch of server config not found and supervisor token missing. However I already have my server setup for another flow that works fine.

I edited your nodes to try and change the server and noticed I now have 3 Home Assistant servers to choose from the drop down. I’m not sure how I ended up with 3 but I changed it to the first one that seems like the correct one. however, when I did that, the “wait until available” node changed what you had {original.data.entity_id}} to one of my actual entities (the first one spelling wise), which seems incorrect.

EDIT: it looks like the other 2 servers were for “home assistant add-on”, since I use docker and don’t use add-onss, i just deleted those 2.

So the main issue is I am not sure how to fix the “wait until available” node. it wont give me the option to put in your original code, it just makes me pick one of my entities from a drop down.

Yes I see what you mean.
In the below image the box to ender the Entity is a bit too smart as it will look for matching entities and wont accept anything else.
The reason I was able to enter {{original.data.entity_id}} is that I created this specific node already a few years ago when it wasn’t so smart and also accepted non-existing entities.
I would also like to understand what the technique is nowadays to get this too work :thinking:

the first time i tried it wouldnt let me type anything, for some reason it eventually let me and I was able to type your code snippet.

However, I’m still having issues. I’m not getting any kind of error messages but all but the first node show error. The debug is empty, so I have no idea how to go about figuring out the problem.