ZWave-JS missing "last received" attribute?

I have also noticed that battery levels reported by zwave devices is often wrong. Keeping track of the last active time reported by zwavejs seems like the best workaround. I ended up writing a custom mqtt sensor that produces a markdown report and list of devices that are past a certain threshold or if the device uses a battery. Enjoy!

configuration.yaml

mqtt:
  sensor:
    - name: Inactive Zwave Battery Devices
      state_topic: "zwave/_CLIENTS/ZWAVE_GATEWAY-zwavejs2mqtt/api/getNodes"
      value_template: "{{ now() }}"
      json_attributes_topic: "zwave/_CLIENTS/ZWAVE_GATEWAY-zwavejs2mqtt/api/getNodes"
      json_attributes_template: |-
        {%- set setting_find_older_than = timedelta(days=2) %}
        {%- set settting_show_battery_only = true %}
        {%- set setting_none_timestamp = 9000000000000000 %}

        {%- set data = namespace(from_ha=[], node_info_list=[], markdown="") %}

        {# Get HA data about the zwave devices. #}
        {%- set device_ids = integration_entities('zwave_js') | map('device_id') | unique | reject('eq',None) | list %}
        {%- for device_id in device_ids %}
          {%- set node_id = device_attr(device_id, 'identifiers') | list | last | list | last | regex_replace("^[0-9]+-", "") | regex_replace("-.+", "") %}
          {%- set data.from_ha = data.from_ha + [namespace(
            device_id = device_id | string,
            node_id = node_id | string
          )] %}
        {%- endfor %}

        {%- for result in value_json.result %}
          {# Find the latest activitiy time. #}
          {%- set ns = namespace(times=[], device_id=None, has_battery=false) %}
          
          {%- if "values" in result %}
            {%- for key, value in result["values"].items() %}
              {%- if "commandClassName" in value and value["commandClassName"] is not none and value["commandClassName"] | lower == "battery" %}
                {%- set ns.has_battery = true %}
              {%- endif %}
            
              {%- if "lastUpdate" in value and value["lastUpdate"] is not none %}
                {%- set ns.times = ns.times + [value["lastUpdate"] / 1000] %}
              {%- endif %}
            {%- endfor %}
          {%- endif %}

          {%- if "lastActive" in result and result["lastActive"] is not none %}
            {%- set ns.times = ns.times + [result["lastActive"] / 1000] %}
          {%- endif %}

          {%- if ns.times | length == 0 %}
            {%- set ns.times = ns.times + [setting_none_timestamp] %}
          {%- endif %}

          {%- if ns.times | length > 0 and ((settting_show_battery_only is false) or (settting_show_battery_only and ns.has_battery)) %}
            {%- set last_activity_timestamp = ns.times | sort | last %}
            {%- set last_activity_dt = as_datetime(last_activity_timestamp | string) %}
            {%- if last_activity_timestamp == setting_none_timestamp or (last_activity_dt is not none and now() - last_activity_dt > setting_find_older_than) %}
              {%- set name = result.name | trim %}
              {%- set manufacturer = result.manufacturer | trim %}
              {%- set product_description = result.productDescription | trim %}
              {%- set location = result.loc | trim %}
            
              {# Find the HA device id. #}
              {%- for ha_item in data.from_ha %}
                {%- if ha_item.node_id|string == result.id|string %}
                  {%- set ns.device_id = ha_item.device_id %}
                {%- endif %}
              {%- endfor %}
            
              {%- set data.node_info_list = data.node_info_list + [{
                "id": result.id,
                "name": name if name | length > 0 else None,
                "manufacturer": manufacturer if manufacturer | length > 0 else None,
                "product_description": product_description if product_description | length > 0 else None,
                "location": location if location | length > 0 else None,
                "last_activity": last_activity_timestamp,
                "device_id": ns.device_id
              }] %}
            {%- endif %}
          {%- endif %}
        {%- endfor %}

        {# Create the output object and markdown format. #}
        {%- set data.markdown = data.markdown + "| Name | Location | Last Activity |\n" %}
        {%- set data.markdown = data.markdown + "| ---- | -------- | ------------- |\n" %}
        {%- if data.node_info_list | length > 0 %}
          {%- for node_info in data.node_info_list | sort(attribute="last_activity", reverse=True) %}
            {%- set name_value = node_info.product_description if node_info.name is none else node_info.manufacturer if node_info.name is none else node_info.name %}
            {%- set device_id = node_info.device_id %}
            {%- set activity_dt = as_datetime(node_info.last_activity | string) %}
          
            {%- set name_cell = name_value if device_id is none else "[" + name_value + "](/config/devices/device/" + device_id + ")" %}
            {%- set location_cell = node_info.location | default("Unknown") %}
            {%- set activity_cell = None if node_info.last_activity == setting_none_timestamp else relative_time(activity_dt) %}
          
            {%- set name_cell_value = "Unknown" if name_cell is none else name_cell %}
            {%- set location_cell_value = "Unknown" if location_cell is none else location_cell %}
            {%- set activity_cell_value = "Unknown" if activity_cell is none else activity_cell %}
          
            {%- set data.markdown = data.markdown + "| " + name_cell_value + " | " + location_cell_value + " | " + activity_cell_value + " |\n" %}
          {%- endfor %}
        {%- else %}
          {%- set data.markdown = data.markdown + "| No devices |\n" %}
        {%- endif %}

        {{ {"markdown": data.markdown, "node_info_list": data.node_info_list } | to_json }}

Automation to refresh the data occasionally:

alias: Reload zwave node info
description: >-
  Used by the custom mqtt sensor sensor.inactive_zwave_devices. See
  configuration yaml for details.
trigger:
  - platform: time
    at: "00:00:00"
  - platform: homeassistant
    event: start
condition: []
action:
  - service: mqtt.publish
    data:
      topic: zwave/_CLIENTS/ZWAVE_GATEWAY-zwavejs2mqtt/api/getNodes/set
      payload: "{ \"args\": [] }"
mode: single