Writing a device updater? Seriously consider WebUSB!

Just like Wikipedia, anyone can contribute to the source code of our calculator and share improvements with the community.

But for everyone to actually use those improvements, we had to make sure our calculator’s firmware could be upgraded super easily. Since over-the-air updates are out of the question, we had an interesting journey finding the best solution, and we would like to share our findings with you.

Our requirements

  1. Updating should work from as many computers and operating systems as possible.
  2. Users should not have to install a specific software just to update their calculator.
  3. We would like to write as little code as possible. Less code, fewer bugs.

What didn’t work

Before finding a good solution, we tried different alternatives. Each had their shortcomings.

Using a native application

This is by far the most common strategy, but unfortunately it only matches one requirement out of three.

  • Users have to install a specific app just to update their machine. This may not work for some users who don’t have admin rights on their machine.
  • Painful to distribute. There are so many different binary platforms it’s really hard to take care of all of them.
  • Platform specific code will be required. Even though there are some cross-platform solutions such as Qt and libusb, you will need to test and debug on every single OS. And even if libusb does a good job, the USB stacks of Linux, macOS and Windows are different enough that you will have a lot of platform-specific issues.
  • Meta overflow: users will now need to update the updater.

Using a web app coupled with an USB-to-HTTP bridge

A compromise is to use a web application for the user interface, and a small UI-less native component to handle USB communications. That component exposes an HTTP API that can be consumed by the web application. That’s an option we used for a while but we eventually decided to move away from it.

  • HTTPS is out because it’s not possible to ship a valid certificate for localhost.
  • It’s still painful to distribute, and you still may need to update the bridge (albeit less frequently than a GUI app).

WebUSB to the rescue

WebUSB is a set of functions that that let you do USB communications in JavaScript straight from a web browser. It perfectly matches all our requirements:

A perfect match…

  1. It is available on a wide range of devices and operating systems (Android, Windows, macOS and Linux)
  2. It works out-of-the-box on most operating systems
  3. We only need to write one JavaScript codebase for all devices and operating systems. Couldn’t get any smaller!

…which is not magic though

  • Technically WebUSB is an open standard. But only Chrome implements this specification at the moment, so end-users may need to switch browser to update their device.
  • It requires a driver on Windows. This can be avoided for some versions of Windows if you can add special USB descriptors on your device. Anyway, it’s not such a big deal though because this is a code-less driver. It’s pretty much just a configuration file that tells Windows “hey, if you every see a NumWorks calculator, then just bind it to WinUSB so that Chrome can talk to it.”
  • iOS devices are not supported, but those are so locked down it was a lost battle anyway.

Thank you

WebUSB has been included in Chrome 61 which became available on september this year. This is a very useful addition to the web and we would like to thank Reilly Grant and Ken Rockot at Google for this initiative.

It fulfilled all our requirements and was a perfect choice for us, and we wouldn’t be surprised if it were to become quite popular for similar use cases. If you want to give it a try, you can head to our Workshop and update your calculator straight from your browser!