Setting up Remote SWUpdate with Yocto
This guide shows how to setup simple remote updates with SWUpdate for Yocto, based on my previously posted guide on setting up local updates. The file and directory structure created as part of that post, will be extended and adapted as follows:
|
|
| |
| | |
| |
|
|
| |
|
|
|
| | | | | | | | |
The resulting project repository of this guide is also available in the branch examples/yocto-swupdate-httpd of my Yocto examples repository.
Preconditions
This guide assumes that you followed my previous post on SWUpdate with Yocto and hence, that you are already able to create update images and install them locally.
You need a webserver that can provide update images according to the SWUpdate documentation on general purpose HTTP servers. This can be the simple SWUpdate HTTPd that I created in Rust for this purpose (just get the binaries at Github). Alternatively, there is also an example available in the SWUpdate repository.
Your Yocto-based device also needs a working network connection to reach the webserver. This is not covered in this guide, but you could, for example, install a wpa_supplicant.conf
file into a Poky-based image to connect to a wifi network (if you have working wifi hardware):
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=0
update_config=1
network=
Extend SWUpdate Build Configuration
As the first step, the Suricatta daemon mode of SWUpdate needs to be enabled, for being able to download update images from an HTTP server. Hence, extend the file recipes-core/swupdate/fragment.cfg
to contain at least the following content:
CONFIG_BOOTLOADERHANDLER=y # enable bootloader support
CONFIG_HASH_VERIFY=y # enable image hash verification
# CONFIG_LUA is not set
# enable support for image downloading from an HTTP server
CONFIG_CURL=y
CONFIG_CHANNEL_CURL=y
CONFIG_SURICATTA=y
#
# Server
#
# CONFIG_SURICATTA_HAWKBIT is not set
# CONFIG_SURICATTA_LUA is not set
CONFIG_SURICATTA_GENERAL=y
# CONFIG_WEBSERVER is not set
# CONFIG_MONGOOSE is not set
In this guide, a general HTTP server is used, which is why the option CONFIG_SURICATTA_GENERAL
is enabled, while CONFIG_SURICATTA_HAWKBIT
is disabled. The first configuration options were introduced in the previous guide for local updates and are needed the same way for remote updates.
Configure the SWUpdate Daemon
For automatically downloading and applying the firmware updates, a daemon needs to run on the device that regularly polls the HTTP server providing the update images. The SWUpdate layer provides init scripts to run swupdate
as a daemon that just needs to be configured as follows.
The general-server.cfg
with the following content will be placed in /etc/swupdate/conf.d
so that it will be sourced by the init script of the SWUpdate daemon:
# select the other partition to update at the sw-description later on during the update process
if ; then COPY=copy2; else COPY=copy1; fi
SWUPDATE_ARGS="-v --syslog -l 5 -e stable, -p 'reboot' -f /etc/swupdate/main.cfg"
SWUPDATE_SURICATTA_ARGS="-t default -i 25 -u @@SWUPDATE_SERVER_ADDRESS@@"
It provides the command line parameters for the SWUpdate daemon for automatic downloading of updates from a general HTTP server.
In addition the main.cfg
that is referenced in the general-server.cfg
should be created with the following content:
;
;
{ ; ; }
{ ; ; }
{ ; ; }
);
Of importance in this file, is the identify
section. The SWUpdate daemon will send all key value pairs from this section as URL parameters to the HTTP server when checking for available updates. The keys in this example match the expected URL parameters of my SWUpdate HTTPd. If you are using a different HTTP server to provide your update images, you can adapt them to your needs.
To make the new configuration files available in the Yocto image, the recipes-core/swupdate/swupdate_2024.%.bbappend
should then be adapted to contain the following:
# add current file path so that the interfaces file from here is used
# append the configuration fragment to the source files
The variables that are used in the swupdate_2024.%.bbappend
file need to be added to the layer.conf
:
# Configuration for SWUpdate via the general HTTP server
# The image name is composed of the image identifier, the machine name,
# and the image version; with identifier and version set above
Of course, the values need to be adapted to match your configuration. Especially regarding the SWUPDATE_SERVER_ADDRESS
. The IMAGE_NAME
is configured to match the format expected by my SWUpdate HTTPd. It can be different, if you use another HTTP server to provide the update images.
For consistency, the new IMAGE_VERSION
variable should be used now in the sw-description
for update images as well, instead of the DISTRO_VERSION
:
- version = "@@DISTRO_VERSION@@";
+ version = "@@IMAGE_VERSION@@";
Automatic Reboot after Image Installation
We configured SWUpdate to automatically reboot, after the download and installation of an update image by providing the reboot
command as a post-update command to the swupdate
daemon in the general-server.cfg
above. There is, however, an issue in SWUpdate currently, that the post-update command is not actually executed when downloading update images from HTTP servers. See also my bug report.
Hence, until this is fixed, it is necessary to add the patch file recipes-core/swupdate/0001-Add-call-for-post-update-script.patch
:
From 0627ee8cc31b1f0bb74446da1e44dc51df49de69 Mon Sep 17 00:00:00 2001
From: Adrian Winterstein <mail@int.winterstein.biz>
Date: Wed, 26 Mar 2025 16:29:16 +0100
Subject: [PATCH] Add call for post update script
core/stream_interface.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/core/stream_interface.c b/core/stream_interface.c
index f5cba496..5b048584 100644
} else {
notify(SUCCESS, RECOVERY_NO_ERROR, INFOLEVEL, "SWUPDATE successful !");
inst.last_install = SUCCESS;
+
+ if (postupdate(software, NULL))
+ {
+ return -1;
+ }
}
}
} else {
And apply it by extending the swupdate_2024.%.bbappend
file like this:
-SRC_URI:append = "file://fragment.cfg file://files/general-server.cfg file://files/main.cfg"
+SRC_URI:append = "file://fragment.cfg file://files/general-server.cfg file://files/main.cfg \
+ file://0001-Add-call-for-post-update-script.patch"
Trying the Remote Update
After building (kas build project.yml
) and flashing the image swupdate-example_raspberrypi0-2w-64_0.1.0.wic.bz2
, there should be an SWUpdate daemon running on your device. It regularly polls the configured HTTP server and will automatically download and install an update image, that you provide via this server.
Change the version number in the layer.conf
and trigger another Yocto build with kas build project.yml
afterwards:
-IMAGE_VERSION = "0.1.0"
+IMAGE_VERSION = "0.1.1"
Make the resulting update image swupdate-example_raspberrypi0-2w-64_0.1.1.swu
available in the images directory of the SWUpdate HTTPd or your HTTP server.
If you configured your device for being able to login (either with keyboard and screen on the device) or by also installing an SSH server into your image, you can check the log messages of the SWUpdate daemon in /var/log/messages
.
Next Steps
SWUpdate is configured to use the double copy with fall-back strategy, which means that an update is always written in a secondary partition that is booted then, with leaving the previous partition intact. This allows for falling back to the last working image, in case that there would be any issue with the installed update image. Testing the freshly booted image and falling back in case of error is, however, not implemented as part of this guide, but could be extended.
For being able to do additional updates after the first one, it is at least needed to set the bootlader evironment variable ustate
back to 0
, because SWUpdate does not do another update, as long as this variable indicates an image being in the testing state. It can be reset with fw_setenv ustate 0
.