Rolling out a device to multiple sites introduces challenges. The WiFi credentials can no longer be part of the source code. Applying firmware updates or accessing crash information over USB becomes cumbersome. Even simply finding the IP address of the device on the LAN may be challenging.
To address such challenges we use a three tiered approach, in which the
bootloader image decides what image to boot.
As usual, the
bootloaderimage does some minimum initializations. If it finds a valid
otaimage, it passes control over to that image. If not, it starts the
factoryimage takes care of provisioning WiFi and MQTT credentials with the help of a phone app. These credentials are stored in the
nvspartition. It then downloads the
We refer to the
otaimage as the
interface, as it provides the core of the functionality of the OPNpool device.
To facilitate this the flash memory is partitioned as shown below.
The partition table is shown in the table below.
The following sections describes the process in further detail. A whole chapter is dedicated to the
interface image, which provides the core functionality of the OPNpool device.
A few more words on the
otadatapartition is erased, it starts the
factoryimage (assuming it is present).
After the first OTA update, the
ota_datapartition is updated to specify which OTA app slot partition should be booted next.
If the image works fine, it marks itself as
ota_data. Otherwise, it marks itself
ESP_OTA_IMG_INVALID. This mechanism support image rollback to keep the device working after the update. It automatically rolls back to the previous version, if the image doesn’t pass its self test.
factory image, handles the provisioning and triggers an over-the-air (OTA) download of the
interface image. It then reboots, the
bootloader will start the
These steps are described in detail in the following section.
Provisioning WiFi credentials
For testing purposes,
OPNPOOL_MQTT_URL can also be provisioned using
Kconfig. If empty, the device will use credentials from flash memory.
A phone is used to connect to the
factory app using Bluetooth Low Energy (BLE). The
factory image will advertise itself to the phone app. Using this phone the user specifies the WiFi and MQTT credentials. During the process the phone remains in contact with the ESP while the WiFi is set up and connects to an access point. The WiFi and MQTT credentials are stored in the
nvs partition of flash memory.
You can find the source code of this app in the
android directory. If you have an iOS phone, or you have problems running the Android app, you can extend
esp_prov.py to include
mqtt_url similar to what is shown here“.
The code base uses the git submodule
The figure and video below give an impression of the provisioning process
Note to self: needs to check MQTT connection status and OTA download progress, awaiting answer to “Provisioning with custom-data after device establishes Wi-Fi connection“.
Connecting to the WiFi network
To establish the WiFi connection, the code base uses the git submodule
ESP32_wifi-connect. This component makes this API available as a reusable component. It connects to a WiFi Access Point, and automatically reconnects when the connection drops.
Download the Interface image
The ESP-IDF API provides a mechanism that allows a device to update itself based on data received while the normal firmware is running. Our code base uses the git submodule
ESP32_ota-update-task that makes the API available as a component.
The location of the
factory image is specified by
Note on HTTPS
components/ota_update_task/CMakelists.txt, and uncomment some lines in
The code checks for an OTA update on a network server. If the image is different, it will download it. Upon completion, the device resets to activate the downloaded code. Note that we use the term “update” loosely, because it can also be used to downgrade the firmware.
To determine if the currently running code is different as the code on the server, it compares the project name, version, date and time. Note that these are not always updated by the SDK. The best way to make sure they are updated is by committing your code to Git and building the project from scratch (by removing the
During debugging, you may want to flash the
image image directly as part of the “IDF-SDK: Build, flash and start monitor your device” cycle. To prevent that image from being overwritten by an OTA update, the update mechanism is disabled when the
interface image is loaded in the factory partition.
An example of the update process is shown in the figure below.
More details of this component can be found at Github.