ESP32 OTA (Over-The-Air) Updates using AsyncElegantOTA Library and Arduino IDE

In this user guide, we will learn an interesting feature of the ESP32 module that will allow us to perform over-the-air (OTA) updates. This means that the ESP32 module like other WiFi enabled microcontrollers has the feature to update the firmware or update files to the filesystem wirelessly. There are several ways to accomplish the OTA updates but we will use the AsyncElegantOTA library to achieve it. Through this library, a web server will be created that will allow us to upload new firmware/ files to the ESP32’s SPIFFS without any physical connection. All the updating will occur wirelessly (OTA) without physically connecting the ESP32 module to a computer via a USB cable.

ESP32 OTA updates AsyncElegantOTA using Arduino IDE

We also have a similar guide with VS Code and PlatformIO:

OTA Introduction

In embedded systems and especially in IoT applications, the devices are usually deployed at remote locations. Therefore, it is very inconvenient to get physical access to these devices to perform applications updates. Over the air or OTA is a commonly used process to update the firmware of these devices wirelessly without having physical access to devices. For example, you have developed a new IoT device and deployed thousands of such devices at different remote locations. After some time, your customer asked you to add a new feature to the device.

You have created a new feature as per the demand of the client. But the question is how you will update the new firmware to these thousands of devices that are already deployed at remote locations? Performing updates one by one by getting physical access to each device will be a wastage of time and resources. By using OTA, we can simply update the firmware of all devices with one click from a remote server wirelessly.

ESP32 OTA Updates using AsyncElegantOTA library

Through OTA programming, the ESP32 board will wirelessly update new sketches. With the help of the AsyncElegantOTA library, there will also be a feature to upload files onto the ESP32 SPIFFS. No physical access is required. Only a stable internet connection will be the requirement. Thus, without any serial connection, we will perform OTA updates. One major inconvenience of using OTA is that we would have to manually add additional code for the OTA functionality for every sketch.

Async ElegantOTA library Arduino IDE

The AsyncElegantOTA library will allow the user to access a web server through which new firmware could be uploaded as well as files could also be uploaded to the ESP32’s filesystem wirelessly. The files will be converted in .bin format before uploading them with this method. Additionally, we will use the ESPAsyncWebServer library to create the OTA web server which is compatible with the AyncElegantOTA library. By the end of this article, you will be able to add the OTA functionality in all the web servers which you previously created using the ESPAsyncWebServer library.

To implement OTA functionality in ESP32, we can choose between various methods. The two most common ones are by using basic OTA where the updates are made through the Arduino IDE or by using a web updater OTA where the web browser will cater to the OTA updates. We will, however, use the AsyncElegantOTA library which works well with the asynchronous web servers we have already created in various articles through the ESPAsyncWebServer library.

Key Advantages of using AsyncElegantOTA Library

  • Easy to integrate with asynchronous web server projects created through the ESPAsyncWebServer library
  • Provides an interactive and visually pleasing interface for the web server
  • Can update new sketches to the ESP32 module as well as upload files to the ESP32 SPIFFS

How to use AsyncElegantOTA Library to Upload Files

  • Firstly, we will create an Arduino sketch for the OTA web updater. This will be uploaded to the ESP32 through a serial connection with the computer via a USB cable. You will require the AsyncElegantOTA library, AsyncTCP and the ESPAsyncWebServer libraries for this step.
  • Inside the Arduino sketch, you will have to include the following lines of code to easily incorporate the OTA updates via the AsyncElegantOTA library: 
  • 1. Include the library: #include <AsyncElegantOTA.h>
  • 2. Add this line before starting the server: AsyncElegantOTA.begin(&server).
  • 3. Lastly, in the loop() function add the line: AsyncElegantOTA.loop().
  • Th OTA web updater sketch will create a web browser that we can access by typing http://IP_Address/update in the search bar. Through this web updater, we will be able to upload new firmware/ add files onto the ESP32 filesystem.
  • Afterwards, for every sketch you upload, you will have to add the additional code for the OTA functionality to upload files/sketches wirelessly.

Setting up Arduino IDE

We will use Arduino IDE to program our ESP32 development board. Thus, you should have the latest version of Arduino IDE. Additionally, you also need to install the ESP32 plugin. If your IDE does not have the plugin installed you can visit the link below:

Installing ESP32 library in Arduino IDE and upload code.

Installing AsyncElegantOTA Library

We will use the Library Manager in our Arduino IDE to install the latest version of the library. Open your Arduino IDE and go to Sketch > Include Libraries > Manage Libraries. Type AsyncElegantOTA name in the search bar and install it.

AsyncElegantOTA library install

Installing ESPAsyncWebServer Library and Async TCP Library

We will need two additional libraries to build our web server. The ESPAsyncWebServer library will help us in creating our web server easily. With this library, we will set up an asynchronous HTTP server. AsyncTCP is another library that we will be incorporating as it a dependency for the ESPAsyncWebServer library. Both of these libraries are not available in the Arduino library manager so we will have to download and load them in our ESP32 board ourselves.

  • To install ESPAsyncWebServer library for free, click here to download. You will download the library as a .zip folder which you will extract and rename as ‘ESPAsyncWebServer.’ Then, transfer this folder to the installation library folder in your Arduino IDE.
  • To install Async TCP library for free, click here to download. You will download the library as a .zip folder which you will extract and rename as ‘AsyncTCP.’ Then, transfer this folder to the installation library folder in your Arduino IDE.

Likewise, you can also go to Sketch > Include Library > Add .zip Library inside the IDE to add the libraries as well. After installation of the libraries, restart your IDE.

Example 1: Arduino Sketch AsyncElegantOTA ESP32

Open your Arduino IDE and go to File > New. A new file will open. Copy the code given below in that file and save it. You just need to enter your network credentials.

This sketch creates an ESP32 web server that displays a simple text message on the /root URL and the ElegantOTA web page on the /update URL. The web page will allow the user to update new firmware/upload files to ESP32 SPIFFS.

#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>

const char* ssid = "PTCL-BB";   //replace with your SSID
const char* password = "*********";   //replace with your password

AsyncWebServer server(80);

void setup(void) {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send(200, "text/plain", "Hello! This is a simple text message sent from ESP32. Microcontrollerslab");
  });

  AsyncElegantOTA.begin(&server);    // Start ElegantOTA
  server.begin();
  Serial.println("HTTP server started!");
}

void loop(void) {
  AsyncElegantOTA.loop();
}

How the Code Works?

Including Libraries

Firstly, we will include the necessary libraries. For this project, we are using five of them. Arduino.h, WiFi.h, ESPAsyncWebServer.h, AsyncTCP.h and AsyncElegantOTA.h. As we have to connect our ESP32 to a wireless network hence we need WiFi.h library for that purpose. The other libraries are the ones that we recently downloaded and will be required for the building of the asynchronous web server as well as for the OTA functionality.

#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>

Setting Network Credentials

Next, we will create two global variables, one for the SSID and the other for the password. These will hold our network credentials which will be used to connect to our wireless network. Replace both of them with your credentials to ensure a successful connection.

const char* ssid = "PTCL-BB";   //replace with your SSID
const char* password = "********";   //replace with your password

Creating the AsyncWebServer Object

The AsyncWebServer object will be used to set up the web server. We will pass the default HTTP port which is 80, as the input to the constructor. This will be the port where the server will listen to the requests.

AsyncWebServer server(80);

setup() function

Inside the setup() function, we will open a serial connection at a baud rate of 115200.

Serial.begin(115200);

The following section of code will connect our ESP32 board with the local network whose network credentials we already specified above. After the connection will be established, the IP address of the ESP board will get printed on the serial monitor. This will help us to make a request to the server.

WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

ESP32 Handling Requests

We will deal with the /root URL request which the ESP32 board will receive. The handling function will respond to the client by using the send() method on the request object. This method will take in three parameters. The first is 200 which is the HTTP status code for ‘ok’. The second is “text/plain” which will correspond to the content type of the response. The third input is the content of the text which will be displayed.

 server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send(200, "text/plain", "Hello! This is a simple text message sent from ESP32. Microcontrollerslab");
  });

Starting Connection

In the next line we will initiate ElegantOTA.


AsyncElegantOTA.begin(&server);    // Start ElegantOTA

To start the server, we will call the begin() on our server object. On the Serial Monitor, you will be able to view the message: ‘HTTP server started!’

  server.begin();
 Serial.println("HTTP server started!");

loop()

Inside the infinite loop() function, we will call AsyncElegantOTA.loop() to continue the connection indefinitely.

AsyncElegantOTA.loop();

Demonstration

Choose the correct board and COM port before uploading your code to the board. Go to Tools > Board and select ESP32 Dev Module.

select esp32 board

Next, go to Tools > Port and select the appropriate port through which your board is connected.

Selecting COM PORT ESP32

Click on the upload button to upload the code into the ESP32 development board.
After you have uploaded your code to the ESP32 development board press its ENABLE button.

ESP32 enable reset button

In your Arduino IDE, open up the serial monitor and you will be able to see the IP address of your ESP32 module.

ESP32 OTA updates via AsyncElegantOTA example1 demo serial monitor
Serial Monitor

Copy that address into a web browser and press enter. The following web page will open displaying the plain text:

ESP32 OTA updates via AsyncElegantOTA example1 demo1

Now type /update beside the IP Address in the search tab and press enter. The following ElegantOTA web server will open.

ESP32 OTA updates via AsyncElegantOTA example1 demo2

In the next two examples, we will learn how to use this web server to:

  • Upload new firmware wirelessly (Example 2)
  • Upload files on the ESP32 filesystem wirelessly (Example 3)

Example 2: Uploading new firmware (ESP32 OTA Updates)

Now, we will show you how to upload new sketches to the ESP32 board over the air using the OTA web server which we created above. For demonstration purposes, we will take the program code from a previous article: ESP32 WebSocket Server using Arduino IDE – Control GPIOs and Relays. In that tutorial, we created an ESP32 web server by using a WebSocket communication protocol and Arduino IDE. The web server controlled the onboard LED of the ESP32 module. We will take that project a step ahead and include OTA functionality inside it. Previously, we used a serial connection between the ESP32 board to upload the code. Now, we will create the same WebSocket web server but upload the code to ESP32 wirelessly. With the help of the AsyncElegantOTA library it will become very easy. Let us learn how to implement it.

As we previously mentioned, to upload firmware via ElegantOTA we have to make sure that the file we upload is in .bin format. This can be easily done through Arduino IDE. Inside your IDE go to Sketch > Export Compiled Binary. This will generate a .bin file of your associated sketch. Its as simple as that.

Arduino Sketch AsyncElegantOTA Uploading new sketch

Open your Arduino IDE and go to File > New. A new file will open. Copy the code given below in that file and save it as ‘ESP32_WebSocket_Webserver_OTA.’ Remember to replace the network credentials with your values.

// Import required libraries
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>

// Replace network credentials with your own WiFi details
const char* ssid = "PTCL-BB";
const char* password = "********";

bool GPIO_State = 0;
const int Led_Pin = 2;

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
AsyncWebSocket ws("/ws");

const char html_page[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <title>ESP32 Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <style>
  html {
    font-family: New Times Roman;
    text-align: center;
  }
  h1 {
    font-size: 1.8rem;
    color: white;
  }
  h2{
    font-size: 1.5rem;
    font-weight: bold;
    color: #612b78;
  }
  .topnav {
    overflow: hidden;
    background-color: #612b78;
  }
  body {
    margin: 0;
  }
  .content {
    padding: 30px;
    max-width: 600px;
    margin: 0 auto; 
  }
  .button {
    padding: 15px 50px;
    font-size: 24px;
    text-align: center;
    outline: none;
    color: #fff;
    background-color:#fa0f0f;  //green
    border: none;
    border-radius: 5px;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: rgba(0,0,0,0);
   }
  .button:active {
     background-color:#fa0f0f ; 
     transform: translateY(2px);
   }
   .state {
     font-size: 1.5rem;
     color:#120707;
     font-weight: bold;
   }
  </style>
<title>ESP32 Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
</head>
<body>
  <div class="topnav">
    <h1>ESP32 WebSocket Server</h1>
  </div>
  <div class="content">
      <h2>ONBOARD LED GPIO2</h2>
       <p><button id="button" class="button">Click to Toggle</button></p>
      <p class="state">State: <span id="state">%STATE%</span></p>
  </div>
  </div>
<script>
  var gateway = `ws://${window.location.hostname}/ws`;
  var websocket;
  window.addEventListener('load', onLoad);
  function initWebSocket() {
    console.log('Trying to open a WebSocket connection...');
    websocket = new WebSocket(gateway);
    websocket.onopen    = onOpen;
    websocket.onclose   = onClose;
    websocket.onmessage = onMessage; // <-- add this line
  }
  function onOpen(event) {
    console.log('Connection opened');
  }
  function onClose(event) {
    console.log('Connection closed');
    setTimeout(initWebSocket, 2000);
  }
  function onMessage(event) {
    var state;
    if (event.data == "1"){
      state = "ON";
    }
    else{
      state = "OFF";
    }
    document.getElementById('state').innerHTML = state;
  }
  function onLoad(event) {
    initWebSocket();
    initButton();
  }
  function initButton() {
    document.getElementById('button').addEventListener('click', toggle);
  }
  function toggle(){
    websocket.send('toggle');
  }
</script>
</body>
</html>
)rawliteral";

void notifyClients() {
  ws.textAll(String(GPIO_State));
}

void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
  AwsFrameInfo *info = (AwsFrameInfo*)arg;
  if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
    data[len] = 0;
    if (strcmp((char*)data, "toggle") == 0) {
      GPIO_State = !GPIO_State;
      notifyClients();
    }
  }
}

void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type,
             void *arg, uint8_t *data, size_t len) {
  switch (type) {
    case WS_EVT_CONNECT:
      Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
      break;
    case WS_EVT_DISCONNECT:
      Serial.printf("WebSocket client #%u disconnected\n", client->id());
      break;
    case WS_EVT_DATA:
      handleWebSocketMessage(arg, data, len);
      break;
    case WS_EVT_PONG:
    case WS_EVT_ERROR:
      break;
  }
}

void initWebSocket() {
  ws.onEvent(onEvent);
  server.addHandler(&ws);
}

String processor(const String& var){
  Serial.println(var);
  if(var == "STATE"){
    if (GPIO_State){
      return "ON";
    }
    else{
      return "OFF";
    }
  }
}

void setup(){
  // Serial port for debugging purposes
  Serial.begin(115200);

  pinMode(Led_Pin, OUTPUT);
  digitalWrite(Led_Pin, LOW);
  
  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  // Print ESP Local IP Address
  Serial.println(WiFi.localIP());

  initWebSocket();

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", html_page, processor);
  });

AsyncElegantOTA.begin(&server);
  server.begin();
}

void loop() {
  AsyncElegantOTA.loop();
  ws.cleanupClients();
  digitalWrite(Led_Pin, GPIO_State);
 
}

To understand how the code works you can have a look at the article here. All the code is the same except for the additional three lines we have added to include the OTA updates functionality via the AsyncElegantOTA library.

Demonstration

After saving the sketch go to Sketch > Export Compiled Binary. This will create a .bin file of your sketch. Now we will upload this .bin file to the ElegantOTA web server which we created in Example 1.

Before proceeding further, make sure your ESP32 is powered ON and has the sketch from Example 1 uploaded.

In a new browser type IP address/update and press enter. In our case, we will type 192.168.10.19/update. You will use the IP address for your own ESP32 module. After pressing enter, the ElegantOTA web page will be displayed. Check Firmware and upload the .bin file by clicking Choose File and selecting it. You will find the .bin file associated with your project in a folder with the same name as your sketch. The process will start.

ESP32 OTA updates via AsyncElegantOTA example2 demo1

After a few moments the process will be completed. Click the Back button to go back to the main web page.

ESP32 OTA updates via AsyncElegantOTA example2 demo2

Now type the /root URL in a new browser and press enter. The ESP32 WebSocket web server will open.

ESP32 OTA updates via AsyncElegantOTA example2 demo3

Now click the toggle button. The onboard LED of the ESP32 board will light up. At the same moment, the state will also be updated to ‘ON’. Now keep on clicking the button and the state will automatically update accordingly and the LED will turn on/off.

VS Code blinking led demo

Thus, we were able to successfully upload a new sketch to our ESP32 board wirelessly through ElegantOTA.

Example 3: Uploading files to ESP32 filesystem via ElegantOTA

Now, we will learn how to upload files to the ESP32’s filesystem SPIFFS wirelessly using the OTA web server which we created in Example 1. For demonstration purposes, we will take the program code from a previous article: ESP32 Web Server with SPIFFS (SPI Flash File System). In that tutorial, we created a web server with ESP32 using SPIFFS and Arduino IDE. This was done by storing the CSS and HTML files in the SPI flash file system of ESP32 and building a web server through those files. Instead of hard coding the HTML as string literals which takes up a lot of memory, the SPIFFS helped us access the flash memory of the ESP32 core.

Thus, we will take that project a step ahead in this example and include OTA functionality inside it. Previously, we used a serial connection between the ESP32 board to upload the code. Now, we will create the same SPIFFS web server but upload the files to the ESP32’s filesystem as well as the sketch via OTA. With the help of the AsyncElegantOTA library, it will become very easy. Let us learn how to implement it.

Prerequisites

You will have to download and install the ESP32 Filesystem Uploader Plugin in your Arduino IDE so that you are able to upload the SPIFFS files on your ESP32 board. If you haven’t, you can follow this tutorial:

Install ESP32 Filesystem Uploader in Arduino IDE – SPIFFS

Creating Files for SPIFFS

With SPIFFS, we can save HTML, CSS, and JavaScript files in ESP32 flash file system. Whenever a web client makes an HTTTP request, we can serve these files directly from SPIFFS. To build an ESP32 web server using SPIFFS, we will create three different files: HTML, CSS, and Arduino sketch and organize them in a project folder. Both the CSS and HTML files will be placed inside the ‘data’ folder. This ‘data’ folder will be inside the project folder.

Note: You should place HTML and CSS files inside the data folder. Otherwise, SPIFFS library will not be able to read these files.

HTML file

Inside our HTML file, we will include the title, a paragraph for the GPIO state, and two on/off buttons.

Now, create an html.index file and replicate the code given below in that file.

<!DOCTYPE html>
<html>

<head>
  <title>ESP32 WEB SERVER</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css"
    integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
  <link rel="stylesheet" type="text/css" href="style.css">
</head>

<body>
  <h2>ESP32 WEB SERVER</h2>
  <div class="content">
    <div class="card-grid">
      <div class="card">
        <p><i class="fas fa-lightbulb fa-2x" style="color:#c81919;"></i>     <strong>GPIO2</strong></p>
        <p>GPIO state: <strong> %GPIO_STATE%</strong></p>
        <p>
          <a href="/led2on"><button class="button">ON</button></a>
          <a href="/led2off"><button class="button button2">OFF</button></a>
        </p>
      </div>
    </div>
  </div>
</body>

</html>

CSS File

Next, create another file “style.css” in the same folder as the HTML file and replicate the code given below in that file.

html {
  font-family: Arial;
  display: inline-block;
  margin: 0px auto;
  text-align: center;
}
h1{
  color: #070812;
  padding: 2vh;
}
.button {
  display: inline-block;
  background-color: #b30000; //red color
  border: none;
  border-radius: 4px;
  color: white;
  padding: 16px 40px;
  text-decoration: none;
  font-size: 30px;
  margin: 2px;
  cursor: pointer;
}
.button2 {
  background-color: #364cf4; //blue color
}
.content { 
  padding: 50px;
}
.card-grid {
  max-width: 800px;
  margin: 0 auto;
  display: grid;
  grid-gap: 2rem;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.card {
  background-color: white;
  box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
}
.card-title {
  font-size: 1.2rem;
  font-weight: bold;
  color: #034078
}

Arduino Sketch SPIFFS OTA Web Server

Open your Arduino IDE and go to File > New. A new file will open. Copy the code given below in that file and save it as ‘ESP32_SPIFFS_Webserver_OTA.’ Remember to replace the network credentials with your values.

#include "WiFi.h"
#include "ESPAsyncWebServer.h"
#include "SPIFFS.h"
#include <AsyncElegantOTA.h>


const char* ssid = "PTCL-BB"; //Replace with your own SSID
const char* password = "*********"; //Replace with your own password

const int ledPin = 2;
String ledState;

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

// Replaces placeholder with LED state value
String processor(const String& var){
  Serial.println(var);
  if(var == "GPIO_STATE"){
    if(digitalRead(ledPin)){
      ledState = "ON";
    }
    else{
      ledState = "OFF";
    }
    Serial.print(ledState);
    return ledState;
  }
  return String();
}
 
void setup(){

  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);

  // Initialize SPIFFS
  if(!SPIFFS.begin(true)){
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }

  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  // Print ESP32 Local IP Address
  Serial.println(WiFi.localIP());

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/index.html", String(), false, processor);
  });
  
  // Route to load style.css file
  server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/style.css", "text/css");
  });

  // Route to set GPIO to HIGH
  server.on("/led2on", HTTP_GET, [](AsyncWebServerRequest *request){
    digitalWrite(ledPin, HIGH);    
    request->send(SPIFFS, "/index.html", String(), false, processor);
  });
  
  // Route to set GPIO to LOW
  server.on("/led2off", HTTP_GET, [](AsyncWebServerRequest *request){
    digitalWrite(ledPin, LOW);    
    request->send(SPIFFS, "/index.html", String(), false, processor);
  });

// Start ElegantOTA
  AsyncElegantOTA.begin(&server);
  // Start server
  server.begin();
}
 
void loop(){
  AsyncElegantOTA.loop();
  
}

To understand how the code works you can have a look at the article here. All the code is same except for the additional three lines which we have added to include the OTA updates functionality via AsyncElegantOTA library.

Now let us proceed further.

Updating new sketch

After saving this sketch, go to Sketch > Export Compiled Binary. This will create a .bin file of your sketch. Now we will upload this .bin file to the ElegantOTA web server which we created in Example 1. Follow the same steps to upload this sketch to ElegantOTA web server like we did previously for Example 2.

Updating Filesystem

Now after you have created both the HTML and CSS files and placed them inside the data folder it is time to upload them to the filesystem. At this point our project folder should look like this:

ESP32 OTA updates via AsyncElegantOTA example3

To view your project folder go to Sketch > Show Project Folder. The ESP32_SPIFFS_Webserver_OTA folder will consist of: the .ino Arduino sketch file, the .bin file of the Arduino sketch and the data folder containing the CSS and HTML files.

Now go to Tools > ESP32 Data Sketch Upload.

SPIFFS sketch data upload

You will get an error ‘SPIFFS upload failed.’ This is because the ESP32 board is not connected serially to the computer. Scroll down until you reach the destination where the .spiffs.bin file is located. This is highlighted below:

ESP32 OTA updates via AsyncElegantOTA example3 pic1

This is the file which we have to upload on the filesystem in the ElegantOTA web server. To do that follow the steps carefully.

Enabling Hidden Items

On your computer go to This PC > View and check Hidden items.

ESP32 OTA updates via AsyncElegantOTA example3 pic2

As AppData was previously not visible to us now we will be able to view our file by following the path which we highlighted in yellow above.

This is the file which we will upload on the filesystem via ElegantOTA:

ESP32 OTA updates via AsyncElegantOTA example3 pic3

In a new browser type IP address/update and press enter. In our case, we will type 192.168.10.19/update. You will use the IP address for your own ESP32 module. After pressing enter the ElegantOTA web page will be displayed. Check Filesystem and upload the highlighted file by clicking Choose File and selecting it.

ESP32 OTA updates via AsyncElegantOTA example3 pic4

After few moments, the process will be completed. Click the Back button to go back to the main web page.

ESP32 OTA updates via AsyncElegantOTA example2 demo2

Now type the /root URL in a new browser and press enter. The ESP32 SPIFFS web server will open.

ESP32 OTA updates via AsyncElegantOTA example3 pic5

Now, press the ON and OFF buttons and the on-board LED will turn on and off accordingly. The GPIO state on the web server will also change and get updated.

To go back to the ElegantOTA web server type /update with the root / URL. Thus, we were successfully able to upload HTML and CSS files to the ESP32 filesystem to create a web server.

Conclusion

In conclusion, we were able to learn a very useful feature of ESP32 through this article today. In this comprehensive guide, we learned how to update new firmware in ESP32 via OTA using the AsyncElegantOTA library. Not only were we able to upload new sketches, but we were also able to upload files to the ESP32’s SPIFFS. We incorporated examples from previously performed projects where we created asynchronous web servers using the ESPAsyncWebServer library.

4 thoughts on “ESP32 OTA (Over-The-Air) Updates using AsyncElegantOTA Library and Arduino IDE”

  1. Hi. Thanks for the tutorial. I was using arduion 2 beta, but it didn’t support elegantOTA file uploads using the ESP32_Sketch_Data_Upload tool, so I dropped back to ardruino ide 1.8.16, which does support the tool. However, I can export the firmware binary and upload it via ElegantOTA, but when I run the ESP32_Sketch_Data_Upload tool to update spiffs files, it immediately says “SPIFFS Error: serial port not defined!” and stops compilation/uploading. So, it never creates the spiffs.bin file that I need to upload via OTA to the ESP32. Any suggestions other than possibly going backwards further with the IDE?? I’d really like to be able to update the firmware and files remotely or I’ll have to continually disconnect my esp32 to reprogram it for updates. Thanks in advance!

    Reply
    • Enter some port, it doesn’t have to be real. It will then create a .bin file and try to transfer it. You can also use VS Code + PlatformIO.

      Reply
  2. The latest version of AsyncElegantOTA has deprecated the loop() function, so the line in the project’s loop function no longer should call “AsyncElegantOTA.loop();”.

    Reply

Leave a Comment