UpdateHub: Sending OTA Updates using the Yocto Project
In the previous article, UpdateHub - Solution for Remote Firmware Updates, we talked about a tool that provides a complete OTA update solution, simplifying the process of remote updating of IoT devices. In this article we'll cover, in a practical and simple way, how to add UpdateHub support to your device using Yocto Project.
Before starting this tutorial, check if your Linux distribution is compatible and has all the dependencies required by Yocto Project, you can consult this information at Yocto Project manual. Another necessary tool is repo
, which is used to download the source code from the project. It is not necessary to have experience with the tool, because we will use few commands.
The device needs a network connection via DHCP, or the user has a prior knowledge of how to change the IP, or change/create a layer for the Yocto Project that makes this configuration. To facilitate we will define some terms used in this tutorial:
- Target: is the development device, in this tutorial we will use a Raspberry Pi 3 Model B+, but it can be the Raspberry Pi 3, Model B and Model B+.
- Host: is the computer where you will build the image in the Yocto Project, where the compilation will be done.
UpdateHub provides a repository with a manifest file used as a platform for the repo
tool. The purpose of using repo
is to ease the management of projects with multiple layers. For more information about the repo
tool, consult the Android development setup guide.
Preparing the environment for the build
To get the project sources install the repo
tool, running following commands:
mkdir ~/bin
curl http://commondatastorage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo
export PATH=${PATH}:~/bin
Create the directory that will contain all the required source code and fetch all the needed source code. The commands to do that are:
mkdir updatehub-platform
cd updatehub-platform
repo init -u https://github.com/UpdateHub/updatehub-yocto-project-reference-platform.git -b thud
repo sync
When the repo sync
command is finished, you can see that all the layers are in the “sources” directory. There is no need to add any more layers to the project.
Next, we need to load the bitbake
environment. We can easily do that running:
MACHINE="raspberrypi3" source ./setup-environment build
The UpdateHub platform provides support for multiple devices, see the list of supported devices here, so you will be asked whether you want to accept the End-user license agreement (EULA) of the meta-freescale layer, follow the steps shown, and it is not necessary to accept the EULA for this example.
Note that the above command is only valid for the shell that you loaded the environment. If you use a new terminal to execute the bitbake
command, the bitbake
environment needs to be loaded, but note that the MACHINE variable should be configured only once.
By default the meta-updatehub is configured to use the UpdateHub Cloud. In this tutorial we will use the UpdateHub Community Edition (updatehub-ce) which is a fully open source server, distributed under the MIT license, which you can start it on your own host.
Starting the UpdateHub Community Edition
To start updatehub-ce you must have Docker installed on the host. For information on how to install and configure Docker on your host, visit the following link.
With Docker installed, run the following command:
docker run -d -p 8080:8080 updatehub/updatehub-ce:latest
This command downloads the Docker image and starts the server on port 8080, to view the web interface, access the url http://IP_ADDRESS:8080
, the IP_ADDRESS
is the same as the host that is running the Docker image, for default login and password are "admin"q, fill in the fields and press LOGIN.
This address will be used to configure the UPDATEHUB_SERVER_URL
variable in the Yocto Project.
The main interface of updatehub-ce is as shown below:
Configuring the environment to generate the image
Before generating an image it is necessary to add and configure some variables in the file conf/local.conf
, these are:
UPDATEHUB_SERVER_URL = "http://ENDERECO_IP:8080"
UPDATEHUB_PACKAGE_VERSION_SUFFIX = "-test-image-1"
ENABLE_UART = "1"
UPDATEHUB_SERVER_URL
: Contains the IP address where updatehub-ce is running, as previously mentioned.
UPDATEHUB_PACKAGE_VERSION_SUFFIX
: Used to add a suffix in the version of the image being generated. This is useful for placing a version number and incrementing with each new image.
When saving the image to the target this variable will be present in VERSION_ID, composed of the DISTRO_VERSION
(you can see here) + UPDATEHUB_PACKAGE_VERSION_SUFFIX
. This information can be verified by reading the /etc/os-release
file in the target.
ENABLE_UART
: There are some ways to access the target. Among them, we can use the serial console or connect a keyboard and a monitor. This variable allows access to a console in RaspberryPi using the serial port.
For more information on how to use the serial connection in RaspberryPi go to here.
Generating the image
With the environment and configurations ready we can perform the compilation of the image, execute the following command:
bitbake updatehub-image-minimal
Wait until the image is generated, this can take a long time depending on the host used. If it is the first time an image is generated for raspberrypi3 in the thud
branch, bitbake
will download the entire source code, so the download speed will also influence the final time to generate the image.
Once the image has been compiled, it will be available in the tmp/deploy/images/raspberrypi3/
host directory. The file that we will use to write to the SD card is updatehub-image-minimal-raspberrypi3.wic.gz
. Copy this file to your home, unzip it and burn it using the dd tool on an SD card. In the command below it is necessary to change the /dev/sdX
device to the one corresponding to your SD card.
CAUTION: Check the name of the SD card device before executing the command below! To find out the name of the device insert the SD card and run the dmesg command to know what is the correct device name.
zcat updatehub-image-minimal-raspberrypi3.wic.gz | sudo dd of=/dev/sdX
With the SD card ready, you can already insert it into the target and then you are ready to connect to RaspberryPi. The image is with the network configured to obtain an IP address using DHCP. To access the console the user is set to “root” and does not need to enter a password.
You can confirm the version of the image that is running on the target with the command cat /etc/os-release
, the output will be as shown below:
root@raspberrypi3:~# cat /etc/os-release
ID="oel"
NAME="O.S. Systems Embedded Linux"
VERSION="18.10"
VERSION_ID="18.10-test-image-1"
PRETTY_NAME="O.S. Systems Embedded Linux 18.10"
UPDATEHUB_PRODUCT_UID="0000000000000000000000000000000000000000000000000000000000000000"
Generating the update package
This process step will create an image that will be used to update your target. In this case, to facilitate, we will use the same previous image, just changing the version. To generate the package used in the update we will change the variable UPDATEHUB_PACKAGE_VERSION_SUFFIX
and put the suffix -test-image-2
, so it is clear that the updated image will have another version. Edit the conf/local.conf
file, save and run the following command:
bitbake updatehub-image-minimal -c uhuarchive
This command generates a file with .uhupkg
extension, a format used by UpdateHub to update the system. The generated file will be in the same directory as the images, tmp/deploy/images/raspberrypi3
, in this example updatehub-image-minimal-raspberrypi3.uhupkg
.
Using UpdateHub Community Edition
Access the server's web interface, http://IP_ADDRESS:8080
, to see if your device, the target, has communicated with the server, click the Devices tab and see the details.
Sending an update package
To send an update package go to the PACKAGES tab, in this tab is shown a list with the available packages, at the moment we do not have any. Click the Upload Package button and select the updatehub-image-minimal-raspberrypi3.uhupkg
file. In this example, you will find it in the tmp/deploy/images/raspberrypi3/directory
. A screen showing the package details will appear as the image below.
Creating a rollout
With the device recognized and the packet sent to the server, we can create a rollout. Navigate to the Rollouts tab and click Create Rollout. In the rollout screen you should choose which package version will be used in the upgrade, in our case there is only the package sent in the previous step with version 18.10-test-image-2
. Choose this version and make sure the device has entered the list of devices that will be updated. If everything occurred as expected a screen like the one bellow will appear.
The image running on the target defaults to 1 minute to perform an update query on the UpdateHub server, so within one minute of creating the rollout
the update process will start. The status of the update can be tracked in the Rollouts tab.
After finishing the upgrade process, the target will restart automatically. The new image will start up and automatically it will query the server for updates. The server will respond that it does not have any updates to be made and thus ending the update cycle.
To check if the target was actually updated, you can execute the cat /etc/os-release
command to get the version installed, you will get an output like this to the command:
root@raspberrypi3:~# cat /etc/os-release
ID="oel"
NAME="O.S. Systems Embedded Linux"
VERSION="18.10"
VERSION_ID="18.10-test-image-2"
PRETTY_NAME="O.S. Systems Embedded Linux 18.10"
UPDATEHUB_PRODUCT_UID="0000000000000000000000000000000000000000000000000000000000000000"
As confirmed in the web interface and target, the image was successfully updated from version 18.10-test-image-1
to 18.10-test-image-2
.
Adding SSH support on target
Now that the whole upgrade process has been explained, we'll add support for an SSH
server on the target and create an update package to install this functionality.
To add support for the SSH OpenSSH server add the following line to the conf/local.conf
file:
IMAGE_FEATURES += "ssh-server-openssh"
and change the variable UPDATEHUB_PACKAGE_VERSION_SUFFIX
to use version 3 of our test image:
UPDATEHUB_PACKAGE_VERSION_SUFFIX = "-test-image-3"
We can save the file and generate a new update package by running the same command used previously:
$ bitbake updatehub-image-minimal -c uhuarchive
After the package is generated, send the new file to updatehub-ce as shown in Sending an update package section. Once the package has been uploaded we can create a new rollout, as shown in Creating a Rollout section, now using the version 18-10-test-image-3
, which is the version with an SSH server installed.
The installation procedure will be the same as the update procedure for version 18-10-test-image-2
, and follow-up can be seen on the Rollouts tab. When the status shows updated, we can access the target using the SSH protocol, for this type in the host:
ssh root@IP_DO_TARGET
No password is required, just press Enter and we will be in the target console. Again we can check the version with the contents of the /etc/os-release
file.
In this tutorial we use as an example a Raspberry Pi 3 in version 2.6 of the Yocto Project, but we have support for other devices and versions, listed here. If you have questions about integrating your device, we have a chat at Gitter or you can contact us at contact@updatehub.io.
In the next article, we'll cover how to include UpdateHub in a Zephyr Project application.