In the previous post of this tutorial, I explained how it is possible to update your board Over-The-Air thanks to a feature of the Freshen IoT dashboard.
Today I’ll show you how to update the firmware running on an esp32 chip using only components included in the esp-idf framework, without the need of any external tools or platforms.
OTA API
The esp-idf framework offers a set of native functions to implement, in your program, the ability to be updated over the air.
Those functions are grouped in the app_update component and to use them in your program you have to include the corresponding header file:
#include "esp_ota_ops.h" |
Altough the use of the native functions is not very difficult (on Github you can find an example program), Espressif developers have added a component to the framework that makes it even easier the over the air update if the new firmware is located on a web site.
The component is named esp_https_ota.
esp_https_ota
The esp_https_ota component uses the OTA API to update the firmware of your board, downloading the binary file that contains the new firmware from a web site. As the name suggests, the only requirement (for security reason) is that the web site supports the secure version of the protocol (HTTPS).
The component is able to automatically identify an OTA partition in the flash memory that is not in use and to save the new firmware in that partition. It then configures the chip to boot from that partition:
The use is very simple. First create an esp_http_client_config_t struct to configure the URL of the file with the new firmware and the SSL certificate of the server (or the certificate of the CA that signed it):
esp_http_client_config_t ota_client_config = { .url = "https://mysite.com/newfirmware.bin", .cert_pem = server_cert_pem_start, }; |
You have to provide the certificate in PEM format. To store the certificate in your program, you can leverage the embedding binary files functionality of the firmware, as I already explained in a previous tutorial.
Then you only have to call the function:
esp_err_t ret = esp_https_ota(&ota_client_config); |
to start the update process. If – when the process is complete – the ret variable contains a positive result (ESP_OK), you can reboot the chip to run the new firmware:
esp_restart(); |
A real application would probably need to periodically check if a new firmware is available and, only in that case, to start the update process. How can it be done?
In the program I wrote for this post and that is explained in the video below, I’m going to show a way widely used also in commercial products… enjoy the show 😉
Really like this Luca. Just what I need! Keep up the good work.
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.
hi Kostas, at the moment the http client used by the OTA component seems to not support mutual authentication…
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
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.
Grazie Luca per il supporto, farò come mi hai detto!
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
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?
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”}
hello
Very nice explanation…
It’s great,
does this support for nodemcu.because I am doing a project on home automation using nodemcu as a microcontroller.
you can find on the internet some tutorials about how to perform OTA using NodeMCU…
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.
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
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?
ciao Alessandro, puoi usare una qualsiasi altra partizione (es NVS)
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
I had a similar problem. How do you solve it?
hi, see answer below (he was using the wrong certificate)
Hi Luca,
Found the problem….I was using the wrong cert.
glad you solved and thanks for having reported it!
Hi Luca,
is it possible to use your example using arduino IDE?
Thanks.
Hi William, no sorry my examples are for the esp framework. I was able to google some tutorials for Arduino, give them a look!
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.
Ciao Lorenzo, puoi fare a rovescio, ovvero usare il framework esp-idf come “libreria” in Arduino… qui è spiegato come fare
Hello Luca, thank you very much, such a nice tutorial.
I’m implementing a version of this code and testing it using a local server with FLASK. I’m getting a error that guides me to a problem with server certificate pem file. When I created the self-signed certificate using:
openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
ERROR:
E (263158) esp-tls: mbedtls_ssl_handshake returned -0x2700
E (263162) esp-tls: Failed to open new connection
E (263162) TRANS_SSL: Failed to open a new connection
E (263163) HTTP_CLIENT: Connection failed, sock < 0
E (263166) esp_https_ota: Failed to open HTTP connection: ESP_ERR_HTTP_CONNECT
E (263173) esp_https_ota: Failed to establish HTTP connection
After create them, I just embedded the certificate.pem into my code to be used, but I do not know if it is completely correct to do that.
static const char server_cert_pem_start[] = \
"—–BEGIN CERTIFICATE—–\n" \
"MIIDoTCCAomgAwIBAgIUNVyUovWOLUzoT33jFP0B3OhqeYAwDQYJKoZIhvcNAQEL\n" \
"BQAwYDELMAkGA1UEBhMCdXMxCzAJBgNVBAgMAnR4MQ8wDQYDVQQHDAZ0ZW1wbGUx\n" \
….
"—–END CERTIFICATE—–\n";
After this line of code, I just get ESP_FAIL:
esp_err_t ret = esp_https_ota(&ota_client_config);
Do you have any idea how could I approach this situation?
Hope you could help
Hi carlos, did you include the SSL certificate in your
&ota_client_config
?Hi Luca,
love the idea to enable SSL OTA for my ESP32 devices as clients.
But while having a shared hosting provider with Lets Encrypt SSL Feature enabled for my domain,
how can i receive the data for generating the .pem files?
And if i have multiple esp32 client devices, do i have to generate different .pem files for each device?
Best, Thorsten
Hi! You can download the certificate from your domain or download the root CA from Let’s encrypt which is valid for all the SSL certificates it signs. You need only one pem for all your devices because it is used to “trust” the webserver they connect to.
Hi Luca,
Great tutorial, just what I needed to understand the esp-idf concept of OTA.
Having tested you example I believe that it is missing a “cJSON_Delete(json);” in order to clean up the cJSON variable ‘json’. I at least, in my setup, ran out of heap memory after some cycles in the task – a “cJSON_Delete(json);” removed that leak.
Br,
Niels
Hi Niels, thanks for your comment!
Bellessimo tutorial io ho un piccolo problema.
Buongiorno dopo aver aggiornato il certificato letsencrypt le centraline che si collegavano in otap ora restituiscono questo errore:
TRANS_SSL: mbedtls_ssl_handshake returned -0x2700
E (14987520) HTTP_CLIENT: Connection failed, sock < 0
E (14987520) esp_https_ota: Failed to open HTTP connection: ESP_ERR_HTTP_CONNECT
Non capisco se l'errore è nel server configurato con Apache letsencrypt e certificao TLS 1.2.
ciao Fabio, l’errore esadecimale indica un problema di validazione del certificato. Lato centraline avevi caricato il certificato “vecchio” oppure quello della CA di Letsencrypt?
Grazie mille per la risposta:
sulla centralina ho caricato il certificato del tuo esempio di qualche anno fa e ha funzionato fino a circa 20 giorni fa, dopo che è stato aggiornato il server con la nuova versione di Cerbot e ricreato il certificato. Il file Json lo legge (crediamo perchè utilizza connessione HTTP). Se la causa del problema è il certificato a bordo della centralina dove posso trovare un certificato funzionante?
Se utilizzo il certificato Letsencrypt che si aggiorna ogni 3 mesi devo quindi aggiornare il certificato delle periferiche ogni 3 mesi?
Oppure è possibile compilare il software senza certificato?
In questo link ho resoconto completo di un test fatto al server ( https://www.fabiozonta.it/reseconto_server.pdf ).
Saluti grazie mille per la consulenza
Ciao Fabio! Purtroppo il componente usato funziona solo in https. Per cambiare il comportamento sarebbe necessario mettere mano al sorgente del framework.
Se hai usato Let’s Encrypt, dovrebbe essere possibile caricare sulla centralina il suo certificato root prendendolo dal sito ufficiale (Root X1) in modo che la centralina si “fidi” di qualsiasi certificato poi emesso da L’sE. Non ho modo di fare un test, prova…
Grazie mille per la tua risposta, utilizzando il certificato che ci hai indicato tu l’aggiornamento è andato a buon fine. Ti chiedo un’ulterirore informazione:
Ho fatto il test con il certificato pem Self-signed e con quello Cross-signed by DST Root CA X3, secondo te quale è meglio utilizzare nelle realese sucessive?
Ho delle periferiche installate con il certificato vecchio secondo te ora è possibile aggiornarle in qualche modo? Posso dare qualche direttiva ad apache per aggiornarle?
ottimo! sicuramente ti conviene utilizzare quello “ufficiale” (DST…). purtroppo credo che per le periferiche con il vecchio certificato l’unica sia riprogrammarle (non via OTA), non penso – ma non conosco così bene apache! – che si possa fare da remoto
is it possible to use your example in my case, OTA update using encrypted binary over HTTPS
Well yes but you have to rewrite the code adding the part to decrypt the firmware before flashing
Can you help me what function should I add in my program or guide me to it, please.
unfortunately not, I don’t think you can only add a function, I suspect you have to rewrite the OTA code. Maybe you can search for someone who has already done it
Thank you very much for your answer
Luca,
You present very good tutorials. Thank you.
Regarding ESP32 OTA, have you tried to use the OTA partitions to update the ESP32 firmware from an SD card?
Also, in your tutorials, you show using the esp-idf framework to change the partition table. Do you know if there a way to do this directly through Visual Studio Code/PlatformIO?
Again, thanks for the great tutorials!
For the second part, I seem to have found my solution for setting up the partitions in platformio… pretty simple…
in platformio.ini in the env section for the processor, add, for example:
board_build.partitions = default.csv
where default.csv is the configuration that includes two equally-sized OTA partitions.
A variety of these csv files with different partition arrangements can be found here:
https://github.com/espressif/arduino-esp32/tree/master/tools/partitions
and more on this is here:
https://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
So now, we still have the question of using SD card to load the OTA partitions…
Ciao Luca! complimenti per il blog ed i progetti molto appassionanti!
Mi piace programmare gli esp con pio nel fw arduino ma non sono poi così esperto, dato che non ho la necessità di avere il mio progetto accessibile da internet ma solo all’interno del wifi di casa, mi chiedevo se ci fosse la possibilità di caricare il firmware via ota senza l’utilizzo di https, certificati ecc… in modo più semplice insomma per cominciare. Grazie!!
Ciao Luca, puoi provare la libreria AsyncElegantOTA (https://github.com/ayushsharma82/AsyncElegantOTA) che dovrebbe proprio fare al caso tuo
Excellent tutorial grate work.
Question Under which name are the source code of the program in your Github repository? It is numbered 36 but the repository only goes to 30
Ciao Luca, grazie per tutto questo grande lavoro.
Ho bisogno di implementare questa soluzione, ma invece di connettermi tramite Wifi, ho bisogno di connettermi tramite un modem cellulare SIM7600G.
Conosci qualche implementazione già fatta “out of the box” per questo?
Sto sviluppando in Argentina (per sfruttare il mio campo di allevamento come laboratorio) e a marzo ho intenzione di trasferirmi a Macerata. Mi piace molto quella regione, il mare e l’Opera estiva allo Sferisterio.
Cordiali saluti,
Orazio