ESP32 (37) – OTA via https

by luca
23 comments

Nel precedente articolo di questo tutorial, vi ho mostrato come sia possibile effettuare un aggiornamento Over-The-Air grazie alle funzionalità della dashboard Freshen.

Oggi vi spiegherò come aggiornare il firmware in esecuzione sul chip esp32 utilizzando solo il framework esp-idf, senza la necessità di dashboard esterne.

OTA API

Il framework esp-idf mette a disposizione una serie di funzioni native per implementare, in un nostro programma, la capacità di aggiornarsi over the air.

Tali funzioni si trovano nel componente app_update e per utilizzarle dobbiamo includere il relativo header file:

#include "esp_ota_ops.h"

Sebbene non sia complesso l’utilizzo di queste funzioni native (su Github potete trovare un programma di esempio), gli sviluppatori di Espressif hanno aggiunto al framework un componente che rende ancora più facile l’aggiornamento over the air, nel caso in cui il nuovo firmware si trovi su un sito web.

Tale componente si chiama esp_https_ota.

esp_https_ota

Il componente esp_https_ota utilizza le OTA API per aggiornare il firmware, scaricando la nuova versione da un sito web. Come il nome suggerisce, l’unico requisito (per questioni di sicurezza) è che tale sito web sia disponibile con protocollo sicuro (HTTPS).

Il componente è in grado di identificare automaticamente la partizione OTA non in uso nella memoria flash e di caricare in tale partizione il nuovo firmware; configurando infine il chip per effettuare il boot da tale partizione:

https_ota_001

Il suo utilizzo è davvero semplice. Per prima cosa creiamo una struct di tipo esp_http_client_config_t dove configurare l’URL del file che contiene il nuovo firmware e il certificato SSL del server (o della CA che lo ha firmato):

esp_http_client_config_t ota_client_config = {
  .url = "https://mysite.com/newfirmware.bin",
  .cert_pem = server_cert_pem_start,
};

Il certificato deve essere fornito in formato PEM. Per caricarlo all’interno del nostro programma, possiamo utilizzare le funzionalità di embedding binary files del framework come vi ho già spiegato in un precedente tutorial.

Ora è sufficiente il comando:

esp_err_t ret = esp_https_ota(&ota_client_config);

Per avviare il processo di aggiornamento. Se al termine la variabile ret contiene un esito positivo (ESP_OK), possiamo riavviare il chip in modo che il nuovo firmware sia eseguito:

esp_restart();

In una applicazione reale, abbiamo però la necessità di controllare periodicamente se sia disponibile un nuovo firmware e, solo in tal caso, procedere con l’aggiornamento. Come possiamo fare?

Nel programma che ho preparato per questo articolo e che illustro nel video seguente, vi mostro una modalità molto utilizzata anche in progetti commerciali… buona visione 😉

come al solito, il sorgente del programma è disponibile nel mio repository Github e il video contiene sottotitoli in italiano

[youtube id=”Ck55tY7mm1c” width=”600″ height=”350″]

Related Posts

23 comments

Andrew Sweeney 12 dicembre 2018 - 17:08

Really like this Luca. Just what I need! Keep up the good work.

Reply
Kostas 17 gennaio 2019 - 12:17

Hello Luca. I would like to ask if you know any way to download OTA with HTTPS + mutual authentication. Have you ever tried this before ? I’ve been looking inside “esp_http_client_config_t” but there is no clients cert* only servers cert.

Regards, Kostas.

Reply
luca 19 gennaio 2019 - 09:50

hi Kostas, at the moment the http client used by the OTA component seems to not support mutual authentication…

Reply
Andrea 7 febbraio 2019 - 22:06

Ciao Luca, complimenti per gli articoli! C’è un modo per sostituire il certificato in formato PEM caricato nel programma con la funzionalità embedding binary files con un altro certificato senza ricompilare il firmware? Ad esempio caricandolo da scheda sd? Ho provato con le funzionalità SPI Flash APIs del framework ma non ho trovato una soluzione…
Grazie Andrea

Reply
luca 9 febbraio 2019 - 16:00

Ciao Andrea, se guardi come è fatta la struct, vedrai che il certificato è in una variabile char*, quindi puoi memorizzarlo dove preferisci (flash, sd…). Semplicemente dovrai “leggerlo” dal supporto e memorizzarlo (alla fine è una sequenza di bytes) in una variabile appunto char* che potrai poi passare alla struct.

Reply
Andrea 10 febbraio 2019 - 15:30

Grazie Luca per il supporto, farò come mi hai detto!

Reply
Mattia Berton 12 febbraio 2019 - 18:04

Ciao Luca,
innanzitutto, complimenti, davvero, per il tuo lavoro. Sei chiaro e “pulito”.
Sul firmware, ho un piccolo dubbio, nel senso che è un errore che non riesco bene a capire se ce l’ho solo io: se il programma lancia il task di aggiornamento del sistema tante volte, e non trova il firmware corretto, comincia ad avere dei problemi di leakage di memoria.
Quando anche, diciamo dopo 15 volte, trova il firmware da aggiornare, non riesce più ad aprire correttamente un socket TLS.
Ho fatto un check sulla heap, ed effettivamente noto un calo della memoria heap disponibile.

Hai mai avuto modo di approfondire?
Ciao e buon lavoro,
Mattia

Reply
luca 16 febbraio 2019 - 11:22

ciao Mattia… non mi è mai capitato ma effettivamente non ho lasciato girare a lungo il programma. Lanciando il “cleanup” finale dovrebbe liberare tutta la memoria, possibile che sia qualche bug del componente esp_http_client. Stai usando l’ultima versione del firmware?

Reply
David 18 febbraio 2019 - 05:12

Luca
Does the jSON file just contain the firmware version number and the url of the firmware?
e.g. {1.0: “https://mywebsite/firmware.bin”}

Reply
Arun 5 marzo 2019 - 14:38

hello
Very nice explanation…

Reply
Sarath 26 marzo 2019 - 10:54

It’s great,
does this support for nodemcu.because I am doing a project on home automation using nodemcu as a microcontroller.

Reply
luca 4 aprile 2019 - 08:11

you can find on the internet some tutorials about how to perform OTA using NodeMCU…

Reply
shivani 29 marzo 2019 - 10:45

Can it be possible from any network? I mean my question is that if I want to update my firmware from other location and that IP is not static, it is dynamic then can I update my firmware.

Reply
luca 4 aprile 2019 - 08:09

sure! if the server that hosts your firmware has a dynamic IP address, you have to use a dyndns service to have a “static” name for it

Reply
Alessandro 14 agosto 2019 - 09:53

Ciao, interessante e complimenti.
é possibile salvare dei dati in un posto che non viene toccato dall’aggiornamento del firmware? Ad esempio impostazioni o altro simile?

Reply
luca 28 agosto 2019 - 14:41

ciao Alessandro, puoi usare una qualsiasi altra partizione (es NVS)

Reply
Len Halio 30 marzo 2020 - 16:57

Hi Luca,

Your example code works fine but I tried using my own website (halio.us) and used the PEM certificate provided by the website host (GoDaddy) and I am getting an error message:

E (5913) esp-tls: mbedtls_ssl_handshake returned -0x2700

Reply
Len Halio 30 marzo 2020 - 18:17

Hi Luca,

Found the problem….I was using the wrong cert.

Reply
luca 6 aprile 2020 - 13:20

glad you solved and thanks for having reported it!

Reply
william 28 maggio 2020 - 11:42

Hi Luca,
is it possible to use your example using arduino IDE?
Thanks.

Reply
luca 1 giugno 2020 - 10:47

Hi William, no sorry my examples are for the esp framework. I was able to google some tutorials for Arduino, give them a look!

Reply
Lorenzo Garcia 31 maggio 2020 - 02:24

Ciao Luca, ottimo contributo. Vorrei vedere se le librerie che utilizziamo nell’ID Arduino per ESP32 possono essere utilizzate in esp-idf e, in tal caso, è possibile creare una combinazione di librerie? ad esempio, prendere le librerie di chiamata “ESPAsyncWebServer.h”.
Grazie, saluti dall’Argentina.

Reply
luca 1 giugno 2020 - 10:45

Ciao Lorenzo, puoi fare a rovescio, ovvero usare il framework esp-idf come “libreria” in Arduino… qui è spiegato come fare

Reply

Leave a Comment

20 − 19 =