Skip to content

Instantly share code, notes, and snippets.

@jasonk
Last active September 10, 2022 17:32
Show Gist options
  • Save jasonk/312020b4c34fd2c553bb5701eed00806 to your computer and use it in GitHub Desktop.
Save jasonk/312020b4c34fd2c553bb5701eed00806 to your computer and use it in GitHub Desktop.
Home Assistant zwave firmware update script

The 2022.9 release of Home Assistant add a much-anticipated integration for doing firmware updates on z-wave devices. I immediately rushed to update the 36 devices it said there were updates available for. Then I woke up the next morning to find it telling me about updates for 35 of those devices...

It's a brand new feature, so I'm not too worried about it being a little rough around the edges at the moment, for now here is what I've found:

  • It does work, you just have to be careful about it
  • When you start the update from the UI it will show as being updated immediately. Don't be fooled! It's started, but it's nowhere near done.
  • Z-wave has it's benefits, but bandwidth is not one of them. It takes quite some time to send a firmware update over the z-wave network to a device (around 20 minutes or the ones where I've timed it).
  • If you start multiple updates they will all try to send update packets at the same time and flood your z-wave network, and very likely all fail, so you should only do one at a time.
  • Doing one at a time isn't as easy as you would hope, because I suspect the progress monitoring for this kind of update doesn't actually work (at least the "in_progress" attribute on the update entity stays false the entire time the update is being sent to the device.

Below are two scripts I threw together to solve this problem for me, hopefully they help somebody else out too.

The update-zwave-firmware script requires hass-cli to find available updates and to start the install process. After starting one it attempts to run the monitor-zwave-firmware-upgrade script to monitor the progress and wait for it to complete.

For the monitor-zwave-firmware-update script to work it has to run on your Home Assistant instance (or somewhere else that it can run the docker logs command in order to get the zwave-js logs to see the progress

  • SSH access to your Home Assistant instance in order to run docker logs (which is the only way I've found to determine when the install is complete0

When you run it with no arguments it will just give you a list of the update.*_firmware entities that are currently in an on state. When run with one of those entities as an argument it will start the update process then watch the logs and output progress information as the install happens. When it gets a log indicating the the install is complete (or failed) then it will exit.

NOTE: It doesn't do any validation on the update entity you give it. If you try to use it with an entity that is going to start an update on something that isn't handled by zwave-js, then it will start the update fine, but it won't get any log messages that it recognizes so it will just seem to hang forever after that.

#!/bin/bash
# Monitor firmware updates in Home Assistant
# https://gist.github.com/jasonk/312020b4c34fd2c553bb5701eed00806
set -euo pipefail
while IFS= read -r LINE; do
LINE="${LINE##* CNTRLR }"
if [[ $LINE =~ Starting\ firmware\ update ]]; then echo "$LINE"; fi
if [[ $LINE =~ Sending\ firmware\ frag ]]; then
echo "$LINE ===> $(awk '{ print int( 100 * $7/$9 ) "%" }' <<<"$LINE")"
fi
if [[ $LINE =~ Firmware\ update\ completed ]]; then
echo "$LINE";
break;
fi
done < <(docker logs --tail=0 --follow addon_core_zwave_js)
#!/bin/bash
# Initiate firmware updates in Home Assistant
# https://gist.github.com/jasonk/312020b4c34fd2c553bb5701eed00806
set -euo pipefail
MYDIR="$(dirname "$(realpath -P "$0")")"
# The path to the monitor-zwave-firmware-update script, in case you
# don't have them in the same directory
MONITOR="$MYDIR/monitor-zwave-firmware-update"
# If not running the scripts on your Home Assistant instance, then
# provide the information necessary to ssh to it to get the docker
# logs
SSH_ARGS="[email protected]"
# If no arguments are provided, list the pending updates
if ! (( $# )); then
hass-cli --columns=state,entity_id state list 'update.*_firmware' |
awk '$1 == "on" { print $2 }'
exit
fi
for ENTITY; do
hass-cli service call update.install --arguments "entity_id=$ENTITY"
if [ -n "$SSH_ARGS" ]; then
# If $SSH_ARGS is provided then use that to login to the instance
# and monitor progress
ssh $SSH_ARGS bash -s < "$MONITOR"
else
# Otherwise assume we can run the monitor locally
"$MONITOR"
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment