Resolve Z-Wave Node ID from Entity

I would like to resolve a ZWave Node ID given it’s HomeAssistant Entity name.

Zwave JS / JSUI

After reviewing the forums I found this template which was offered up by others to answer a similar problem

{% set ns = namespace(devices=[]) %}
{%- for device_id in states | map(attribute='entity_id') | map('device_id') | unique | reject('eq', none) %}
  {%- set identifiers = device_attr(device_id, 'identifiers') | list |  selectattr('0', 'eq', 'zwave_js') | selectattr('1', 'search',  '^([0-9]+)-([0-9]+)$') | list | first | default %}
  {%- if identifiers %}
    {%- set node = identifiers[-1].split('-')[-1] | int %}
    {%- set ns.devices = ns.devices + [(node, device_entities(device_id))] %}
  {%- endif %}
{%- endfor %}
{%- for node, entities in ns.devices | sort(attribute='0') %}

  {{ node }}:
  {%- for entity in entities %}
    • {{ entity }}
  {%- endfor %}
{% endfor %}

That template is CLOSE - It results in a formatted list of nodes, each with its associated entities as follows:

(partial list)

6:
    button.living_room_lights_ping_2
    light.living_room_lights
    sensor.living_room_lights_node_status


  7:
    sensor.back_porch_light_node_status
    light.back_porch_light
    sensor.back_porch_light_humidity
    button.back_porch_light_ping


  8:
    sensor.back_porch_fan_node_status
    fan.back_porch_fan
    button.back_porch_fan_ping

I could modify this template and at the point where it starts looping through a given node, I COULD check each name and compare it to the one I’m looking for and if its a match - return the result. It just SEEMS messy and when I run this template, it takes a second or two - because I have a LOT of Z-Wwave entities. (Over 90 unique Z-Wave devices)

If I read the template correctly (I’m still very novice with templates) we have the device list and the nodes at the end of the for on line 8/9 Is there a way to modify the select on line 9 to just dump out a node number if we find a given target entity ID in the list?

Preferred result - given one string input - full entity ID, produces one string representation of a number - Z-Wave Node ID or NULL if not found.

In my data above, ‘fan.back_porch_fan’ would yield ‘8’

Basically I’m tired of having to update all of my ZwaveJS service based automations and Node Red flows every time I swap out a device… Took me three days to realize I needed to edit a flow with the new node ID when I swapped out a lock that died earlier this week.

Thoughts?

If you use ZWaveJS UI there is an option called Replace Failed Device. It allows you to swap a device and it keeps that same NODE ID. You can find it in the same place as the Inclusion button. It will try and ping the node first to see if its alive and if it doesn’t respond then it will let you replace the device.

Let me clarify -The node could not be replaced - there were other extraneous circumstances. This is not a valid workaround. I am looking to improve the automations to be self sufficient and not care. Thank you though. :slight_smile:

1 Like

@NathanCu, were you able to find a way to do it? My case is reversed, needing to get entity_id from either node_id or device_id. I’m making an event wrapper to receive all of the zwave double-click events from my GE/Jasco switches and translate them to a new event with entity_id and a direction (up or down). It will simplify triggers for my other automations.

@NathanCu, I found a way to do what I wanted. It took me hours to figure it out, but finally ended up with this to get a single entity_id from a device_id within a subset of device types:

{{ 
  'a5dce3f6611b39fea9b154f8d3a3dec0'
  |device_entities
  |select('match', 'light|fan|switch')
  |first 
}}

In your case, node_id is a bit more involved but I found a way to do that based on your original example and applying what I learned getting my case to work:

{{
  ( 
    'light.hall_light'
    |device_id
    |device_attr('identifiers')
    |selectattr('0', 'eq', 'zwave_js')
    |selectattr('1', 'search', '^([0-9]+)-([0-9]+)$')
    |map(attribute='1')
    |first
  ).split("-")[-1]
  |int
}}

No idea how much of the syntax you know, but this may be handy for others so I’ll break it down:

  • |device_id → converts entity_id to device_id
  • |device_attr('identifiers') → gets device identifiers, which is a list of two-element lists
    • example: {('zwave_js', '3882907366-3-99:18756:12344'), ('zwave_js', '3882907366-3')}
  • |selectattr('0', 'eq', 'zwave_js') → filters identifiers where first element is ‘zwave_js’
  • |selectattr('1', 'search', '^([0-9]+)-([0-9]+)$') → filters identifiers where second element is a two-part hyphenated number
  • |map(attribute='1') → selects just the hyphenated number value from the identifiers
  • |first → we only need the first one
  • (...).split("-")[-1] gives us the node number on the right side of the hyphen (negative indexes start from right end of the split)
  • |int → does what it says: converts resulting string to integer

I learned a lot while figuring this out, and your question and example gave me the critical clues I needed to get there…thanks!