ESP32 self OTA update firmware from a server with version check – 2

Spread the love

In the rapidly evolving world of Internet of Things (IoT) devices, keeping firmware up-to-date is crucial to ensure the security, stability, and functionality of connected systems.

One powerful and versatile microcontroller that has gained popularity in the IoT community is the ESP32, which offers a wide range of features for both hobbyists and professionals alike.

One essential aspect of maintaining an IoT network is the ability to perform Over-the-Air (OTA) firmware updates, which allows devices to receive new software without requiring physical intervention.

ESP32 self OTA update: firmware from a server with version check
ESP32 self OTA update: firmware from a server with version check

In this article, we’ll explore a robust and efficient method for implementing self OTA update firmware for the ESP32, complete with a version check mechanism that will enable your devices to automatically download and install the latest updates from a designated server. This will not only save you time and resources but also contribute to a more resilient and adaptable IoT ecosystem.

First of all, check the tutorial “ESP32: flash compiled firmware (.bin)“.

Here a selection of esp32 devices ESP32 Dev Kit v1 - TTGO T-Display 1.14 ESP32 - NodeMCU V3 V2 ESP8266 Lolin32 - NodeMCU ESP-32S - WeMos Lolin32 - WeMos Lolin32 mini - ESP32-CAM programmer - ESP32-CAM bundle - ESP32-WROOM-32 - ESP32-S

Conditionally OTA (version control) updates with REST

We can use a more complex update firmware, and we can pass the firmware version to check,

    t_httpUpdate_return ret = httpUpdate.update(client, "192.168.1.125", 3000, "/update", FIRMWARE_VERSION);

with FIRMWARE_VERSION equal to 0.2.

This call transports a set of information in the Header of the call, so if we check the received header by the update GET

app.get('/update', (request, response) => {
    console.log("List of headers", request.headers);
});

we can find these values

host = "192.168.1.70:3000"
user-agent = "ESP32-http-Update"
connection = "close"
cache-control = "no-cache"
x-esp32-sta-mac = "30:AE:A4:F4:7C:38"
x-esp32-ap-mac = "30:AE:A4:F4:7C:39"
x-esp32-free-space = "1310720"
x-esp32-sketch-size = "731136"
x-esp32-sketch-md5 = "b91170ed29a37d086b1f22e55750af43"
x-esp32-sketch-sha256 = "716398C33FFC451B000B3F4664BD568CCABA49FC36A21CFA426E982305BC2D90"
x-esp32-chip-size = "4194304"
x-esp32-sdk-version = "v3.3.5-1-g85c43024c"
x-esp32-mode = "sketch"
x-esp32-version = "0.2"

In this case, we check only the x-esp32-version, but some information like free space and SDK version can be very useful.

Update endpoint with version control

Now we add an update endpoint

const express = require('express');
const { networkInterfaces } = require('os');
const path = require('path');

const app = express();
const nets = networkInterfaces();

// Server port
const PORT = 3000;

app.get('/', (request, response) => response.send('Hello from www.mischianti.org!'));

let downloadCounter = 1;
const LAST_VERSION = 0.3;
app.get('/update', (request, response) => {
    const version = (request.header("x-esp32-version"))?parseFloat(request.header("x-esp32-version")):Infinity;

    if (version<LAST_VERSION){
        // If you need an update go here
        response.status(200).download(path.join(__dirname, 'firmware/httpUpdateNew.bin'), 'httpUpdateNew.bin', (err)=>{
            if (err) {
                console.error("Problem on download firmware: ", err)
            }else{
                downloadCounter++;
            }
        });
        console.log('Your file has been downloaded '+downloadCounter+' times!')
    }else{
        response.status(304).send('No update needed!')
    }
});


app.listen(PORT, () => {
    const results = {}; // Or just '{}', an empty object

    for (const name of Object.keys(nets)) {
        for (const net of nets[name]) {
            // Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
            if (net.family === 'IPv4' && !net.internal) {
                if (!results[name]) {
                    results[name] = [];
                }
                results[name].push(net.address);
            }
        }
    }

    console.log('Listening on port '+PORT+'\n', results)
});

And we generate a new compiled binary file with version 0.3 and put It on the server

[SETUP] WAIT 4...
[SETUP] WAIT 3...
[SETUP] WAIT 2...
[SETUP] WAIT 1...
Firmware version 0.2
Update start now! 
HTTP_UPDATE_OK
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1216
ho 0 tail 12 room 4
load:0x40078000,len:10944
load:0x40080400,len:6388
entry 0x400806b4
 


[SETUP] WAIT 4...
[SETUP] WAIT 3...
[SETUP] WAIT 2...
[SETUP] WAIT 1...
Firmware version 0.3

Conditionally FileSystem OTA (version control) updates with REST

In the same manner, we can manage filesystem updates. We are going fast now because It’s the same logic of firmware update.

Generate FileSystem binary file

To manage the filesystem, we can use the same way, but first, you must read one of the following guides:

After that operation, you can use the plugin as usual.

Now we are going to add data directory to the sketch folder, and we create a file version.txt with this content

0.2

and use the plugin to upload.

Arduino IDE esp32 SPIFFS Sketch Data Upload
Arduino IDE esp32 SPIFFS Sketch Data Upload
esp32 SPIFFS LittleFS FatFS file uploader from Arduino IDE
esp32 SPIFFS LittleFS FatFS file uploader from Arduino IDE

You can check the IDE console output to check what happened.

Chip : esp32
Using partition scheme from Arduino IDE.
Start: 0x290000
Size : 0x170000
mkspiffs : C:\Users\renzo\AppData\Local\Arduino15\packages\esp32\tools\mkspiffs\0.2.3\mkspiffs.exe

espota : C:\Users\renzo\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.0\tools\espota.exe

[SPIFFS] data   : D:\Projects\Arduino\sloeber-workspace-OTA\ArduinoOTAesp32_basic_arduino\data
[SPIFFS] offset : 0
[SPIFFS] start  : 2686976
[SPIFFS] size   : 1472
[SPIFFS] page   : 256
[SPIFFS] block  : 4096
->/version.txt
[SPIFFS] upload : C:\Users\renzo\AppData\Local\Temp\arduino_build_258074/ArduinoOTAesp32_basic_arduino.spiffs.bin
[SPIFFS] IP     : 192.168.1.186
Running: C:\Users\renzo\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.0\tools\espota.exe -i 192.168.1.186 -p 3232 -s -f C:\Users\renzo\AppData\Local\Temp\arduino_build_258074/ArduinoOTAesp32_basic_arduino.spiffs.bin

_>Sending invitation to 192.168.1.186 
_>Uploading................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
_>09:21:38 [ERROR]: Error response from device
SPIFFS Upload failed!

The IDE console returns an error, but the upload work, I think there is a little bug now when I write this article.

IDE gives an error but it is a bug, the loading works correctly

You can retrieve the file system bin file from this line

[SPIFFS] upload : C:\Users\renzo\AppData\Local\Temp\arduino_build_258074/ArduinoOTAesp32_basic_arduino.spiffs.bin

Create sketch

Now we are going to modify the sketch already used for firmware.

/*
 * ESP32 Sketch for update of filesystem with version control
 *
 * Renzo Mischianti <www.mischianti.org>
 *
 * https://mischianti.org
*/

#include <Arduino.h>

#include <WiFi.h>
#include <WiFiMulti.h>

#include <HTTPClient.h>
#include <HTTPUpdate.h>

#include <SPIFFS.h>

#ifndef APSSID
#define APSSID "<YOUR-SSID>"
#define APPSK  "<YOUR-PASSWD>"
#endif

WiFiMulti WiFiMulti;

#define FIRMWARE_VERSION "0.2"
String FILESYSTEM_VERSION = "0.0";

void setup() {

  Serial.begin(115200);
  // Serial.setDebugOutput(true);

  Serial.println();
  Serial.println();
  Serial.println();

  for (uint8_t t = 4; t > 0; t--) {
    Serial.printf("[SETUP] WAIT %d...\n", t);
    Serial.flush();
    delay(1000);
  }

  WiFi.mode(WIFI_STA);
  WiFiMulti.addAP(APSSID, APPSK);

  Serial.print(F("Firmware version "));
  Serial.println(FIRMWARE_VERSION);
  delay(2000);

  Serial.print(F("Inizializing FS..."));
  if (SPIFFS.begin()){
      Serial.println(F("done."));
  }else{
      Serial.println(F("fail."));
  }

  Serial.print(F("FileSystem version "));
  File versionFile = SPIFFS.open(F("/version.txt"), "r");
  if (versionFile) {
	  FILESYSTEM_VERSION = versionFile.readString();
	  versionFile.close();
  }
  Serial.println(FILESYSTEM_VERSION);
}

void loop() {
  // wait for WiFi connection
  if ((WiFiMulti.run() == WL_CONNECTED)) {

    WiFiClient client;

    // The line below is optional. It can be used to blink the LED on the board during flashing
    // The LED will be on during download of one buffer of data from the network. The LED will
    // be off during writing that buffer to flash
    // On a good connection the LED should flash regularly. On a bad connection the LED will be
    // on much longer than it will be off. Other pins than LED_BUILTIN may be used. The second
    // value is used to put the LED on. If the LED is on with HIGH, that value should be passed
    // httpUpdate.setLedPin(LED_BUILTIN, LOW);

    httpUpdate.rebootOnUpdate(false); // remove automatic update

    Serial.println(F("Update start now!"));

    t_httpUpdate_return ret = httpUpdate.updateSpiffs(client, "http://192.168.1.70:3000/updateFS", FILESYSTEM_VERSION);

    switch (ret) {
      case HTTP_UPDATE_FAILED:
        Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str());
        Serial.println(F("Retry in 10secs!"));
        delay(10000); // Wait 10secs
        break;

      case HTTP_UPDATE_NO_UPDATES:
        Serial.println("HTTP_UPDATE_NO_UPDATES");
        break;

      case HTTP_UPDATE_OK:
        Serial.println("HTTP_UPDATE_OK");
        delay(1000); // Wait a second and restart
        ESP.restart();
        break;
    }
  }
}

I retrieve the version of the filesystem from version.txt the file and put It on FILESYSTEM_VERSION the variable.

  Serial.print(F("Inizializing FS..."));
  if (SPIFFS.begin()){
      Serial.println(F("done."));
  }else{
      Serial.println(F("fail."));
  }

  Serial.print(F("FileSystem version "));
  File versionFile = SPIFFS.open(F("/version.txt"), "r");
  if (versionFile) {
	  FILESYSTEM_VERSION = versionFile.readString();
	  versionFile.close();
  }
  Serial.println(FILESYSTEM_VERSION);

Create server end-point

Now we are going to create a new endpoint /updateFS in GET that checks the filesystem version get from version.txt with the variable LAST_FS_VERSION.

const express = require('express');
const { networkInterfaces } = require('os');
const path = require('path');

const app = express();
const nets = networkInterfaces();

// Server port
const PORT = 3000;

app.get('/', (request, response) => response.send('Hello from www.mischianti.org!'));

let downloadCounter = 1;
const LAST_VERSION = 0.3;
app.get('/update', (request, response) => {
    const version = (request.header("x-esp32-version"))?parseFloat(request.header("x-esp32-version")):Infinity;

    if (version<LAST_VERSION){
        // If you need an update go here
        response.status(200).download(path.join(__dirname, 'firmware/httpUpdateNew.bin'), 'httpUpdateNew.bin', (err)=>{
            if (err) {
                console.error("Problem on download firmware: ", err)
            }else{
                downloadCounter++;
            }
        });
        console.log('Your file has been downloaded '+downloadCounter+' times!')
    }else{
        response.status(304).send('No update needed!')
    }
});

let downloadFSCounter = 1;
const LAST_FS_VERSION = 0.3;
app.get('/updateFS', (request, response) => {
    const version = (request.header("x-esp32-version"))?parseFloat(request.header("x-esp32-version")):Infinity;

    if (version<LAST_FS_VERSION){
        // If you need an update go here
        response.status(200).download(path.join(__dirname, 'filesystem/httpUpdateNewFS.bin'), 'httpUpdateNewFS.bin', (err)=>{
            if (err) {
                console.error("Problem on download filesystem: ", err)
            }else{
                downloadFSCounter++;
            }
        });
        console.log('Your file FS has been downloaded '+downloadFSCounter+' times!')
    }else{
        response.status(304).send('No FS update needed!')
    }
});

app.listen(PORT, () => {
    const results = {}; // Or just '{}', an empty object

    for (const name of Object.keys(nets)) {
        for (const net of nets[name]) {
            // Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
            if (net.family === 'IPv4' && !net.internal) {
                if (!results[name]) {
                    results[name] = [];
                }
                results[name].push(net.address);
            }
        }
    }

    console.log('Listening on port '+PORT+'\n', results)
});

Now we are going to modify the file version.txt with the version 0.2 then upload to the device:

  1. In OTAServer create the folder filesystem,
  2. Change version to 0.3 in version.txt, regenerate without upload, and copy the file ArduinoOTAesp32_fs_update.mkspiffs.bin to the folder
  3. Rename in httpUpdateNewFS.bin.

The result in serial output becomes like so.

[SETUP] WAIT 4...
[SETUP] WAIT 3...
[SETUP] WAIT 2...
[SETUP] WAIT 1...
Firmware version 0.3
Inizializing FS...done.
FileSystem version 0.1
Update start now!
HTTP_UPDATE_OK
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1216
ho 0 tail 12 room 4
load:0x40078000,len:10944
load:0x40080400,len:6388
entry 0x400806b4


 
[SETUP] WAIT 4...
[SETUP] WAIT 3...
[SETUP] WAIT 2...
[SETUP] WAIT 1...
Firmware version 0.3
Inizializing FS...done.
FileSystem version 0.2
Update start now!

Update endpoint with version control and secure TLS connection

Now we can upgrade our example with SSL/TLS connection.

To generate a good Self-Signed certificate, you need to associate a common name or IP of the machine you want to call.

But ESP32 and esp8266 do not support IP (I lost a day trying It), so the only way to test a real solution is to assign a hostname to the server machine.

If you want to do a fast solution, you can use the command

    client.setInsecure();

that prevents all server validation check and allow you to do HTTPS request without a thrust certificate.

But we do It step by step.

Self-signed certificate generation

But if you want to use a self-signed certificate, you can use OpenSSL for the generation of the private keys and certificate.

Basic server certificate (you must bypass certificate validation on the client)

You can get openssl by downloading Linux version from all packet managers, or download it for windows from here, to use It with more simplicity add to PATH.

openssl req -new -x509 -sha256 -newkey rsa:2048 -nodes -keyout key.pem -days 365 -out cert.pem -subj "/CN=192.168.1.70"

and here is the response

Generating a RSA private key
................................+++++
..........................................................+++++
writing new private key to 'key.pem'
-----

Now you can grab data from key.pem

-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDPwU8Kbzr4PiKO
k+S4Cwj20tgnxYlesv99Fbmivl7PjwhYaIEX68afazYUoeQa1nNM8GSKRh4gSZnR
Zk61RR5d1U/EtWRVFWhIUB2U4Vy6KQ3vUaVoXRjtHjzlvarulvLvHF3/37rTJMqg
rnP2EbdKUQyxuAW7P3OMfSLEzn1LbuPGtZRHepckXnOpddghBvqIRrvrM8GPo0Ro
AXziXZMQ4hQgSxZopnP62XintfM1f/eZVPws9ww/5DVLFQs0ji2LuCPtxaokNgkq
t0wGHS6QNaWDbB7IBhbeg7oLg0HHz2SMJkYrGkmWhku+BVkWWf9snMK/RjN2NNMA
zMGADoSPAgMBAAECggEBAMQ8NHuHquy2TA/edAi/K51wdInElUekzZyJ+8lUBdwJ
n3laZK2CoB8OtotwizQqYchHvL+7EVOwEaFwAGJKQi+hf/Iu3/FaAiFjwz1QTTTt
+GKX/SQB47x9dkoPCDjKzfa7FbLN0fsEYny5q4C/JSEGQ3ZOeuNuQKdvv3qkDEdF
Z90JBHWzOrfUR2SpHuuk366ixwBjohOwyOHSP8VLXfPYp/RcgU/7/cRBSPN+xxIB
2Ovv/ERnTUbLqYlgU0Ok5KMMc7RmtXO9mwE6wFwNGJImYgn4IcCxAe41h6UTxmaG
gdeS2Ixil20Fi7wuLntOGkaqGewdjmjZN2apJ33gCukCgYEA7zE0hVzgfzLXPRVe
y7ouuLLrhZlkJfFsk75aVv9vfLD4eX6JgN/VU34vqmzqVSdszfum6fWyycSXwc9s
xrCLMYMS9lbz/HuiQn1c+7mZT+3hF4Qazy4ZU1rA4CBgGoyJK4eiO7tC9Vl29PvR
osDTdCOjJbIOCIAKsswrixHfgDsCgYEA3lqWDEuxQTctplL6gtXRUyBAooMLrrGZ
9/5Ut3qLlTWqdKr5+RlJCF4hc/1iYQHxDq+6SV2GpOO/0E7w0GlcoO3ME+AMf4qq
OHMcAGoJXYCEw/0u2MjuEnXlo8L3qp1+LK9rvGUViCx7Fha4OCIRuNWeJ4g8eIAl
qqzUd6fJ+70CgYEAiBDEoMzZxGIGgPAEMf5ij5zwT9qXVuJEcrNJLs41/IergWmT
DOXHs6xHrzov/2rjATYTmGm1YAPelFjLtyc8t1ip08pZFxq5jftEhsnoxcg7UKZM
nejKbVll+NlR8ihZ65JHnpUDHRDck7YgZeYtI5cWOt5UD0/PRjDQ4Fa1fnsCgYAL
+gEfBGy1wI0a6llH9tBhk9knZ7uXW0WZz/8sKtOd49gclKEGQ9BlPPy8TKeh5gLf
8aMtFHaOJx5L0BS0hRhSKrzVTTofHI7yn3CgrRV4DdYY4GhHkPsRz3vhCD1i2TzU
l1ZMPX2dahfvJqYhj+Q4enkcVAA91VkyCkEfeNAuWQKBgH+82agy+jlRyRBvQ6eI
i5n7FbCMJSw/1mfOmxGiEQhshaQkPDx+PfPgy+LOMuXAr1ZBsWMCGERdUsesXjIH
AHcY8Nl0tC5dG8q7B3A11xttwFbhQ4fgq+AUEzSH3ykTvuobGCNtM5AuawNWIjj7
VO0JDqUFQcom1brJIHowKKNU
-----END PRIVATE KEY-----

and cert.pem

-----BEGIN CERTIFICATE-----
MIIDGTCCAgGgAwIBAgIULbAi2zs41Rh6AZy08xumoYMIFJQwDQYJKoZIhvcNAQEL
BQAwHDEaMBgGA1UEAwwRMTkyLjE2OC4xLjcwOjM0NDMwHhcNMjEwOTEzMDcwODUw
WhcNMjIwOTEzMDcwODUwWjAcMRowGAYDVQQDDBExOTIuMTY4LjEuNzA6MzQ0MzCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM/BTwpvOvg+Io6T5LgLCPbS
2CfFiV6y/30VuaK+Xs+PCFhogRfrxp9rNhSh5BrWc0zwZIpGHiBJmdFmTrVFHl3V
T8S1ZFUVaEhQHZThXLopDe9RpWhdGO0ePOW9qu6W8u8cXf/futMkyqCuc/YRt0pR
DLG4Bbs/c4x9IsTOfUtu48a1lEd6lyRec6l12CEG+ohGu+szwY+jRGgBfOJdkxDi
FCBLFmimc/rZeKe18zV/95lU/Cz3DD/kNUsVCzSOLYu4I+3FqiQ2CSq3TAYdLpA1
pYNsHsgGFt6DuguDQcfPZIwmRisaSZaGS74FWRZZ/2ycwr9GM3Y00wDMwYAOhI8C
AwEAAaNTMFEwHQYDVR0OBBYEFKyvsHqrsHBj+V5H8aDT5qvPOSfdMB8GA1UdIwQY
MBaAFKyvsHqrsHBj+V5H8aDT5qvPOSfdMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
hvcNAQELBQADggEBALwdlitiQayOG2o2y3BAipcdaMxdGbihorheuO17glsZtp2R
H2LUUqnmG8hGH4pHbkd2gozxLt/h7ILrD1xK/EIlXjGueu3MF377GWZpR18OXt+1
cqpxDdAESD3PRbcJnu75uffFYLSKizbuaTbV2D8RY1kcUxRlrFG2bciNP9widbjq
T9B4RhtJb0d+Sk8Z2G2eTlNxESPQ/Oi530rrbZsez0XmdYyogbVHuNdwJvfQdA8U
F1UtWj6vtGAramUn0dS5rJ8REfZ4jdGsXYT2jmCfDTgaE+1sEYm6ry+RInDK5RVi
Kk+bL292uc4d0STCqXciv7YbWDWlZPo9fH0Pxs0=
-----END CERTIFICATE-----

Valid self-signed certificate

If you don’t need to create a real environment, go to the next paragraph, the certificate generated in the previous chapter is sufficient for our test.

First of all, we must assign a name to the server host, there are a lot of alternatives, but I think the fastest way is to use a Dynamic DNS.

Normally Dynamic DNS is used to assign a name dynamically to the IP given to us by ISP, but you can assign a static IP and use It like a normal host, here is an example with a free service NO-IP.

Configure Dynamic DNS service

Go to https://www.noip.com/ and Sign Up.

I add my email, insert a password and, create a name like serverota.ddns.net, then click on Free Sign Up.

Add the certificate to the NodeJS server

First, modify the server to expose the HTTPS endpoint, I select the 3443 port for that purpose, and I add the 2 certificates to the certificate folder.

var fs = require('fs');

const express = require('express');
var http = require('http');
var https = require('https');
var privateKey  = fs.readFileSync('certificate/key.pem', 'utf8');
var certificate = fs.readFileSync('certificate/cert.pem', 'utf8');

var credentials = {key: privateKey, cert: certificate};

const { networkInterfaces } = require('os');
const path = require('path');

const app = express();
var httpServer = http.createServer(app);
var httpsServer = https.createServer(credentials, app);

const nets = networkInterfaces();

// Server port
const PORT = 3000;
const PORT_HTTPS = 3443;

app.get('/', (request, response) => response.send('Hello from www.mischianti.org!'));

let downloadCounter = 1;
const LAST_VERSION = 0.3;
app.get('/update', (request, response) => {
    const version = (request.header("x-esp8266-version"))?parseFloat(request.header("x-esp8266-version")):Infinity;

    if (version<LAST_VERSION){
        // If you need an update go here
        response.status(200).download(path.join(__dirname, 'firmware/httpUpdateNew.bin'), 'httpUpdateNew.bin', (err)=>{
            if (err) {
                console.error("Problem on download firmware: ", err)
            }else{
                downloadCounter++;
            }
        });
        console.log('Your file has been downloaded '+downloadCounter+' times!')
    }else{
        response.status(304).send('No update needed!')
    }
});


httpServer.listen(PORT, () => {
    const results = {}; // Or just '{}', an empty object

    for (const name of Object.keys(nets)) {
        for (const net of nets[name]) {
            // Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
            if (net.family === 'IPv4' && !net.internal) {
                if (!results[name]) {
                    results[name] = [];
                }
                results[name].push(net.address);
            }
        }
    }

    console.log('HTTP Listening on port '+PORT+'\n', results)
});
httpsServer.listen(PORT_HTTPS, () => console.log('HTTPS Listening on port '+PORT_HTTPS+'\n'));

Now in the command prompt, you have this output.

D:\Projects\IdeaProjects\OTAWebPages\OTAServer>node index.js
HTTP Listening on port 3000
 {
  Ethernet: [ '192.168.1.70' ],
  'VirtualBox Host-Only Network': [ '192.168.56.1' ],
  'VMware Network Adapter VMnet1': [ '192.168.113.1' ],
  'VMware Network Adapter VMnet8': [ '192.168.116.1' ]
}
HTTPS Listening on port 3443

Modify the sketch to do a secure HTTPs call.

To manage HTTPS connection you can use 3 ways.

Prevent certificate validation

The first is to prevent any certificate validation with this command:

client.setInsecure();

but not all servers work.

Create and add CertStore

The second is to add the certificate and key to the call, and you can do this by adding to the filesystem and preloading in the certification store like so:

  LittleFS.begin();

  int numCerts = certStore.initCertStore(LittleFS, PSTR("/certs.idx"), PSTR("/certs.ar"));

Add certificate and key to the client

Practically you are going to add directly to the client the certificate needed.

static const char serverCert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIDGTCCAgGgAwIBAgIULbAi2zs41Rh6AZy08xumoYMIFJQwDQYJKoZIhvcNAQEL
BQAwHDEaMBgGA1UEAwwRMTkyLjE2OC4xLjcwOjM0NDMwHhcNMjEwOTEzMDcwODUw
WhcNMjIwOTEzMDcwODUwWjAcMRowGAYDVQQDDBExOTIuMTY4LjEuNzA6MzQ0MzCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM/BTwpvOvg+Io6T5LgLCPbS
2CfFiV6y/30VuaK+Xs+PCFhogRfrxp9rNhSh5BrWc0zwZIpGHiBJmdFmTrVFHl3V
T8S1ZFUVaEhQHZThXLopDe9RpWhdGO0ePOW9qu6W8u8cXf/futMkyqCuc/YRt0pR
DLG4Bbs/c4x9IsTOfUtu48a1lEd6lyRec6l12CEG+ohGu+szwY+jRGgBfOJdkxDi
FCBLFmimc/rZeKe18zV/95lU/Cz3DD/kNUsVCzSOLYu4I+3FqiQ2CSq3TAYdLpA1
pYNsHsgGFt6DuguDQcfPZIwmRisaSZaGS74FWRZZ/2ycwr9GM3Y00wDMwYAOhI8C
AwEAAaNTMFEwHQYDVR0OBBYEFKyvsHqrsHBj+V5H8aDT5qvPOSfdMB8GA1UdIwQY
MBaAFKyvsHqrsHBj+V5H8aDT5qvPOSfdMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
hvcNAQELBQADggEBALwdlitiQayOG2o2y3BAipcdaMxdGbihorheuO17glsZtp2R
H2LUUqnmG8hGH4pHbkd2gozxLt/h7ILrD1xK/EIlXjGueu3MF377GWZpR18OXt+1
cqpxDdAESD3PRbcJnu75uffFYLSKizbuaTbV2D8RY1kcUxRlrFG2bciNP9widbjq
T9B4RhtJb0d+Sk8Z2G2eTlNxESPQ/Oi530rrbZsez0XmdYyogbVHuNdwJvfQdA8U
F1UtWj6vtGAramUn0dS5rJ8REfZ4jdGsXYT2jmCfDTgaE+1sEYm6ry+RInDK5RVi
Kk+bL292uc4d0STCqXciv7YbWDWlZPo9fH0Pxs0=
-----END CERTIFICATE-----
)EOF";

static const char serverKey[] PROGMEM =  R"EOF(
-----BEGIN RSA PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDPwU8Kbzr4PiKO
k+S4Cwj20tgnxYlesv99Fbmivl7PjwhYaIEX68afazYUoeQa1nNM8GSKRh4gSZnR
Zk61RR5d1U/EtWRVFWhIUB2U4Vy6KQ3vUaVoXRjtHjzlvarulvLvHF3/37rTJMqg
rnP2EbdKUQyxuAW7P3OMfSLEzn1LbuPGtZRHepckXnOpddghBvqIRrvrM8GPo0Ro
AXziXZMQ4hQgSxZopnP62XintfM1f/eZVPws9ww/5DVLFQs0ji2LuCPtxaokNgkq
t0wGHS6QNaWDbB7IBhbeg7oLg0HHz2SMJkYrGkmWhku+BVkWWf9snMK/RjN2NNMA
zMGADoSPAgMBAAECggEBAMQ8NHuHquy2TA/edAi/K51wdInElUekzZyJ+8lUBdwJ
n3laZK2CoB8OtotwizQqYchHvL+7EVOwEaFwAGJKQi+hf/Iu3/FaAiFjwz1QTTTt
+GKX/SQB47x9dkoPCDjKzfa7FbLN0fsEYny5q4C/JSEGQ3ZOeuNuQKdvv3qkDEdF
Z90JBHWzOrfUR2SpHuuk366ixwBjohOwyOHSP8VLXfPYp/RcgU/7/cRBSPN+xxIB
2Ovv/ERnTUbLqYlgU0Ok5KMMc7RmtXO9mwE6wFwNGJImYgn4IcCxAe41h6UTxmaG
gdeS2Ixil20Fi7wuLntOGkaqGewdjmjZN2apJ33gCukCgYEA7zE0hVzgfzLXPRVe
y7ouuLLrhZlkJfFsk75aVv9vfLD4eX6JgN/VU34vqmzqVSdszfum6fWyycSXwc9s
xrCLMYMS9lbz/HuiQn1c+7mZT+3hF4Qazy4ZU1rA4CBgGoyJK4eiO7tC9Vl29PvR
osDTdCOjJbIOCIAKsswrixHfgDsCgYEA3lqWDEuxQTctplL6gtXRUyBAooMLrrGZ
9/5Ut3qLlTWqdKr5+RlJCF4hc/1iYQHxDq+6SV2GpOO/0E7w0GlcoO3ME+AMf4qq
OHMcAGoJXYCEw/0u2MjuEnXlo8L3qp1+LK9rvGUViCx7Fha4OCIRuNWeJ4g8eIAl
qqzUd6fJ+70CgYEAiBDEoMzZxGIGgPAEMf5ij5zwT9qXVuJEcrNJLs41/IergWmT
DOXHs6xHrzov/2rjATYTmGm1YAPelFjLtyc8t1ip08pZFxq5jftEhsnoxcg7UKZM
nejKbVll+NlR8ihZ65JHnpUDHRDck7YgZeYtI5cWOt5UD0/PRjDQ4Fa1fnsCgYAL
+gEfBGy1wI0a6llH9tBhk9knZ7uXW0WZz/8sKtOd49gclKEGQ9BlPPy8TKeh5gLf
8aMtFHaOJx5L0BS0hRhSKrzVTTofHI7yn3CgrRV4DdYY4GhHkPsRz3vhCD1i2TzU
l1ZMPX2dahfvJqYhj+Q4enkcVAA91VkyCkEfeNAuWQKBgH+82agy+jlRyRBvQ6eI
i5n7FbCMJSw/1mfOmxGiEQhshaQkPDx+PfPgy+LOMuXAr1ZBsWMCGERdUsesXjIH
AHcY8Nl0tC5dG8q7B3A11xttwFbhQ4fgq+AUEzSH3ykTvuobGCNtM5AuawNWIjj7
VO0JDqUFQcom1brJIHowKKNU
-----END RSA PRIVATE KEY-----
)EOF";

[...]

    client.setClientRSACert(new BearSSL::X509List(serverCert), new BearSSL::PrivateKey(serverKey));

If you use a self signed certificate you must specify that with this command.

    client.allowSelfSignedCerts();

You must specify if It’s a self signed certificate

Set the clock for certificate validation

I speak about NTP service in deep in this article “Network Time Protocol (NTP), Timezone and Daylight saving time (DST) with esp8266, esp32 or Arduino” and we are going to use this function

// Set time via NTP, as required for x.509 validation
time_t setClock() {
  configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");

  Serial.print("Waiting for NTP time sync: ");
  time_t now = time(nullptr);
  while (now < 8 * 3600 * 2) {
    delay(500);
    Serial.print(".");
    now = time(nullptr);
  }
  Serial.println("");
  struct tm timeinfo;
  gmtime_r(&now, &timeinfo);
  Serial.print("Current time: ");
  Serial.print(asctime(&timeinfo));
  return now;
}

Complete sketch for secure update

Now we are going to assemble all the parts and the result is this.

/**
 * Sketch with secure and conditionally firmware update
 *
 * Renzo Mischianti <www.mischianti.org>
 *
 * https://mischianti.org
 */

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>

#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>

#include <time.h>

#ifndef APSSID
#define APSSID "<YOUR-SSID>"
#define APPSK  "<YOUR-PASSWD>"
#endif

ESP8266WiFiMulti WiFiMulti;

// Set time via NTP, as required for x.509 validation
time_t setClock() {
  configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");

  Serial.print("Waiting for NTP time sync: ");
  time_t now = time(nullptr);
  while (now < 8 * 3600 * 2) {
    delay(500);
    Serial.print(".");
    now = time(nullptr);
  }
  Serial.println("");
  struct tm timeinfo;
  gmtime_r(&now, &timeinfo);
  Serial.print("Current time: ");
  Serial.print(asctime(&timeinfo));
  return now;
}

void update_started() {
  Serial.println("CALLBACK:  HTTP update process started");
}

void update_finished() {
  Serial.println("CALLBACK:  HTTP update process finished");
}

void update_progress(int cur, int total) {
  Serial.printf("CALLBACK:  HTTP update process at %d of %d bytes...\n", cur, total);
}

void update_error(int err) {
  Serial.printf("CALLBACK:  HTTP update fatal error code %d\n", err);
}

static const char serverCert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIDGTCCAgGgAwIBAgIULbAi2zs41Rh6AZy08xumoYMIFJQwDQYJKoZIhvcNAQEL
BQAwHDEaMBgGA1UEAwwRMTkyLjE2OC4xLjcwOjM0NDMwHhcNMjEwOTEzMDcwODUw
WhcNMjIwOTEzMDcwODUwWjAcMRowGAYDVQQDDBExOTIuMTY4LjEuNzA6MzQ0MzCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM/BTwpvOvg+Io6T5LgLCPbS
2CfFiV6y/30VuaK+Xs+PCFhogRfrxp9rNhSh5BrWc0zwZIpGHiBJmdFmTrVFHl3V
T8S1ZFUVaEhQHZThXLopDe9RpWhdGO0ePOW9qu6W8u8cXf/futMkyqCuc/YRt0pR
DLG4Bbs/c4x9IsTOfUtu48a1lEd6lyRec6l12CEG+ohGu+szwY+jRGgBfOJdkxDi
FCBLFmimc/rZeKe18zV/95lU/Cz3DD/kNUsVCzSOLYu4I+3FqiQ2CSq3TAYdLpA1
pYNsHsgGFt6DuguDQcfPZIwmRisaSZaGS74FWRZZ/2ycwr9GM3Y00wDMwYAOhI8C
AwEAAaNTMFEwHQYDVR0OBBYEFKyvsHqrsHBj+V5H8aDT5qvPOSfdMB8GA1UdIwQY
MBaAFKyvsHqrsHBj+V5H8aDT5qvPOSfdMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
hvcNAQELBQADggEBALwdlitiQayOG2o2y3BAipcdaMxdGbihorheuO17glsZtp2R
H2LUUqnmG8hGH4pHbkd2gozxLt/h7ILrD1xK/EIlXjGueu3MF377GWZpR18OXt+1
cqpxDdAESD3PRbcJnu75uffFYLSKizbuaTbV2D8RY1kcUxRlrFG2bciNP9widbjq
T9B4RhtJb0d+Sk8Z2G2eTlNxESPQ/Oi530rrbZsez0XmdYyogbVHuNdwJvfQdA8U
F1UtWj6vtGAramUn0dS5rJ8REfZ4jdGsXYT2jmCfDTgaE+1sEYm6ry+RInDK5RVi
Kk+bL292uc4d0STCqXciv7YbWDWlZPo9fH0Pxs0=
-----END CERTIFICATE-----
)EOF";

static const char serverKey[] PROGMEM =  R"EOF(
-----BEGIN RSA PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDPwU8Kbzr4PiKO
k+S4Cwj20tgnxYlesv99Fbmivl7PjwhYaIEX68afazYUoeQa1nNM8GSKRh4gSZnR
Zk61RR5d1U/EtWRVFWhIUB2U4Vy6KQ3vUaVoXRjtHjzlvarulvLvHF3/37rTJMqg
rnP2EbdKUQyxuAW7P3OMfSLEzn1LbuPGtZRHepckXnOpddghBvqIRrvrM8GPo0Ro
AXziXZMQ4hQgSxZopnP62XintfM1f/eZVPws9ww/5DVLFQs0ji2LuCPtxaokNgkq
t0wGHS6QNaWDbB7IBhbeg7oLg0HHz2SMJkYrGkmWhku+BVkWWf9snMK/RjN2NNMA
zMGADoSPAgMBAAECggEBAMQ8NHuHquy2TA/edAi/K51wdInElUekzZyJ+8lUBdwJ
n3laZK2CoB8OtotwizQqYchHvL+7EVOwEaFwAGJKQi+hf/Iu3/FaAiFjwz1QTTTt
+GKX/SQB47x9dkoPCDjKzfa7FbLN0fsEYny5q4C/JSEGQ3ZOeuNuQKdvv3qkDEdF
Z90JBHWzOrfUR2SpHuuk366ixwBjohOwyOHSP8VLXfPYp/RcgU/7/cRBSPN+xxIB
2Ovv/ERnTUbLqYlgU0Ok5KMMc7RmtXO9mwE6wFwNGJImYgn4IcCxAe41h6UTxmaG
gdeS2Ixil20Fi7wuLntOGkaqGewdjmjZN2apJ33gCukCgYEA7zE0hVzgfzLXPRVe
y7ouuLLrhZlkJfFsk75aVv9vfLD4eX6JgN/VU34vqmzqVSdszfum6fWyycSXwc9s
xrCLMYMS9lbz/HuiQn1c+7mZT+3hF4Qazy4ZU1rA4CBgGoyJK4eiO7tC9Vl29PvR
osDTdCOjJbIOCIAKsswrixHfgDsCgYEA3lqWDEuxQTctplL6gtXRUyBAooMLrrGZ
9/5Ut3qLlTWqdKr5+RlJCF4hc/1iYQHxDq+6SV2GpOO/0E7w0GlcoO3ME+AMf4qq
OHMcAGoJXYCEw/0u2MjuEnXlo8L3qp1+LK9rvGUViCx7Fha4OCIRuNWeJ4g8eIAl
qqzUd6fJ+70CgYEAiBDEoMzZxGIGgPAEMf5ij5zwT9qXVuJEcrNJLs41/IergWmT
DOXHs6xHrzov/2rjATYTmGm1YAPelFjLtyc8t1ip08pZFxq5jftEhsnoxcg7UKZM
nejKbVll+NlR8ihZ65JHnpUDHRDck7YgZeYtI5cWOt5UD0/PRjDQ4Fa1fnsCgYAL
+gEfBGy1wI0a6llH9tBhk9knZ7uXW0WZz/8sKtOd49gclKEGQ9BlPPy8TKeh5gLf
8aMtFHaOJx5L0BS0hRhSKrzVTTofHI7yn3CgrRV4DdYY4GhHkPsRz3vhCD1i2TzU
l1ZMPX2dahfvJqYhj+Q4enkcVAA91VkyCkEfeNAuWQKBgH+82agy+jlRyRBvQ6eI
i5n7FbCMJSw/1mfOmxGiEQhshaQkPDx+PfPgy+LOMuXAr1ZBsWMCGERdUsesXjIH
AHcY8Nl0tC5dG8q7B3A11xttwFbhQ4fgq+AUEzSH3ykTvuobGCNtM5AuawNWIjj7
VO0JDqUFQcom1brJIHowKKNU
-----END RSA PRIVATE KEY-----
)EOF";

#define FIRMWARE_VERSION "0.2"

void setup() {

  Serial.begin(115200);
  // Serial.setDebugOutput(true);

  Serial.println();
  Serial.println();
  Serial.println();

  for (uint8_t t = 4; t > 0; t--) {
    Serial.printf("[SETUP] WAIT %d...\n", t);
    Serial.flush();
    delay(1000);
  }

  WiFi.mode(WIFI_STA);
  WiFiMulti.addAP(APSSID, APPSK);

}

const char* updateServer = "192.168.1.70";
const int updateServerPort = 3443;

void loop() {
  // wait for WiFi connection
  if ((WiFiMulti.run() == WL_CONNECTED)) {

    BearSSL::WiFiClientSecure client;

    bool mfln = client.probeMaxFragmentLength(updateServer, updateServerPort, 1024);  // server must be the same as in ESPhttpUpdate.update()
    Serial.printf("MFLN supported: %s\n", mfln ? "yes" : "no");
    if (mfln) {
      client.setBufferSizes(1024, 1024);
    }
    client.setClientRSACert(new BearSSL::X509List(serverCert), new BearSSL::PrivateKey(serverKey));
    client.allowSelfSignedCerts();
    setClock();

    // The line below is optional. It can be used to blink the LED on the board during flashing
    // The LED will be on during download of one buffer of data from the network. The LED will
    // be off during writing that buffer to flash
    // On a good connection the LED should flash regularly. On a bad connection the LED will be
    // on much longer than it will be off. Other pins than LED_BUILTIN may be used. The second
    // value is used to put the LED on. If the LED is on with HIGH, that value should be passed
    ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW);

    // Add optional callback notifiers
    ESPhttpUpdate.onStart(update_started);
    ESPhttpUpdate.onEnd(update_finished);
    ESPhttpUpdate.onProgress(update_progress);
    ESPhttpUpdate.onError(update_error);

    ESPhttpUpdate.rebootOnUpdate(false); // remove automatic update

    Serial.println(F("Update start now!"));

     t_httpUpdate_return ret = ESPhttpUpdate.update(client, "https://192.168.1.70:3443/update", FIRMWARE_VERSION);

    switch (ret) {
      case HTTP_UPDATE_FAILED:
        Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
        Serial.println(F("Retry in 10secs!"));
        delay(10000); // Wait 10secs
        break;

      case HTTP_UPDATE_NO_UPDATES:
        Serial.println("HTTP_UPDATE_NO_UPDATES");
        Serial.println("Your code is up to date!");
          delay(10000); // Wait 10secs
        break;

      case HTTP_UPDATE_OK:
        Serial.println("HTTP_UPDATE_OK");
        delay(1000); // Wait a second and restart
        ESP.restart();
        break;
    }
  }
}

The serial output is the same as the HTTP update.

[SETUP] WAIT 4...
[SETUP] WAIT 3...
[SETUP] WAIT 2...
[SETUP] WAIT 1...
Firmware version 0.2
Update start now!
CALLBACK:  HTTP update process started
CALLBACK:  HTTP update process at 0 of 307888 bytes...
CALLBACK:  HTTP update process at 0 of 307888 bytes...
CALLBACK:  HTTP update process at 4096 of 307888 bytes...
CALLBACK:  HTTP update process at 8192 of 307888 bytes...
CALLBACK:  HTTP update process at 12288 of 307888 bytes...
CALLBACK:  HTTP update process at 16384 of 307888 bytes...
CALLBACK:  HTTP update process at 20480 of 307888 bytes...
CALLBACK:  HTTP update process at 24576 of 307888 bytes...
CALLBACK:  HTTP update process at 28672 of 307888 bytes...
CALLBACK:  HTTP update process at 32768 of 307888 bytes...
CALLBACK:  HTTP update process at 36864 of 307888 bytes...
CALLBACK:  HTTP update process at 40960 of 307888 bytes...
CALLBACK:  HTTP update process at 45056 of 307888 bytes...
CALLBACK:  HTTP update process at 49152 of 307888 bytes...
CALLBACK:  HTTP update process at 53248 of 307888 bytes...
CALLBACK:  HTTP update process at 57344 of 307888 bytes...
CALLBACK:  HTTP update process at 61440 of 307888 bytes...
CALLBACK:  HTTP update process at 65536 of 307888 bytes...
CALLBACK:  HTTP update process at 69632 of 307888 bytes...
CALLBACK:  HTTP update process at 73728 of 307888 bytes...
CALLBACK:  HTTP update process at 77824 of 307888 bytes...
CALLBACK:  HTTP update process at 81920 of 307888 bytes...
CALLBACK:  HTTP update process at 86016 of 307888 bytes...
CALLBACK:  HTTP update process at 90112 of 307888 bytes...
CALLBACK:  HTTP update process at 94208 of 307888 bytes...
CALLBACK:  HTTP update process at 98304 of 307888 bytes...
CALLBACK:  HTTP update process at 102400 of 307888 bytes...
CALLBACK:  HTTP update process at 106496 of 307888 bytes...
CALLBACK:  HTTP update process at 110592 of 307888 bytes...
CALLBACK:  HTTP update process at 114688 of 307888 bytes...
CALLBACK:  HTTP update process at 118784 of 307888 bytes...
CALLBACK:  HTTP update process at 122880 of 307888 bytes...
CALLBACK:  HTTP update process at 126976 of 307888 bytes...
CALLBACK:  HTTP update process at 131072 of 307888 bytes...
CALLBACK:  HTTP update process at 135168 of 307888 bytes...
CALLBACK:  HTTP update process at 139264 of 307888 bytes...
CALLBACK:  HTTP update process at 143360 of 307888 bytes...
CALLBACK:  HTTP update process at 147456 of 307888 bytes...
CALLBACK:  HTTP update process at 151552 of 307888 bytes...
CALLBACK:  HTTP update process at 155648 of 307888 bytes...
CALLBACK:  HTTP update process at 159744 of 307888 bytes...
CALLBACK:  HTTP update process at 163840 of 307888 bytes...
CALLBACK:  HTTP update process at 167936 of 307888 bytes...
CALLBACK:  HTTP update process at 172032 of 307888 bytes...
CALLBACK:  HTTP update process at 176128 of 307888 bytes...
CALLBACK:  HTTP update process at 180224 of 307888 bytes...
CALLBACK:  HTTP update process at 184320 of 307888 bytes...
CALLBACK:  HTTP update process at 188416 of 307888 bytes...
CALLBACK:  HTTP update process at 192512 of 307888 bytes...
CALLBACK:  HTTP update process at 196608 of 307888 bytes...
CALLBACK:  HTTP update process at 200704 of 307888 bytes...
CALLBACK:  HTTP update process at 204800 of 307888 bytes...
CALLBACK:  HTTP update process at 208896 of 307888 bytes...
CALLBACK:  HTTP update process at 212992 of 307888 bytes...
CALLBACK:  HTTP update process at 217088 of 307888 bytes...
CALLBACK:  HTTP update process at 221184 of 307888 bytes...
CALLBACK:  HTTP update process at 225280 of 307888 bytes...
CALLBACK:  HTTP update process at 229376 of 307888 bytes...
CALLBACK:  HTTP update process at 233472 of 307888 bytes...
CALLBACK:  HTTP update process at 237568 of 307888 bytes...
CALLBACK:  HTTP update process at 241664 of 307888 bytes...
CALLBACK:  HTTP update process at 245760 of 307888 bytes...
CALLBACK:  HTTP update process at 249856 of 307888 bytes...
CALLBACK:  HTTP update process at 253952 of 307888 bytes...
CALLBACK:  HTTP update process at 258048 of 307888 bytes...
CALLBACK:  HTTP update process at 262144 of 307888 bytes...
CALLBACK:  HTTP update process at 266240 of 307888 bytes...
CALLBACK:  HTTP update process at 270336 of 307888 bytes...
CALLBACK:  HTTP update process at 274432 of 307888 bytes...
CALLBACK:  HTTP update process at 278528 of 307888 bytes...
CALLBACK:  HTTP update process at 282624 of 307888 bytes...
CALLBACK:  HTTP update process at 286720 of 307888 bytes...
CALLBACK:  HTTP update process at 290816 of 307888 bytes...
CALLBACK:  HTTP update process at 294912 of 307888 bytes...
CALLBACK:  HTTP update process at 299008 of 307888 bytes...
CALLBACK:  HTTP update process at 303104 of 307888 bytes...
CALLBACK:  HTTP update process at 307200 of 307888 bytes...
CALLBACK:  HTTP update process at 307888 of 307888 bytes...
CALLBACK:  HTTP update process at 307888 of 307888 bytes...
CALLBACK:  HTTP update process at 307888 of 307888 bytes...
CALLBACK:  HTTP update process finished
HTTP_UPDATE_OK

 ets Jan  8 2013,rst cause:2, boot mode:(3,6)

load 0x4010f000, len 3460, room 16 
tail 4
chksum 0xcc
load 0x3fff20b8, len 40, room 4 
tail 4
chksum 0xc9
csum 0xc9
v0005cd20
@cp:B0
ld



[SETUP] WAIT 4...
[SETUP] WAIT 3...
[SETUP] WAIT 2...
[SETUP] WAIT 1...
Firmware version 0.3
Update start now!
HTTP_UPDATE_NO_UPDATES
Your code is up to date!

Thanks

  1. ESP32: pinout, specs and Arduino IDE configuration
  2. ESP32: integrated SPIFFS Filesystem
  3. ESP32: manage multiple Serial and logging
  4. ESP32 practical power saving
    1. ESP32 practical power saving: manage WiFi and CPU
    2. ESP32 practical power saving: modem and light sleep
    3. ESP32 practical power saving: deep sleep and hibernation
    4. ESP32 practical power saving: preserve data, timer and touch wake up
    5. ESP32 practical power saving: external and ULP wake up
    6. ESP32 practical power saving: UART and GPIO wake up
  5. ESP32: integrated LittleFS FileSystem
  6. ESP32: integrated FFat (Fat/exFAT) FileSystem
  7. ESP32-wroom-32
    1. ESP32-wroom-32: flash, pinout, specs and IDE configuration
  8. ESP32-CAM
    1. ESP32-CAM: pinout, specs and Arduino IDE configuration
    2. ESP32-CAM: upgrade CamerWebServer with flash features
  9. ESP32: use ethernet w5500 with plain (HTTP) and SSL (HTTPS)
  10. ESP32: use ethernet enc28j60 with plain (HTTP) and SSL (HTTPS)
  11. How to use SD card with esp32
  12. esp32 and esp8266: FAT filesystem on external SPI flash memory
  1. Firmware and OTA update management
    1. Firmware management
      1. ESP32: flash compiled firmware (.bin)
      2. ESP32: flash compiled firmware and filesystem (.bin) with GUI tools
    2. OTA update with Arduino IDE
      1. ESP32 OTA update with Arduino IDE: filesystem, firmware, and password
    3. OTA update with Web Browser
      1. ESP32 OTA update with Web Browser: firmware, filesystem, and authentication
      2. ESP32 OTA update with Web Browser: upload in HTTPS (SSL/TLS) with self-signed certificate
      3. ESP32 OTA update with Web Browser: custom web interface
    4. Self OTA uptate from HTTP server
      1. ESP32 self OTA update firmware from the server
      2. ESP32 self OTA update firmware from the server with version check
      3. ESP32 self-OTA update in HTTPS (SSL/TLS) with trusted self-signed certificate
    5. Non-standard Firmware update
      1. ESP32 firmware and filesystem update from SD card
      2. ESP32 firmware and filesystem update with FTP client
  1. Integrating LAN8720 with ESP32 for Ethernet Connectivity with plain (HTTP) and SSL (HTTPS)
  2. Connecting the EByte E70 to ESP32 c3/s3 devices and a simple sketch example
  3. ESP32-C3: pinout, specs and Arduino IDE configuration
  4. Integrating W5500 with ESP32 Using Core 3: Native Ethernet Protocol Support with SSL and Other Features
  5. Integrating LAN8720 with ESP32 Using Core 3: Native Ethernet Protocol Support with SSL and Other Features

Spread the love

5 Responses

  1. Johan Roux says:

    Hi Renzo, I’m following your “ESP32 self OTA update firmware” tutorial but I’m having some difficulty understanding the processes and steps in the second part “with version check”. Do I need to create the “update” folder in the OTAServer directory? Also what file should I create in this folder? Please help me
    Thank you very much

  2. Philipp says:

    Just wanted to say thank you! Helped me a lot 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *