ESP32 self OTA update firmware from a server with version check - 2 (original) (raw)

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

Toggle

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

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.

/*

#include <Arduino.h>

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

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

#include <SPIFFS.h>

#ifndef APSSID #define APSSID "" #define APPSK "" #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

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:

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.

/**

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

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

#include <time.h>

#ifndef APSSID #define APSSID "" #define APPSK "" #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
  13. 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
  14. Integrating LAN8720 with ESP32 for Ethernet Connectivity with plain (HTTP) and SSL (HTTPS)
  15. Connecting the EByte E70 to ESP32 c3/s3 devices and a simple sketch example
  16. ESP32-C3: pinout, specs and Arduino IDE configuration
  17. Integrating W5500 with ESP32 Using Core 3: Native Ethernet Protocol Support with SSL and Other Features
  18. Integrating LAN8720 with ESP32 Using Core 3: Native Ethernet Protocol Support with SSL and Other Features
  19. Dallas ds18b20:
  20. Guide to I2C on ESP32: Communication with Heterogeneous 5V and 3.3V Devices, Additional Interface Management and Scanner