IoT device development starts on the bench, before any connectivity happens. For Zephyr devices, this often involves using a programmer/debugger to get an initial firmware image onto a device. Sometimes, the device already has an MCUboot-based bootloader onboard and it’s possible to load up a new image using tools like mcumgr, newtmgr, or smpmgr. These tools send Simple Management Protocol (SMP) packets over a serial or Bluetooth link. We created a tool that allows similar actions, but works through the browser using Web Serial. This new tool called Local Shell allows cross-platform programming of devices (and more) without any installation.
Why do we need Web Serial tools?
Since my first day at Golioth, we have been working to make embedded devices easier to use. Golioth does Zephyr training to teach developers how to use the popular RTOS and Ecosystem, and a pain point is always that “getting started” moment. Even with the great development boards from silicon vendors, there are tooling issues in getting started: we either need to tell trainees to install a desktop or command line tool to program images onto devices. These small instances of frictions slow down the learning, bit by bit.
WebSerial has been around in Chromium browsers for years now. Firefox recently turned it on in their browser as well. We have seen some hardware vendors use it to great effect, such as Espressif. We used that in our hackathon project that created a smart display and allowed our users to load up new images near-instantly. This works because Espressif has a bootloader flow that allows direct loading of new images over a serial link. Others in the space like Blues have a built in tool in their docs to interact directly with their custom hardware platform.
Zephyr is different because of SMP: almost all tooling is built around sending these binary packets to devices. There are benefits, including direct modification of the filesystem onboard and deeper direct manipulation of devices. The downside is that it requires custom tooling to send SMP packets to devices. There have been other projects on the web that enabled mcumgr over Web Bluetooth, but we wanted to push SMP over serial. So we worked with an LLM coding agent to get SMP working over Web Serial. We called this new tool Local Shell.
Introducing Local Shell
The term “Local Shell” is possibly a bit ambiguous. Yes, we allow users to interact with the Zephyr Shell directly using Web Serial, but that has been possible using other Web Serial interfaces like WebSerial.io. The real value of Local Shell is the SMP interface. The name really came from a previous project we did called “Remote Shell” where we enabled Zephyr Shell access from the cloud using Golioth RPC (Remote Shell does not involve SMP). Since we could talk to the Zephyr Shell remotely before, it made sense to call this Web Serial interface “Local Shell”. The SMP interface came later, thanks to some LLM assisted coding.
Let’s talk about the functions where we see the most value for our users
Web Serial connection to Zephyr Shell
This is a straightforward capability that is mostly a Web Serial interface to the device, which needs to be configured to use the Zephyr Shell (a favorite feature of ours). This works when the device is running USB-CDC emulating a serial connection or through a USB-to-serial chip using something like the CP2102 (which we have on the Aludel Elixir). There is an input box on the current implementation that limits things like tab completion and other capabilities available from the Zephyr shell, but we hope to improve this over time to approximate the experience you might have from a tool like minicom (my preferred desktop interface to serial devices).
Zephyr does have support for things like vt100 colors and better formatting of linebreaks, so we did pull that into this view, much like we did on remote shell. Not as useful if you are hoping to troubleshoot the variety of hidden characters a Shell might send, but definitely fits the iTerm-like aesthetic we have targeted for both projects.
Loading Certificates to the Filesystem over SMP
The Tikk board and nRF52840 combination shown in the video above has LittleFS (LFS) enabled as a filesystem. We use the filesystem to store the generated device certificates we created using the Golioth Certificate Generator. Any device utilizing Pouch encrypts data using Certificates and this is the current best practice for using certs on device.
Pushing arbitrary files into LFS requires a tool that “talks” SMP. Both smpmgr or mcumgr can do this, but require install on your machine (and sometimes compilation, like with mcumgr). Using Web Serial APIs depends upon the browser–Chromium and now Firefox–to handle that lower level interface with user hardware.
The new method is to use the ‘upload certificate’ button on the Local Shell that pushes arbitrary files into /lfs1/credentials. This is where we normally store device certs for our Golioth application demos, but can be expanded in the future to determine arbitrary file locations.
Loading New Firmware over SMP
To me, firmware update through the browser is the holy grail of device enablement for IoT beginners: getting new firmware onto devices without a debugger/programmer and without installing a tool. For our own Zephyr training, we show users how to build Zephyr programs on the cloud using devcontainers and Github Codespaces. The users then download the generated binary and we encourage them to use nRF Connect for Desktop app–a great app in its own right, but not without some friction around installation for the variety of users who sign up for our training. For the training, we actually target devices that have debuggers/programmers on board (the nRF9160-DK and the nRF7002-DK), but it’s still possible to load images over the connection to the board.
With Local Shell, the user needs to put the device into bootloader mode, normally with a GPIO held down during reset or by sending an unlock sequence. Currently we only enable the former, but are looking at others. Then the user clicks the ‘Upload Firmware’ button and selects the MCUboot device in bootloader mode. The SMP packets flow over the Web Serial connection and closes the connection once the transfer is complete.
For future versions of our training, we will be able to target boards that have MCUboot and we can load in the “zephyr.signed.bin” file generated in the build stage of Zephyr projects. This is the same asset users upload to Golioth when using the OTA firmware update service.
Future enhancements
The Local Shell interface is a prototype, to be sure. We have been testing it internally but hope that others will try it out and give us feedback. We also see some parts we hope to improve in the future, such as
- Creating local clients built from the same source so LLM enabled interaction moves in lockstep
- Additional firmware examples including buttonless firmware loading
- Additional local tools to simulate sending data up to the cloud
- Improving the “terminal-like” interface to enable tab completion
- Pulling in other SMP-based communication for Zephyr boards
We want to continue to lower the barrier to getting started with embedded IoT projects and build other tools that make things easier. If you have any suggestions, feel free to email [email protected]


No comments yet! Start the discussion at forum.golioth.io