Web-server for handling files and updating of ESP8266 and ESP32 boards.
ESP8266 and ESP32 boards are widely popular for all kinds of tinkering projects and hacking. These boards support Over-The-Air updating, so they can be upgrade via wifi without having to physically access them.
This project provides a web-server written in Python Flask that supports this Over-The-Air updating. Furthermore, it provides a user interface where platforms can be easily managed and update binary files easily uploaded.
The main feature are:
- Platform Names: Each platform supported must be created on the web interface before a binary is uploaded. If an existing platform name is not found in an uploaded binary it is rejected. Multiple devices can share the same platform name and thus receive the same binary. Individual devices are controlled through whitelists described below.
- Semantic Versioning: Updates are only done if a newer version of a binary is available compared to the version the device is already running. Semantic versioning is assumed e.g. v1.0.2. The uploaded binary must contain a version number starting with v and three version number components i.e MAJOR, MINOR, PATCH - v1.0.2. An uploaded binary is rejected if such a version number is not found in the binary or if the version number is not increased compared to the one already known.
- Whitelists: Download control is enforced by MAC Address whitelists. On the web interface WiFi MAC Addresses can be added and removed to created platforms. Only whitelisted devices will be allowed to update.
- Binary Upload: Uploading binaries is simple and administration is kept to a minimum by automatic detection of platform name and version number. This detection helps prevent mistakes where the OTA update routine is not called or you forgot to enter a valid platform name.
The server is intended to run on internal network where it cannot be accessed from the internet. As such it does only offer very basic security. In the users.yml, you can create additional users that are allowed to access the server. If no users.yml file is found, the server runs without authentication.
To run the server directly from code start it with the following command:
python3 server.py
From the root-directory of this app, run: docker build -t esp-update-server:latest .
to re-build the docker-image from source
To directly run this app, run
docker run -d --restart unless-stopped --name esp-update-server -v $PWD/bin:/esp-update-server/bin -p 5000:5000 esp-update-server:latest
Ready-made Docker images are available on Docker Hub which support running on Linux on both AMD64 and ARM32V6 architectures - i.e. desktops, laptops, and Raspberry Pis.
To run the server in a Docker container create a directory bin
for storing binaries. Then run following command from the directory where you have the server.py
docker run -d --restart unless-stopped --name esp-update-server -v $PWD/bin:/esp-update-server/bin -p 5000:5000 kstobbe/esp-update-server:latest
Using the -v
option ensures files are stored outside the Docker container and are thus persisted even if the container is terminated.
In a web browser, when the server is running, enter the IP address of the machine running the server and port 5000, e.g. http://192.168.0.10:5000
. Now platforms can be created and deleted. Whitelists can be managed and binaries uploaded.
Status overview
Whitelisting devices, and assigning them to a platform
Devices requesting download of a binary file for upgrade must access path update
and include device name and current version number in a query like below - substitute the IP address with your own.
http://192.168.0.10:5000/update?dev=chase&ver=v1.0.2
The server will respond with HTTP Error Code:
200
A new binary is available.304
No update is needed.400
or500
An error occurred, e.g. device not whitelisted or platform name is unknown.
Below if an implementation for ESP32 that works with the server. Remember to change the IP address in the code to match your own.
#include <HTTPClient.h>
#include <HTTPUpdate.h>
#include <WiFi.h>
#define VERSION "v1.0.2
#define DEVICE_PLATFORM "Chase"
const char* ota_update_server = "http://192.168.0.10:5000/";
/***************************************************/
void checkForUpdates(void)
{
String checkUrl = String( ota_update_server) + String("update?dev=" DEVICE_PLATFORM "&ver=" VERSION );
Serial.println("INFO: Checking for updates at URL: " + String( checkUrl ) );
WiFiClient client;
t_httpUpdate_return ret = httpUpdate.update( client, checkUrl );
switch (ret) {
default:
case HTTP_UPDATE_FAILED:
Serial.println("ERROR: HTTP_UPDATE_FAILD Error (" + String(httpUpdate.getLastError()) + "): " + httpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES:
Serial.println("INFO: HTTP_UPDATE_NO_UPDATES");
break;
case HTTP_UPDATE_OK:
Serial.println("INFO status: HTTP_UPDATE_OK");
break;
}
}
For ESP8266 the implementation is very similar with a few changes. Remember to change the IP address in the code to match your own.
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#include <ESP8266WiFi.h>
#define VERSION "v1.0.2
#define DEVICE_PLATFORM "Chase"
const char* ota_update_server = "http://192.168.0.10:5000/";
/***************************************************/
void checkForUpdates(void)
{
String checkUrl = String( ota_update_server) + String("update?dev=" DEVICE_PLATFORM "&ver=" VERSION );
Serial.println("INFO: Checking for updates at URL: " + String( checkUrl ) );
t_httpUpdate_return ret = ESPhttpUpdate.update( checkUrl );
switch (ret) {
default:
case HTTP_UPDATE_FAILED:
Serial.println("ERROR: HTTP_UPDATE_FAILD Error (" + String(ESPhttpUpdate.getLastError()) + "): " + ESPhttpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES:
Serial.println("INFO: HTTP_UPDATE_NO_UPDATES");
break;
case HTTP_UPDATE_OK:
Serial.println("INFO status: HTTP_UPDATE_OK");
break;
}
}
Project is under the MIT License.