Unable to update Black Switch firmware using Hubitat

I have several LZW-30 black on/off switches running firmware 1.11 that I am struggling to update to the latest firmware using my hubitat C-5 hub. I have tried both the Binary Firmware Updater and the legacy one. I am using https://files.inovelli.com/firmware/LZW30/Beta/LZW30_1.22.otz as my firmware link to download.

With the binary firmware updater, I select target 0, and it uploads the firmware to the device. I see debug logs like
“Got request for fragment #:xxx packing report and sending” for fragments 1 through 2339. For fragment 2340 (which I think is the last fragment), I see 10 log lines of “Got request for fragment #:2340 packing report and sending”, each almost exactly 12 seconds apart, followed by a SwitchBinaryReport with the current value. While the lines about fragment 2340 are being logged, the device handler says “Sent last fragment. Waiting on device…”, but the device shows no sign of actually installing the firmware. It just stays that way for a half hour or more.

When I have tried it with the legacy firmware updater, I usually get a “please wake up your sleepy device” error message (which doesn’t make sense since the switch is mains powered, not battery). Although I tried it just now with the legacy updater and got exactly the same failure mode as with the binary updater, so perhaps that’s unrelated to the issue.

I have successfully used my hub to update the firmware on several LZW31-SN and two LZW-36. I also managed to do it for my one LZW30-SN, although I remember that it was not straightforward; it failed many times before it eventually succeeded. It was a while ago, though, so I don’t remember the details.

Any ideas of what’s going wrong?

One thing I had to do (on a few BLK switches) was pull the air gap, start the OTA update and push the air gap back in. When it finished booting up, it would start the firmware update. Note I was using PC Controller method and not from Hubitat.

1 Like

I figured it out! It smelled like an off-by-one error, and indeed that’s what was happening. There’s a bug in the hubitat firmware update tool that is only triggered when the size of the firmware file is one byte larger than an even multiple of the fragment size. I fixed the bug and now it works.

Here’s what I figured out:

  • The firmware size of the LZW30 1.22 “beta” firmware as reported by the legacy firmware update tool is “firmware total bytes: 93601”
  • The max fragment size is 40 bytes.
  • 2340 * 40 = 93600, so the last fragment in the 1.22 firmware should be fragment 2341, with the last 1 byte of data in it.
  • The firmware size of the LZW30 1.20 “production” firmware is 93600 bytes
  • I was able to successfully flash the 1.20 firmware using the legacy firmware updater tool.

The bug is present in both versions of the firmware updater, in the void zwaveEvent(hubitat.zwave.commands.firmwareupdatemdv3.FirmwareUpdateMdGet cmd) method, where it’s trying to figure out if it’s sending the last fragment.

    if (lastByte >= byteBuffer.size()-1) {
        lastReport=true
        lastByte = byteBuffer.size()
    }

This stood out to me because generally you use if (foo > bar.size()-1) OR if (foo >= bar.size()) as a stopping condition when foo is zero-indexed and .size is one-indexed. Indeed, in this case, the code incorrectly sets lastReport=true for report 2340.

The next part is my inference, not what I can actually see, but I think it’s pretty likely what’s happening. Because the zwave command for the last fragment is a little different, setting lastReport=true for fragment 2340 results in a command that has a different header than what the switch is expecting (since the switch knows to expect 93601 bytes, which require 2341 fragments). So the switch doesn’t acknowledge it, and the firmware updater retransmits after 12 seconds. When that fails 10 times in a row, it times out.

The fix is simple: remove the -1 from that condition. Once I did that I was able to upload firmware 1.22 without problems. I’ll open a github PR for it.

This is my absolute favorite thing about open source software. There was a bug, and I could find and fix it myself by looking at the code. I love it when this happens.

3 Likes

@bcopeland in case you see the ping here more prominently than the one on github, I opened Fix off-by-one error when checking for last fragment by mbbush · Pull Request #18 · djdizzyd/hubitat · GitHub

tried this, and still getting stuck on: Current States

  • firmwareUpdateProgress : Please wake up your sleepy device
  • lockedBy : None
  • currentFirmwareVersion : null
  • firmwareUploadPercent : null
  • manufacturerId : null
  • firmwareTarget : null

Did you try the air gap method @harjms mentioned? I recall needing to do this for some of my devices when using the hubitat tool with my C-5.

Yes. And also clicking “Get Version Report” does not work either.

The only thing I can think of is either a) removing the device from the Zwave network and including it back in (maybe there was a hiccup on initial inclusion?). I would think Get Version would work if it’s talking to the network normally. Or b) get an external USB Zwave stick and use PC Controller to upgrade the software.

I’ve never used the firmware updater from Hubitat, so I’m not real familiar with it. I bought a ZWave stick because originally Hubitat didn’t have @bcopeland 's updater tool as part of the ecosystem when Inovelli started with the firmware updates.

The sleepy device issue is a pain. My recollection is that when I ran into it, I would have to try the air gap trick several times before I could get the timing right. I’d encourage you to try several times before giving up.

Sometimes the sleepy device issue just doesn’t happen. I have no idea why.

Turn on debug logging, which should allow you to see all the zwave commands sent to/from the device. When you click Get Version Report the hub should send a command to the device requesting a version report, then the device should send back the version report, then the driver should update the version that is displayed. Which of these steps is failing?

If Get Version Report isn’t working, it’s possible there’s some other issue with the zwave connection. You should get that working before trying the firmware update again, as whatever the issue is is likely to affect that as well.

I have debug logging on in the zwave updater, I go into the Logs tab on hubitat and then stay in the Current Logs tab, and then click get version report, and no events happen