ESP32 (37) – https OTA

by luca
23 comments

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:

https_ota_001

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 😉

as usual, the source code of the program is available in my Github repository

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

Related Posts

23 comments

Andrew Sweeney Wednesday December 12th, 2018 - 05:08 PM

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

Reply
Kostas Thursday January 17th, 2019 - 12:17 PM

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 Saturday January 19th, 2019 - 09:50 AM

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

Reply
Andrea Thursday February 7th, 2019 - 10:06 PM

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 Saturday February 9th, 2019 - 04:00 PM

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 Sunday February 10th, 2019 - 03:30 PM

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

Reply
Mattia Berton Tuesday February 12th, 2019 - 06:04 PM

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 Saturday February 16th, 2019 - 11:22 AM

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 Monday February 18th, 2019 - 05:12 AM

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 Tuesday March 5th, 2019 - 02:38 PM

hello
Very nice explanation…

Reply
Sarath Tuesday March 26th, 2019 - 10:54 AM

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

Reply
luca Thursday April 4th, 2019 - 08:11 AM

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

Reply
shivani Friday March 29th, 2019 - 10:45 AM

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 Thursday April 4th, 2019 - 08:09 AM

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 Wednesday August 14th, 2019 - 09:53 AM

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 Wednesday August 28th, 2019 - 02:41 PM

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

Reply
Len Halio Monday March 30th, 2020 - 04:57 PM

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 Monday March 30th, 2020 - 06:17 PM

Hi Luca,

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

Reply
luca Monday April 6th, 2020 - 01:20 PM

glad you solved and thanks for having reported it!

Reply
william Thursday May 28th, 2020 - 11:42 AM

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

Reply
luca Monday June 1st, 2020 - 10:47 AM

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 Sunday May 31st, 2020 - 02:24 AM

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 Monday June 1st, 2020 - 10:45 AM

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

Reply

Leave a Comment

one × 1 =