Battery level not updating in HA with Z-wave JS


Since a few months I migrated from OZW to Z-wave JS and I’m loving it so far. I re-paired all my devices and started fresh only to find that my battery levels aren’t reporting under Z-wave JS like they used to under Open Z-wave. I don’t see any updates of my battery state in the logbook, don’t have any errors in the log and have tried waking up my battery powered devices multiple times.

They function without problems (when the batteries aren’t dead) and I can see all Z-wave traffic in the logbook. The problem spans all of my battery powered devices from motion sensors to door/window sensors and a keypad from different brands (Zipato, Neo Coolcam and Vision Security).

When I pair a new device it will adopt the current battery level (mostly 100%) but after that it will never update. When a device dies it will sometimes update from 100% to 0%. When I then replace the battery it will stay at 0%. Opening the device, healing the device, healing the network, reloading the Z-Wave addon or restarting the entire system does not resolve the issue.

I’ve spend multiple hours going through logs and topics but it’s starting to drive me crazy, please release me out of my misery :wink:

What I’ve tried

  • Rebooting the system
  • Reloading the integration
  • Restarting Home Assistant
  • Repairing the device
  • Waking the device up manually multiple times
  • Heal the network
  • Re-Interview the device
  • Update everything to the latest version
  • Add new sensors from other brands

Platform & integrations

  • Hardware: Home Assistant Blue
  • Aeotec Z-Wave USB Stick
  • Version: core-2021.11.2
  • Installation Type: Home Assistant OS
  • Development: false
  • Supervisor: true
  • Docker: true
  • Python Version: 3.9.7
  • Operating System Family: Linux
  • Operating System Version: 5.10.75
  • CPU Architecture: aarch64
  • Z-wave JS: 0.1.47

I use the official Z-wave JS integration and I’m not running ZwaveJS through MQTT.


I use new and older batteries to see what would happen but this is the battery state for months now for all of these devices. I have no idea what the actual levels are.

It does say it updated the battery status 12 mins ago but it has a new battery for at least a month now and never went back to 100%


ps: my friends at work have the exact same setup as I and experience the same problems.

Many battery devices do not send unsolicited battery reports. You’ll need to create an automation that uses the zwave_js.refresh_value with the battery entities you want to update. Trigger based on time, such as once a week, once a month, etc. The battery refresh will be queued in the driver, and when the battery devices wake up it will refresh the battery value.

Z-Wave JS doesn’t refresh battery values on its own, although it’s been requested. As for why it worked on legacy zwave, OZW does a refresh of all values when the network starts up. Since the network starts and stops with legacy zwave when HA restarts, you were just getting these battery updates as a side effect. Z-Wave JS is much less “poll happy” and won’t refresh these values on startup, and Z-Wave JS is not dependent on HA restarts.

If you don’t think this is the case, and want to really confirm if any battery updates are happening, you’ll need to look at long-term debug driver logs. This isn’t possible with the Z-Wave JS addon. You’d have to switch to zwavejs2mqtt.

It does say it updated the battery status 12 mins ago but it has a new battery for at least a month now and never went back to 100%

I think this time is also affected by other conditions, like when HA restarted or when Z-Wave JS restarted. It doesn’t necessarily reflect a real message from the device.


Any idea how to set up the automation, declaring the list of Z-Wave entities, without listing every Z-Wave entity with battery manually?

  - data_template: 
      entity_id: |
        {{ (Get-all-the-Z-Wave-entities-with-battery....????
          | list 
        )[0].entity_id }}
    service:  zwave_js.refresh_value

Thanks a lot for explaining how and why battery levels need to be called manually! I wasn’t aware of that. I’ve already tried the ZWAVE_JS.REFRESH_VALUE multiple times in the developer tools by calling it like this:

service: zwave_js.refresh_value
  entity_id: sensor.office_multisensor_battery_level
  refresh_all_values: true

I know this battery is new and should report 100% but its still stuck at 45% and isn’t updated after calling the zwave_js.refresh_value command. Even when the device detects motion afterwards or when I open the device and manually wake it up, the battery level still won’t change :frowning:

So I understand now that I need to manually call the devices to report the right battery value and that the commands get queued until that device reports again. So now my goal is to get that actually working. Any idea on why the device isn’t sending battery reports after calling the zwave_js.refresh_value?

Eventually the value did refresh when I took the battery out of the device and put it back in! Even though this isn’t a solution it does prove your theory and did update my battery. So now I have to make a script that will call all battery powered device every 24 hours and refresh the values and then find an alternative for opening and waking up the battery powered device.

If you have any advice on this it would be highly appreciated :slight_smile:


I ended up with making a group in my groups.yaml through the editor for all battery entities.

  name: Battery Level Entity Group

After that I made an automation to call the zwave_js.refresh_value on that group entity with a trigger on time for every 24 hours.

- id: '1337'
  alias: Virtual Refresh Battery Levels
  description: Poll all battery powered devices to update their battery levels
  - platform: time
    at: 00:00:00
  condition: []
  - service: zwave_js.refresh_value
      entity_id: group.battery_level_entity_group
  mode: single

I noticed my battery powered devices will eventually update their value as explained by @freshcoast

With all this combined I think my issue is solved. Thanks for this awesome community and Freshcoast in particular!

1 Like

I created the same group with replacing values of my devices and added automation. Ran the automation manually but the battery percentage did not change. But then read the comment that you tagged about it will update when the device wakes up, it is a flood sensor so I tried to shake it to make it active and it made a sound that the device moved but the battery percentage did not update. Before doing this I re-interviewed the devices and it shows an accurate battery in the Z wave panel but when I try to access the device in Lovelace or Devices using the integration UI it shows 0%. Any idea on what can be wrong?

It started working after I manually woke up the device.

I’m not having any luck making this work with my devices :frowning: Just wondering if any of you are using Aeon water leak sensors in your setups?

Same… I know when there low, because suddenly motion is not working anymore… haha

I had a similar issue and went down the refresh_value route.

I created an automation triggered by any door opening (my batteries are door sensors) and then for action I got the device for the triggering entity and then refreshed each entity for the device. Not ideal, but it seemed to work

  - repeat:
      count: '{{ device_entities(device_id(trigger.entity_id)) | count }}'
      - service: zwave_js.refresh_value
          entity_id: '{{ device_entities(device_id(trigger.entity_id))[repeat.index
            -1] }}'
          refresh_all_values: true

Thought I’d share if anyone is interested.


I have three battery powered smoke detectors which I’ve only hac for about a moth, and untill I saw this thread I thought the battery levels should update by itself, but now I know better.

I have this automation:

description: ''
  - platform: time
    at: '00:00:00'
condition: []
  - service: zwave_js.refresh_value
      entity_id: sensor.smoke_alarm_sensor_battery_level
  - service: zwave_js.refresh_value
      entity_id: sensor.smoke_alarm_sensor_battery_level_2
  - service: zwave_js.refresh_value
      entity_id: sensor.smoke_alarm_sensor_battery_level_3
mode: single

And when I check the the zwave log, which I’ve set to log level verbose, it looks like this. I gues sthat means it’s working as it should:

2022-04-08T07:44:40.122Z CNTRLR « [Node 003] received wakeup notification
2022-04-08T07:44:40.124Z CNTRLR   [Node 003] The node is now awake.
2022-04-08T07:44:40.156Z SERIAL » 0x01150013030e9f032b00aca13d33b33768fb3529250668                    (23 bytes)
2022-04-08T07:44:40.158Z DRIVER » [Node 003] [REQ] [SendData]
                                  │ transmit options: 0x25
                                  │ callback id:      6
                                    │ sequence number: 43
2022-04-08T07:44:40.161Z SERIAL « [ACK]                                                                   (0x06)
2022-04-08T07:44:40.167Z SERIAL « 0x0104011301e8                                                       (6 bytes)
2022-04-08T07:44:40.169Z SERIAL » [ACK]                                                                   (0x06)
2022-04-08T07:44:40.170Z DRIVER « [RES] [SendData]
                                    was sent: true
2022-04-08T07:44:40.185Z SERIAL « 0x0107001306000002ef                                                 (9 bytes)
2022-04-08T07:44:40.186Z SERIAL » [ACK]                                                                   (0x06)
2022-04-08T07:44:40.188Z DRIVER « [REQ] [SendData]
                                    callback id:     6
                                    transmit status: OK
2022-04-08T07:44:40.213Z SERIAL « 0x0115000400030f9f03a900acac14ee46a25155d16ca8d8                    (23 bytes)
2022-04-08T07:44:40.222Z CNTRLR   [Node 003] [~] [Battery] level: 100 => 100                        [Endpoint 0]
2022-04-08T07:44:40.225Z CNTRLR   [Node 003] [~] [Battery] isLow: false => false                    [Endpoint 0]
2022-04-08T07:44:40.227Z SERIAL » [ACK]                                                                   (0x06)
2022-04-08T07:44:40.231Z DRIVER « [Node 003] [REQ] [ApplicationCommand]
                                    │ sequence number: 169
                                        level:  100
                                        is low: false
2022-04-08T07:44:41.242Z CNTRLR » [Node 003] Sending node back to sleep...

I’m not sure this is working for me. Would appreciate any insight anyone could share. Running HA v2022.4.2 and zwavejs2mqtt v6.7.0.

Though the Integrations menu in HA, I set the Z-Wave JS logs to “silly”. When I call the following service through Developer Tools → Services

service: zwave_js.refresh_value
  entity_id: sensor.laundrydoor_sensor_battery_level

I only see the following in the logs:

Subscribed to Z-Wave JS Log Messages…
Log Level changed to: Silly
2022-04-11T15:20:49.665Z SERIAL « 0x010b0004000b032001ffaa008c                                        (13 bytes)
2022-04-11T15:20:49.674Z SERIAL » [ACK]                                                                   (0x06)
2022-04-11T15:20:49.678Z DRIVER « [Node 011] [REQ] [ApplicationCommand]
                                      target value: 255
2022-04-11T15:20:49.683Z CNTRLR   [Node 011] treating BasicCC::Set as a report
2022-04-11T15:20:49.685Z CNTRLR   [Node 011] [~] [Basic] currentValue: 0 => 255                     [Endpoint 0]
2022-04-11T15:20:49.717Z SERIAL « 0x01130004000b0b7105000000ff0616000000aa00d9                        (21 bytes)
2022-04-11T15:20:49.720Z CNTRLR   [Node 011] [~] [Notification] notificationMode: "push" [Endpoint 0] [internal]
                                   => "push"
2022-04-11T15:20:49.722Z SERIAL » [ACK]                                                                   (0x06)
2022-04-11T15:20:49.725Z DRIVER « [Node 011] [REQ] [ApplicationCommand]
                                      notification type:   Access Control
                                      notification status: 255
                                      notification state:  Window/door is open
2022-04-11T15:20:49.729Z CNTRLR   [Node 011] [~] [Notification] Access Control[Door state]: 23 => 2 [Endpoint 0]

2022-04-11T15:20:56.917Z SERIAL « 0x010b0004000b03200100a80071                                        (13 bytes)
2022-04-11T15:20:56.919Z SERIAL » [ACK]                                                                   (0x06)
2022-04-11T15:20:56.921Z DRIVER « [Node 011] [REQ] [ApplicationCommand]
                                      target value: 0
2022-04-11T15:20:56.924Z CNTRLR   [Node 011] treating BasicCC::Set as a report
2022-04-11T15:20:56.926Z CNTRLR   [Node 011] [~] [Basic] currentValue: 255 => 0                     [Endpoint 0]
2022-04-11T15:20:56.969Z SERIAL « 0x01130004000b0b7105000000ff0617000000a800da                        (21 bytes)
2022-04-11T15:20:56.971Z CNTRLR   [Node 011] [~] [Notification] notificationMode: "push" [Endpoint 0] [internal]
                                   => "push"
2022-04-11T15:20:56.972Z SERIAL » [ACK]                                                                   (0x06)
2022-04-11T15:20:56.974Z DRIVER « [Node 011] [REQ] [ApplicationCommand]
                                      notification type:   Access Control
                                      notification status: 255
                                      notification state:  Window/door is closed
2022-04-11T15:20:56.978Z CNTRLR   [Node 011] [~] [Notification] Access Control[Door state]: 22 => 2 [Endpoint 0]

This was me calling the service, then opening and closing the door. As far as I can tell, there is no battery refresh happening. Am I wrong in this? Any insights?


Opening and closing a door will not wakeup the node. Check your manual for the instructions.

Thank you. I was able to manually wake up each node and have now set their “wakeupinterval” to 7200. Hopefully this will work now.

I can get the list of entity IDs that represent Z-Wave JS battery entities but I’m not sure how best to call zwave_js.refresh_value on them

{% set ns = namespace(zw_devices=[], battery_entities=[], result=[]) %}
{% set ns.battery_entities = states.sensor | selectattr('attributes.device_class', 'eq', 'battery') | list %}
{%- for device_id in ns.battery_entities | map(attribute='entity_id') | map('device_id') | unique | reject('eq', none) %}
  {%- if (device_attr(device_id, 'identifiers') | list | selectattr('0', 'eq', 'zwave_js') | first ) %}
    {%- set ns.zw_devices = ns.zw_devices + [device_id] %}
  {%- endif %}
{%- endfor %}
{%- for entity_id in ns.battery_entities | map(attribute='entity_id') %}
  {%- if device_id(entity_id) in ns.zw_devices %}
    {%- set ns.result = ns.result + [entity_id] %}
  {%- endif %}
{%- endfor %}
{{ ns.result }}

Based on this pattern:

okay, so - what the blazes is going on with my sensors?
I’ve got these ZP3111 (zooz 4-in-1, monoprice rebranded) sensors. several of them show “0%” battery.

I did a force update, and they responded with 0%, which was weird because they are functional - they correctly reported awake status, motion, temp, etc. I replaced the battery and now it responds as 100% battery but does not update the value in Home Assistant.

I can manually modify it in developer tools, but then I can force it to re-read, and it gets reset back to zero, despite being able to see the values at 100% in the logs.

2022-05-02T20:36:40.610Z SERIAL « 0x0109000400040380036412                                            (11 bytes)
2022-05-02T20:36:40.612Z CNTRLR   [Node 004] [~] [Battery] level: 100 => 100                        [Endpoint 0]
2022-05-02T20:36:40.614Z CNTRLR   [Node 004] [~] [Battery] isLow: false => false                    [Endpoint 0]
2022-05-02T20:36:40.616Z SERIAL » [ACK]                                                                   (0x06)
2022-05-02T20:36:40.618Z DRIVER « [Node 004] [REQ] [ApplicationCommand]
                                      level:  100
                                      is low: false

I’ve double-checked the device ID, and I’ve given it almost 24 hours to update.
What gives?

I have the same problem with the same device.

i have also a issue with the fibaro motion sensor , reading the correct battery level
2 of them are always 100% , till the automations are not working correctly the battery is empty
And 1 of them is really stepping down from 100 to 80 and 70 but if it is really a correct value

i thought it is the firmware of the motion sensors. but that is not the issue .
Is this really working ?
Z-Wave JS: Refresh value(s) of a Z-Wave entity

i tried the automation from “gberg”
looks like only one sensor is responding it had lowered to 66%
the others ones are still 100%

when the sensors are awake , i see in the logging that the battery status is send
One is 66%, and the two others are 100% . (always)

strange is the bug than at the fibaro sensor itself , and not at zwave JS??

I’ve crerated an automation in Node Red to refresh the battery levels:

Here’s the code:

[{"id":"f02f9b9db785b34a","type":"api-call-service","z":"92da3f90.2062d","name":"refresh battery level","server":"5c29d263.09d2ac","version":5,"debugenabled":false,"domain":"zwave_js","service":"refresh_value","areaId":[],"deviceId":[],"entityId":["{{payload.entity_id}}"],"data":"{\"refresh_all_values\":\"true\"}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":630,"y":4400,"wires":[[]]},{"id":"2d64fe73353ee48c","type":"ha-get-entities","z":"92da3f90.2062d","name":"Get all battery entities","server":"5c29d263.09d2ac","version":0,"rules":[{"property":"attributes.device_class","logic":"is","value":"battery","valueType":"str"},{"property":"state","logic":"lte","value":"100","valueType":"num"},{"property":"attributes.friendly_name","logic":"is_not","value":"Ups Battery Charge","valueType":"str"},{"property":"attributes.friendly_name","logic":"is_not","value":"mobile Battery Level","valueType":"str"}],"output_type":"split","output_empty_results":false,"output_location_type":"msg","output_location":"payload","output_results_count":1,"x":420,"y":4400,"wires":[["f02f9b9db785b34a"]]},{"id":"e922e823e77ff3ed","type":"inject","z":"92da3f90.2062d","name":"01:00","props":[{"p":"payload"}],"repeat":"","crontab":"00 01 * * *","once":false,"onceDelay":"60","topic":"","payload":"","payloadType":"date","x":250,"y":4400,"wires":[["2d64fe73353ee48c"]]},{"id":"5c29d263.09d2ac","type":"server","name":"Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":false,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30}]

Trouble is that it doesn’t seem to work, all are still reporting as 100%:

1 Like