ESP32 OTA (Over-the-Air) Updates – AsyncElegantOTA using Arduino IDE

In this guide, you’ll learn how to do over-the-air (OTA) updates to your ESP32 boards using the AsyncElegantOTA library. This library creates a web server that allows you to upload new firmware (a new sketch) to your board without the need to make a serial connection between the ESP32 and your computer.

Additionally, with this library, you can also upload new files to the ESP32 filesystem (SPIFFS). The library is very easy to use, and it’s compatible with the ESPAsyncWebServer library that we often use to build web server projects.

ESP32 OTA Over-the-Air Updates AsyncElegantOTA using Arduino IDE Firmware Filesystem

By the end of this tutorial, you’ll be able to easily add OTA capabilities to your web server projects with the ESP32 to upload new firmware and files to the filesystem wirelessly in the future.

We have a similar tutorial for the ESP8266 NodeMCU board: ESP8266 NodeMCU OTA (Over-the-Air) Updates – AsyncElegantOTA using Arduino IDE

Watch the Video Tutorial

This project is available in video format and in written format. You can watch the video below or you can scroll down for the written instructions.

Overview

This tutorial covers:

We recommend that you follow all the tutorial steps to understand how ElegantOTA works and how you can use it in your projects. To demonstrate how to do this, we’ll upload files to build different web server projects.

ESP32 OTA (Over-the-Air) Programming

OTA (Over-the-Air) update is the process of loading new firmware to the ESP32 board using a Wi-Fi connection rather than a serial communication. This functionality is extremely useful in case of no physical access to the ESP32 board.

There are different ways to perform OTA updates. In this tutorial, we’ll cover how to do that using the AsyncElegantOTA library. In our opinion, this is one of the best and easiest ways to perform OTA updates.

The AsyncElegantOTA library creates a web server that you can access on your local network to upload new firmware or files to the filesystem (SPIFFS). The files you upload should be in .bin format. We’ll show you later in the tutorial how to convert your files to .bin format.

Async ElegantOTA Web Server How it Works ESP32

The only disadvantage of OTA programming is that you need to add the code for OTA in every sketch you upload so that you’re able to use OTA in the future. In the case of the AsyncElegantOTA library, it consists of just three lines of code.

AsyncElegantOTA Library

As mentioned previously, there are a bunch of alternatives for OTA programming with the ESP32 boards. For example, in the Arduino IDE, under the Examples folder, there is the BasicOTA example (that never worked well for us); the OTA Web Updater (works well, but it isn’t easy to integrate with web servers using the ESPAsyncWebServer library); and many other examples from different libraries.

Most of our web server projects with the ESP32 use the ESPAsyncWebServer library. So, we wanted a solution that was compatible with that library. The AsyncElegantOTA library is just perfect for what we want:

AsyncElegantOTA Library
  • It is compatible with the ESPAsyncWebServer library;
  • You just need to add three lines of code to add OTA capabilities to your “regular” Async Web Server;
  • It allows you to update not only new firmware to the board but also files to the ESP32 filesystem (SPIFFS);
  • It provides a beautiful and modern web server interface;
  • It works extremely well.

If you like this library and you’ll use it in your projects, consider supporting the developer’s work.

OTA Updates with AsyncElegantOTA Library – Quick Summary

To add OTA capabilities to your projects using the AsyncElegantOTA library, follow these steps:

  1. Install AsyncElegantOTA, AsyncTCP, and ESPAsyncWebServer libraries;
  2. Include AsyncElegantOTA library at the top of the Arduino sketch: #include <AsyncElegantOTA.h>;
  3. Add this line AsyncElegantOTA.begin(&server); before server.begin();
  4. Open your browser and go to http://<IPAddress>/update, where <IPAddress> is your ESP32 IP address.

Continue reading the tutorial for more detailed steps.

How does OTA Web Updater Work?

  • The first sketch should be uploaded via serial port. This sketch should contain the code to create the OTA Web Updater so that you are able to upload code later using your browser.
  • The OTA Web Updater sketch creates a web server you can access to upload a new sketch via web browser.
  • Then, you need to implement OTA routines in every sketch you upload so that you’re able to do the next updates/uploads over-the-air.
  • If you upload a code without an OTA routine, you’ll no longer be able to access the web server and upload a new sketch over-the-air.

Install AsyncElegantOTA Library

In this tutorial, the ESP32 will be programmed using Arduino IDE. If you want to learn how to do the same using VS Code + PlatformIO, follow the next tutorial: ESP32 OTA (Over-the-Air) Updates – AsyncElegantOTA (VS Code + PlatformIO)

You can install the AsyncElegantOTA library using the Arduino Library Manager. In your Arduino IDE, go to Sketch > Include Library > Manage Libraries… Search for “AsyncElegantOTA” and install it.

Install Async Elegant OTA Library Arduino IDE

Install AsyncTCP and ESPAsyncWebServer Libraries

You also need to install the AsyncTCP and the ESPAsyncWebServer libraries. Click the links below to download the libraries.

These libraries aren’t available to install through the Arduino Library Manager, so you need to copy the library files to the Arduino Installation Libraries folder. Alternatively, in your Arduino IDE, you can go to Sketch Include Library > Add .zip Library and select the libraries you’ve just downloaded.

AsyncElegantOTA ESP32 Basic Example

Let’s start with the basic example provided by the library. This example creates a simple web server with the ESP32. The root URL displays some text, and the /update URL displays the interface to update firmware and filesystem.

Copy the following code to your Arduino IDE.

/*
  Rui Santos
  Complete project details
   - Arduino IDE: https://RandomNerdTutorials.com/esp32-ota-over-the-air-arduino/
   - VS Code: https://RandomNerdTutorials.com/esp32-ota-over-the-air-vs-code/
  
  This sketch shows a Basic example from the AsyncElegantOTA library: ESP32_Async_Demo
  https://github.com/ayushsharma82/AsyncElegantOTA
*/

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

const char* ssid = "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("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send(200, "text/plain", "Hi! I am ESP32.");
  });

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

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

View raw code

Insert your network credentials and the code should work straight away:

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

How the Code Works

First, include the necessary libraries:

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

Insert your network credentials in the following variables so that the ESP32 can connect to your local network.

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Create an AsyncWebServer object on port 80:

AsyncWebServer server(80);

In the setup(), initialize the Serial Monitor:

Serial.begin(115200);

Initialize Wi-Fi:

WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");

// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());

Then, handle the client requests. The following lines, send some text Hi! I am ESP32. when you access the root (/) URL:

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
  request->send(200, "text/plain", "Hi! I am ESP32.");
});

If your web server needs to handle more requests you can add them (we’ll show you in the next example).

Then, add the next line to start ElegantOTA:

AsyncElegantOTA.begin(&server);

Finally, initialize the server:

server.begin();

Lastly, add the following in the loop():

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

Access the Web Server

After uploading code to the board, open the Serial Monitor at a baud rate of 115200. Press the ESP32 on-board RST button. It should display the ESP IP address as follows (yours may be different):

AsyncElegantOTA Get ESP IP Address Serial Monitor

In your local network, open your browser and type the ESP32 IP address. You should get access the root (/) web page with some text displayed.

Async ElegantOTA Demo Example Web Server Root URL

Now, imagine that you want to modify your web server code. To do that via OTA, go to the ESP IP address followed by /update. The following web page should load.

Async ElegantOTA Update Page

Follow the next sections to learn how to upload new firmware using AsyncElegantOTA.

Upload New Firmware OTA (Over-the-Air) Updates – ESP32

Every file that you upload via OTA should be in .bin format. You can generate a .bin file from your sketch using the Arduino IDE.

With your sketch opened, you just need to go to Sketch > Export Compiled Binary. A .bin file will be generated from your sketch. The generated file will be saved under your project folder.

That’s that .bin file you should upload using the AsyncElegantOTA web page if you want to upload new firmware.

Upload a New Web Server Sketch – Example

Let’s see a practical example. Imagine that after uploading the previous sketch, you want to upload a new one that allows you to control an LED via a web interface like this project. Here’s the steps you need to follow:

1. Copy the following code to your Arduino IDE. Don’t forget to insert your network credentials.

/*
  Rui Santos
  Complete project details
   - Arduino IDE: https://RandomNerdTutorials.com/esp32-ota-over-the-air-arduino/
   - VS Code: https://RandomNerdTutorials.com/esp32-ota-over-the-air-vs-code/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

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

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

bool ledState = 0;
const int ledPin = 2;

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

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <title>ESP Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <style>
  html {
    font-family: Arial, Helvetica, sans-serif;
    text-align: center;
  }
  h1 {
    font-size: 1.8rem;
    color: white;
  }
  h2{
    font-size: 1.5rem;
    font-weight: bold;
    color: #143642;
  }
  .topnav {
    overflow: hidden;
    background-color: #143642;
  }
  body {
    margin: 0;
  }
  .content {
    padding: 30px;
    max-width: 600px;
    margin: 0 auto;
  }
  .card {
    background-color: #F8F7F9;;
    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
    padding-top:10px;
    padding-bottom:20px;
  }
  .button {
    padding: 15px 50px;
    font-size: 24px;
    text-align: center;
    outline: none;
    color: #fff;
    background-color: #0f8b8d;
    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:hover {background-color: #0f8b8d}*/
   .button:active {
     background-color: #0f8b8d;
     box-shadow: 2 2px #CDCDCD;
     transform: translateY(2px);
   }
   .state {
     font-size: 1.5rem;
     color:#8c8c8c;
     font-weight: bold;
   }
  </style>
<title>ESP Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
</head>
<body>
  <div class="topnav">
    <h1>ESP WebSocket Server</h1>
  </div>
  <div class="content">
    <div class="card">
      <h2>Output - GPIO 2</h2>
      <p class="state">state: <span id="state">%STATE%</span></p>
      <p><button id="button" class="button">Toggle</button></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(ledState));
}

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) {
      ledState = !ledState;
      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 (ledState){
      return "ON";
    }
    else{
      return "OFF";
    }
  }
  return String();
}

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

  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, 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", index_html, processor);
  });

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

void loop() {
  AsyncElegantOTA.loop();
  ws.cleanupClients();
  digitalWrite(ledPin, ledState);
}

View raw code

This is the same code used in this project, but it contains the needed lines of code to handle ElegantOTA:

#include <AsyncElegantOTA.h>
AsyncElegantOTA.begin(&server);
AsyncElegantOTA.loop();

2. Save your sketch: File > Save and give it a name. For example: Web_Server_LED_OTA_ESP32.

3. Generate a .bin file from your sketch. Go to Sketch > Export Compiled Binary. A new .bin file should be created under the project folder.

Bin File Generated for OTA Updates Arduino IDE

4. Now, you need to upload that file using the ElegantOTA page. Go to your ESP IP address followed by /update. Make sure you have the firmware option selected. Click on Choose File and select the .bin file you’ve just generated.

Update New Firmware Elegant OTA

5. When it’s finished, click on the Back button.

Upload New Firmware AsyncElegantOTA success

6. Then, you can go to the root (/) URL to access the new web server. This is the page you should see when you access the ESP IP address on the root (/) URL.

ESP32 Websocket Server Control Outputs

You can click on the button to turn the ESP32 on-board LED on and off.

ESP32 board Built in LED turned on HIGH

Because we’ve also added OTA capabilities to this new web server, we can upload a new sketch in the future if needed. You just need to go to the ESP32 IP address followed by /update.

Congratulations, you’ve uploaded new code to your ESP32 via Wi-Fi using AsyncElegantOTA.

Continue reading if you want to learn how to upload files to the ESP32 filesystem (SPIFFS) using AsyncElegantOTA.

Upload Files to Filesystem OTA (Over-the-Air) Updates – ESP32

In this section you’ll learn to upload files to the ESP32 filesystem (SPIFFS) using AsyncElegantOTA.

ESP32 Filesystem Upload Plugin

Before proceeding, you need to have the ESP32 Uploader Plugin installed in your Arduino IDE. Follow the next tutorial before proceeding:

Web Server with Files from SPIFFS

Imagine the scenario that you need to upload files to the ESP32 filesystem, for example: configuration files; HTML, CSS and JavaScript files to update the web server page; or any other file that you may want to save in SPIFFS via OTA.

To show you how to do this, we’ll create a new web server that serves files from SPIFFS: HTML, CSS and JavaScript files to build a web page that controls the ESP32 GPIOs remotely.

Before proceeding make sure you have the Arduino_JSON library by Arduino version 0.1.0 installed. You can install this library in the Arduino IDE Library Manager. Just go to Sketch Include Library > Manage Libraries and search for the library name as follows: Arduino_JSON.

Copy the following code to your Arduino IDE.

/*
  Rui Santos
  Complete project details
   - Arduino IDE: https://RandomNerdTutorials.com/esp32-ota-over-the-air-arduino/
   - VS Code: https://RandomNerdTutorials.com/esp32-ota-over-the-air-vs-code/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

// Import required libraries
#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "SPIFFS.h"
#include <Arduino_JSON.h>
#include <AsyncElegantOTA.h>

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

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

// Create a WebSocket object
AsyncWebSocket ws("/ws");

// Set number of outputs
#define NUM_OUTPUTS  4

// Assign each GPIO to an output
int outputGPIOs[NUM_OUTPUTS] = {2, 4, 12, 14};

// Initialize SPIFFS
void initSPIFFS() {
  if (!SPIFFS.begin(true)) {
    Serial.println("An error has occurred while mounting SPIFFS");
  }
  Serial.println("SPIFFS mounted successfully");
}

// Initialize WiFi
void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

String getOutputStates(){
  JSONVar myArray;
  for (int i =0; i<NUM_OUTPUTS; i++){
    myArray["gpios"][i]["output"] = String(outputGPIOs[i]);
    myArray["gpios"][i]["state"] = String(digitalRead(outputGPIOs[i]));
  }
  String jsonString = JSON.stringify(myArray);
  return jsonString;
}

void notifyClients(String state) {
  ws.textAll(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, "states") == 0) {
      notifyClients(getOutputStates());
    }
    else{
      int gpio = atoi((char*)data);
      digitalWrite(gpio, !digitalRead(gpio));
      notifyClients(getOutputStates());
    }
  }
}

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);
}

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

  // Set GPIOs as outputs
  for (int i =0; i<NUM_OUTPUTS; i++){
    pinMode(outputGPIOs[i], OUTPUT);
  }
  initSPIFFS();
  initWiFi();
  initWebSocket();

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

  server.serveStatic("/", SPIFFS, "/");

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

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

View raw code

Insert your network credentials in the following variables and save the code.

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Update Firmware

Create a .bin file from this sketch as shown previously (this sketch includes the needed lines of code to provide OTA capabilities).

Go to the ESP32 IP address followed by /update and upload the new firmware.

Next, we’ll see how to upload the files.

Update Filesystem

Under the project folder, create a folder called data and paste the following HTML, CSS, and JavaScript files (click on the links to download the files):

To find your project folder, you can simply go to Sketch > Show Sketch Folder.

This is where your data folder should be located and how it looks:

Data Folder Structure ESP32 Async ElegantOTA Example

After this, with the ESP32 disconnected from your computer (that’s the whole purpose of OTA), click on ESP32 Data Sketch Upload.

ESP32 Sketch Data Upload Arduino IDE SPIFFS FS Filesystem

You’ll get an error because there isn’t any ESP32 board connected to your computer – don’t worry.

Scroll up on the debugging window until you find the .spiffs.bin file location. That’s that file that you should upload (in our case the file is called Web_Server_OTA_ESP32_Example_2.spiffs.bin.

Get SPIFFS bin binary File Path

And this is the path where our file is located:

C:\Users\sarin\AppData\Local\Temp\arduino_build_675367\Web_server_OTA_ESP32_Example_2.spiffs.bin

To access that file on my computer, I need to make hidden files visible (the AppData folder was not visible). Check if that’s also your case.

Arduino IDE ESP32 ESP8266 NodeMCU Board Add-on fix install

Once you reach the folder path, you want to get the file with .spiffs.bin extension.

SPIFFS Bin Folder Arduino IDE

To make things easier you can copy that file to your project folder.

Now that we have a .bin file from the data folder, we can upload that file. Go to your ESP32 IP address followed by /update. Make sure you have the Filesystem option selected.

Upload Files to Filesystem AsyncElegantOTA

Then, select the file with the .spiffs.bin extension.

After successfully uploading, click the Back button. And go to the root (/) URL again. You should get access to the following web page that controls the ESP32 outputs using Web Socket protocol.

Control Multiple ESP32 ESP8266 Outputs Websocket Web Server

To see the web server working, you can connect 4 LEDs to your ESP32 on GPIOS: 2, 4, 12, and 14. You should be able to control those outputs from the web server.

If you need to update something on your project, you just need to go to your ESP32 IP address followed by /update.

Congratulations! You’ve successfully uploaded files to the ESP32 filesystem using AsyncElegantOTA.

Wrapping Up

In this tutorial you’ve learned how to add OTA capabilities to your Async Web Servers using the AsyncElegantOTA library. This library is super simple to use and allows you to upload new firmware or files to SPIFFS effortlessly using a web page. In our opinion, the AsyncElegantOTA library is one of the best options to handle OTA web updates.

We hope you’ve found this tutorial useful.

Learn more about the ESP32 with our resources:

Thanks for reading.



Build Web Server projects with the ESP32 and ESP8266 boards to control outputs and monitor sensors remotely. Learn HTML, CSS, JavaScript and client-server communication protocols DOWNLOAD »

Build Web Server projects with the ESP32 and ESP8266 boards to control outputs and monitor sensors remotely. Learn HTML, CSS, JavaScript and client-server communication protocols DOWNLOAD »

Recommended Resources

Build a Home Automation System from Scratch » With Raspberry Pi, ESP8266, Arduino, and Node-RED.

Home Automation using ESP8266 eBook and video course » Build IoT and home automation projects.

Arduino Step-by-Step Projects » Build 25 Arduino projects with our course, even with no prior experience!

What to Read Next…


Enjoyed this project? Stay updated by subscribing our newsletter!

64 thoughts on “ESP32 OTA (Over-the-Air) Updates – AsyncElegantOTA using Arduino IDE”

  1. This is great. I have been (trying) to use OTA for years and very rarely has it worked. This seems to work every time (sort of) so that’s a plus. The only thing odd is that after loading the “Web Server Sketch – Example” it will not connect to the Wifi. I see “Connecting to WiFi..” repeating but it never connects unless I reboot/reset the ESP32, then it connects every other time. In other words, after uploading the code it doesn’t work until I reboot the ESP32. Then it connects. If I reboot it again, it doesn’t connect. If I reboot it again, it works. Very odd behavior. Any thoughts.

    Reply
    • Hi Bruce.
      That’s indeed a very odd behavior.
      We’ve experimented with the library with different examples, and it never failed.
      We also tried it with the ESP8266, and everything went fine.
      Do you have another board to experiment with?
      Regards,
      Sara

      Reply
      • experimenting too. currently I have a a program (on an ESP8266 using the proper ESP8266 code) with both STA and AP,Async webserver that connects with static IP and the elegantOTA does not seem to want to start. Have not figured out why yet. disabling the AP makes no difference. Will try to find it (the example runs fine)

        Reply
        • OK I found the problem. As you can see, most of the examples, make their WiFi connection, then issue a ‘server,on(“/”……..’ request, and then do their elegant ota and server.begin() requests, placing it at the end of setup().

          That is what I did…….but I had a couple more server requests,,,,one of them called ‘update’.
          need i say more 🙂

          Reply
  2. Hi Sara
    An excellent description – as usual!
    I’m wondering if this works with LittleFS too as the SPIFF file system seems to be deprecated for the ESP32. Have you tried it and it it possible to make it work in a similar way?
    Regards, Juerg

    Reply
    • Hi.
      SPIFFS is only deprecated for the ESP8266.
      This tutorial also works with littlefs (at least with the ESP8266).
      We’ll publish a similar tutorial for the ESP8266 by the end of this week (with littlefs).
      Regards,
      Sara

      Reply
      • Hi Sara
        I have just tested the OTA library with an ESP32 with LITTLEFS: Indeed everything works fine and smooth, even with a username and password for the OTA website (IoT security). The ESP32 just had to be rebooted after the LITTLEFS update, after a firmware update the ESP32 restarted itself.
        Best Regards, Juerg

        Reply
  3. Great,I have been trying this with the ESP8266 and works very well.
    Never had real trouble with the regular OTA, including webOTA, but had the occasional odd behaviour. Main advantage here is that it can be used with Async webpages and it looks a lot better.

    Very well explained

    Reply
  4. Great example. I will definitely use this.
    I am a little concerned that just about anyone can corrupt your esp32 server by uploading a new (possibly a virus) program to it. There seems to be no security and a very generic “update” catch phrase to access it.

    Reply
  5. I clicked on view raw of the second example
    link https://github.com/RuiSantosdotme/Random-Nerd-Tutorials/raw/master/Projects/ESP32/AsyncElegantOTA/ESP32_Web_Server_LED_OTA/ESP32_Web_Server_LED_OTA.ino

    and did a <ctrl-a, ctrl-c ctrl-v
    then I tried to compile the example but I get a lot of error-messages

    Do you RE-test EVERYTHING by following your tutorial?
    I guess not otherwise you would have recognized the bugs yourself

    exit status 1

    control reaches end of non-void function [-Werror=return-type]

    Reply
    • Hi.
      Can you provide more details about the error?
      I’ve just compiled the code again and it was fine.
      Regards,
      Sara

      Reply
  6. Hi Sara,
    thank you for answering so quick. Did you do a Copy & paste from the website and then compile it?
    The I have actovated erbose output so the complete output is more than the forum-software allows

    I guess this part is important
    C:\Users\Stefan\Documents\Arduino\Web_Server_LED_OTA_ESP32\Web_Server_LED_OTA_ESP32.ino: In function ‘String processor(const String&)’:

    Web_Server_LED_OTA_ESP32:202:1: error: control reaches end of non-void function [-Werror=return-type]
    }
    cc1plus.exe: some warnings being treated as errors
    Multiple libraries were found for “WiFi.h”

    Used: P:\Portable-Apps\arduino1.8.13\portable\packages\esp32\hardware\esp32\1.0.4\libraries\WiFi

    Not used: P:\Portable-Apps\arduino1.8.13\libraries\WiFi

    Using library WiFi at version 1.0 in folder: P:\Portable-Apps\arduino1.8.13\portable\packages\esp32\hardware\esp32\1.0.4\libraries\WiFi

    Using library AsyncTCP at version 1.1.1 in folder: C:\Users\Stefan\Documents\Arduino\libraries\AsyncTCP

    Using library ESPAsyncWebServer at version 1.2.3 in folder: C:\Users\Stefan\Documents\Arduino\libraries\ESPAsyncWebServer

    Using library FS at version 1.0 in folder: P:\Portable-Apps\arduino1.8.13\portable\packages\esp32\hardware\esp32\1.0.4\libraries\FS

    Using library AsyncElegantOTA at version 2.2.5 in folder: C:\Users\Stefan\Documents\Arduino\libraries\AsyncElegantOTA

    Using library Update at version 1.0 in folder: P:\Portable-Apps\arduino1.8.13\portable\packages\esp32\hardware\esp32\1.0.4\libraries\Update

    exit status 1

    control reaches end of non-void function [-Werror=return-type]

    best regards Stefan

    Reply
    • Hi.

      Yes, I did that and it compiles fine for me.
      What’s the Arduino IDE and esp32 boards version that you have?

      Modify your processor() function to be like this:

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

      Let me know if this solves your issue.
      Regards,
      Sara

      Reply
  7. I did modify the first code and tested the OTA with this modified first code-version.
    The one that just says Hi! I am ESP32.
    This worked.

    When I inserted your version of String processor
    there was no formatting. no indentions so I pressed ctrl-t for autoformatting. but nothing changed.

    then I moved the function String processor above the html-code and voila there autoformatting worked.

    So my conclusion is that something is written “non-international” inside the rawliteral.
    Something inside the raw-literal has a syntactical error. No idea what this could be as I have never worked with html-code.

    Now idea if – when I post the html-code section here that all the character-translations done by the forum-software keeps the error

    anyway I post it here

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

    const char index_html[] PROGMEM = R”rawliteral(

    ESP Web Server

    html {
    font-family: Arial, Helvetica, sans-serif;
    text-align: center;
    }
    h1 {
    font-size: 1.8rem;
    color: white;
    }
    h2{
    font-size: 1.5rem;
    font-weight: bold;
    color: #143642;
    }
    .topnav {
    overflow: hidden;
    background-color: #143642;
    }
    body {
    margin: 0;
    }
    .content {
    padding: 30px;
    max-width: 600px;
    margin: 0 auto;
    }
    .card {
    background-color: #F8F7F9;;
    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
    padding-top:10px;
    padding-bottom:20px;
    }
    .button {
    padding: 15px 50px;
    font-size: 24px;
    text-align: center;
    outline: none;
    color: #fff;
    background-color: #0f8b8d;
    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:hover {background-color: #0f8b8d}/
    .button:active {
    background-color: #0f8b8d;
    box-shadow: 2 2px #CDCDCD;
    transform: translateY(2px);
    }
    .state {
    font-size: 1.5rem;
    color:#8c8c8c;
    font-weight: bold;
    }

    ESP Web Server

    ESP WebSocket Server

    Output – GPIO 2
    state: %STATE%
    Toggle

    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');
    }

    )rawliteral”;

    void notifyClients() {
    ws.textAll(String(ledState));
    }
    best regards Stefan

    Reply
  8. Posting html-code in this commenting-software SUCKS,
    The comment-software eats half of the code

    to be honest: Sara and Rui you should consider using a completely DIFFERENT commenting-software. All this is about programming. Which means SOURCECODE is a very important part.

    So the Commenting-part should be able to show Sourcecode as Sourcecode
    with a FIXED-DISTANCE-font and as CODE-SECTIONS like ANY other programming-user-forum does.

    I did some reading about PROGMEN and rawliterals and found the syntactical error.
    Then I did do the following:
    I took my mouse holding down the left mousebutton to start marking the sourcecode of the seconds sourcecode (the one that is called Web_Server_LED_OTA_ESP32)

    I finished the marking of the source-code by keeping the shift-key-pressed using cursor down to mark all characters that belong to the sourcecode.

    Then I pasted this into the Arduino-IDE. As a cross-checking I pasted it into UltraEdit, Notepad++ , and standard-notepad.

    Always the same result:

    At the end of the html-code there is

    )rawliteral”;

    “)” is one line BELOW the “>”

    the closing bracket of the command rawliteral is one line below the closing “edgy” bracket “>” of the html-tag

    it is the same inside the “RAW-Code”-page

    as soon as I removed the CR so the source-code looks like this
    )rawliteral”;

    the closing-tag and closing bracket and rawliteral all in the SAME line

    the code compiled.

    This is why I highly doubt that you did do an EXACT copy and paste into Arduino-IDE without any additional hand-formatting

    How would it be possible that your Arduino-IDE could remove a CR (a carriage-return) while my version and any other texteditor does not?

    I developed the habit of testing / repeating ALL steps (if I say ALL steps I mean ALL steps!!)
    before uploading code into a user-forum. Even after changing a single character.

    Which means for example I upload a code-example to the Arduino-forum as a code-section. I use the select all link to copy the code into the clipboard
    I paste this clipboard-content into an absolutely empty new opened sketch and do a REAL upload into the microcontroller and testing the code and watch the serial output does the code behave like expected?

    So this means I do ALL steps another user will do if he tries my code.

    Maybe you have tested it with PlatForm-IO or did remove the CR because you thought it was a type by you

    There is nothing more frustrating for newbees as if a tutorial pretends to explain everything step by step and therefore seems to be fool-proof and then it does not work because of an error in the description.

    best regards Stefan

    Reply
    • I’ve also tested the exact code on my computer right now and it works fine for me. I honestly don’t know what’s missing either.

      I’ve copied the exact code from our website again to both Arduino IDE and VS Code and both compiled just fine.

      Reply
  9. again this forumsoftware eat up the html-code so I add it modified by inserting underlines between each character of the html-code-part
    your codeversion looks like this
    </_h_t_m_l>_)
    rawliteral”;

    it should be in ONE line
    </_h_t_m_l>_)rawliteral”;

    best regards Stefan

    Reply
    • Hi Stefan.
      I’m sorry for the issue.
      But I did test the code, as I told you.
      I copied the raw code, paste it into Arduino IDE, and recompiled it. It went fine, as you can see here: https://imgur.com/ylc6n11.
      This is all very weird, and I can’t find any explanation about this. What’s the version of Arduino IDE that you are using? I’m using 1.8.13.
      All I want is that the tutorials work for everyone straight away.
      I’ll try to investigate a bit more about this issue.
      Regards,
      Sara

      Reply
  10. I tried it with Arduino Ide 1.8.12 and 1.8.13 both showed the same problem.
    Then I tried it with Arduino-IDE 1.8.13 on another computer same problem.

    the combination of
    – changing the code of function “processor” to return String()
    with
    – putting the html-tag and the keyword rawliteral in the same line of code makes the compiler compiling.

    Beside this weird syntax-pickiness this OTA-functionality is great.
    Thank you very much for providing this.

    What really astonished me was the fact that – if I call the ESP32’s website with the LED-toggle-button from multiples computers that on each computer the written state of the LED gets updated the same tenth second I click on the button.
    No reloading of the website requiered. That is really great!

    Do you happen to know a WYSIWYG-website designer that makes it easier to create the HTML-code?

    Or do you have a tutorial that shows how the HTML-elements like buttons, sliders etc. are programmed?
    I mean giving an example and explaining the details through variations:

    positioning the button
    button-size
    button color
    button-text
    how to evaluate the button-click
    how to change the button text/color on run-time
    etc.

    best regards Stefan

    Reply
    • Hi.

      That’s very strange behavior. Rui also tested the code, and it went fine.
      What operating system do you use? We are on Windows.

      Yes, the synchronization of all clients is a great feature, thanks to the WebSocket protocol.

      I’m not familiar with software like that. We design our own webpages.
      In our latest course, “Build Web Servers with ESP32 and ESP8266,” we go into more detail about writing the HTML and CSS for your web pages, handling the HTML elements, and how to use JavaScript.
      Whenever I have a doubt about HTML elements and how to style them, I usually refer to the w3schools website.
      Regards,
      Sara

      Reply
  11. Hi Sara,

    thank you very much.
    Now a simple copy & paste compiles.
    From both “sources” the Website-section (with the colored code) and the raw code (just text)

    OK I’m gonna take a look into your Build Web Servers with ESP32-course

    best regards Stefan

    Reply
  12. Really great tutorial – excellent level of clarity.
    Where I cam unstuck was my Arduino IDE was an Ubuntu SNAP package and for the life of me I could not find the …SPIFFS.bin file. Solved by installing the IDE from the web site but then had to solve all the python2 – python3 problems. Anyway working really well so now I need to think of a use for it!

    Reply
  13. H Sara,
    I get the following error message when attempting to run the Arduino IDE:

    Arduino: 1.8.13 (Mac OS X), Board: “Adafruit ESP32 Feather, 80MHz, 921600, None, Default”

    Traceback (most recent call last):
    File “esptool.py”, line 57, in
    File “/Library/Python/2.7/site-packages/PyInstaller/loader/pyimod03_importers.py”, line 389, in load_module
    File “serial/tools/list_ports.py”, line 29, in
    File “/Library/Python/2.7/site-packages/PyInstaller/loader/pyimod03_importers.py”, line 389, in load_module
    File “serial/tools/list_ports_posix.py”, line 31, in
    File “/Library/Python/2.7/site-packages/PyInstaller/loader/pyimod03_importers.py”, line 389, in load_module
    File “serial/tools/list_ports_osx.py”, line 32, in
    ValueError: dlsym(RTLD_DEFAULT, kIOMasterPortDefault): symbol not found
    Failed to execute script esptool
    Multiple libraries were found for “WiFi.h”
    Used: /Users/TinkersHome/Library/Arduino15/packages/esp32/hardware/esp32/1.0.4/libraries/WiFi
    Not used: /private/var/folders/5y/zlr8vhg579vbb3glg_x9dfsr0000gn/T/AppTranslocation/1E1F157B-C1FB-4E6D-B760-D8182C3AD58B/d/Arduino.app/Contents/Java/libraries/WiFi
    exit status 255
    /private/var/folders/5y/zlr8vhg579vbb3glg_x9dfsr0000gn/T/AppTranslocation/1E1F157B-C1FB-4E6D-B760-D8182C3AD58B/d/Arduino.app/Contents/Java/arduino-builder returned 255
    Error compiling for board Adafruit ESP32 Feather.

    Would you please tell me what my problem is? Thanks

    Reply
  14. I downloaded esp32 and esp 8266 but it didn’t go into Arduino IDE library. It went somewhere .when I re download
    It said its already been installed.I have windows 10. What can be done?

    Reply
    • “I downloaded ESP32 and ESP8266” is a pretty vague description of what you have
      might done. For programming ESP32/8266 you need to add two additional board-definition url into the preferences. So the minimum is that you describe in detail what you have really have done. And I guess you tried to compile he code. You have to activate verbose output and then analyse the output for the errors that were found during compilation and post the errors here.

      best regards Stefan

      Reply
  15. Another excellent tutorial – many thanks
    Can I suggest changing:
    request->send(200, “text/plain”, “Hi! I am ESP32.”);
    to:
    request->send(200, “text/plain”,FILE “\nCompiled: ” DATE ” ” TIME);

    This will return the path and INO name currently loaded IDE and when it was compiled.
    Also… recommend using fixed IP address otherwise you need to connect to USB to find IP address which defeats the use of OTA

    Reply
    • If you encounter a problem or if you want a new feature do a 5 minute-research.
      5 minutes is almost nothing and in a part of all cases you have success in just 5 minutes.

      I developed this habit. For googling and for coding.

      So I took a look into the file AsyncElegantOTA.h
      and VOILÀ:
      you can find there two lines for setting up a username and a password

      I haven’t tested this myself yet.

      best regards Stefan

      Reply
      • Thanks Stefan

        I did indeed google but had no joy. Looking at the Code I thought that the credentials referred to the Wifi Password… my coding is a tad rusty 🙂

        I will do a bit more digging in the *.h file.

        Thanks again.

        Reply
        • Ok so this works i.e. adding credentials to this line, “void begin(AsyncWebServer server, const char username = “username”, const char* password = “password”)

          I tried setting them where they are declared in at the bottom of the file but that did not work.

          I just need to now work out how to log off as once you have logged on it appears to keep you logged in.

          Reply
  16. Hello, very good article. A question would be possible, say on any device with ESp32, installed on a user, company client …, to change / register a new wifi network and password on esp32 through the use of the web server page, when so desired?

    Reply
  17. Hello Sara and Rui.

    I’m trying to upload my .bin file into ESP32CAM through OTA, but is occurring a problem…The web page shows up well and I can choose the .bin file, however after show up 100%, doesn’t appear the message OTA Succes and the button BACK. The web page stay on 100% message always.
    After that the ESP32 CAM reboot and run the old firmware.
    Can you help me with this issue?

    Reply
  18. Very neat solution! A little typo: You explain that the update interface is started by:

    Now, you need to upload that file using the ElegantOTA page. Go to your ESP IP address followed by /updated.

    It should be /update only – without the final “d” – else you get a blank screen.

    Thanks and regards

    Reply
  19. Hi Sara,
    Thank you for sharing the awesome technology. Excellent code base.
    I just have 2 queries

    Can we update firmware and files from intermate, Like if I kept both .bin file on my google drive, every power on Node MCU will check if files are updated and update itself with new .bin files of firmware and other files(html, java, css, image)
    I need to work on some data in csv file, how I can get the csv file from my google drive to my Node MCU

    Reply
    • Hi.
      Thanks for reaching out.
      I think that should be possible, but I don’t have any tutorials about that subject.
      Regards,
      Sara

      Reply
  20. I am trying to use AsyncElegantOTA with an existing sketch, but am getting a bunch of “Multiple definition ” errors.
    I have the sketch set up to allow me to switch Access points, so, I am also including <WebServer.h>. No matter what I tried, I could not get away from multiple errors, so, I loaded your scetch in a new project, It compiles fine.
    But, as soon as I add
    #include <WebServer.h>
    to you sketch, I get a host of errors, leading me to believe WebServer.h and AsyncElegantOTA.h are causing problems for each other.
    Is there a way to include both?
    Is

    sketch\menu.cpp.o:(.bss.AsyncElegantOTA+0x0): multiple definition of AsyncElegantOTA'
    sketch\AsyncIOTWebServer.ino.cpp.o:(.bss.AsyncElegantOTA+0x0): first defined here
    sketch\pin_manager.cpp.o:(.bss.AsyncElegantOTA+0x0): multiple definition of
    AsyncElegantOTA’
    sketch\AsyncIOTWebServer.ino.cpp.o:(.bss.AsyncElegantOTA+0x0): first defined here
    sketch\system.cpp.o:(.bss.AsyncElegantOTA+0x0): multiple definition of AsyncElegantOTA'
    sketch\AsyncIOTWebServer.ino.cpp.o:(.bss.AsyncElegantOTA+0x0): first defined here
    sketch\temperatures.cpp.o:(.bss.AsyncElegantOTA+0x0): multiple definition of
    AsyncElegantOTA’
    sketch\AsyncIOTWebServer.ino.cpp.o:(.bss.AsyncElegantOTA+0x0): first defined here
    sketch\wifi_code.cpp.o:(.bss.AsyncElegantOTA+0x0): multiple definition of `AsyncElegantOTA’
    sketch\AsyncIOTWebServer.ino.cpp.o:(.bss.AsyncElegantOTA+0x0): first defined here
    collect2.exe: error: ld returned 1 exit status
    exit status 1
    Error compiling for board ESP32 Dev Module.

    Reply
  21. Thanks for the answer Sara, will this also be compatible with <ESPAsyncWebServer.h>?

    It may seem as if I cannot make up my mind what I want to use, but, I am only using “WebServer.h” to add new WiFi credentials if I am not within range of a currently known AP, but the project runs on <ESPAsyncWebServer.h> once an AP has been established.

    Reply
  22. OK, Thanks, I will try it, I have already been round and round with so many different ways of trying to acomplish this, one more attempt it is. You & Rui have been an excellent source of quality information!
    Thanks!

    Reply
  23. Hi, nice tutorial and just what i need. I consider myself a novice where esp32 is concerned. I have just 1 question, i need to upload temperature logs to a server hosted outside of my network. So, i will do an http get request with temp values. Can i use the OTA library as well as do the above mentioned tasks. Temp logs get uploaded every 5 minutes

    Reply
  24. OTA means a compiled binary file that contains a PROGRAM will be transferred over WiFi into a reserved part of the ESP32-flash-memory. After storing the new compiled program into the OTA-area successfully, this compiled program is transferred into the regular program-flash-memory.

    compiled binary PROGRAM——>——-any Computer——–>WiFi———–>ESP32——Flash-PROGRAM-memory

    That is a completely different thing than
    ESP32–temperature-Data-in-RAM-Memory—–>——WiFi——->——–external Server

    different direction: Computer—>–ESP32 versus ESP32—–>—-Server
    different datalocation: flash / versus RAM
    different dataNATURE: PROGRAM versus TemperatureDATA

    there could not much more be different between those two tasks

    Reply
  25. Hi Sara,

    I am using the ESP32-CAM for my test. All programs work fine on it
    When I do OTA update it hangs at 58% (several attempts done)
    Reloading the web page gives me the update page again with Browse again.
    Do I need to change something for ESP32-CAM?

    Reply
  26. I had problems when update firmware “abort() was called at pc 0x40143f45 on core 1”. ESP32 immediately reset. What do I need to do to make it work properly?

    Reply
  27. Hi
    Thanks a lot for your tutorials, I have ElegantOTA working on my ESP32 project now.

    Wondering if there is a way to write the filesystem to SD instead of SPIFFS?

    I have a webserver running with files on a micro SD card (working thanks to your other tutorials), and would like to make OTA updates to the html files.

    Randy

    Reply
    • FWIW, I gave up trying to save files to a micro sd card using elegant OTA.

      I changed my code to use store and read the html files to/from SPIFFS.
      This is working very well, its now really easy to make changes to the webpage, and then load them with elegantOTA.

      Still using the uSD card to store files, no problem using SPIFFS and uSD at the same time.

      Reply
  28. Hi Sara
    I get error for ws.cleanupClient();

    AsyscWebSocket has no member named cleanupClients

    I’m using a Mac an Arduini 1.8.15

    Reply
  29. I have followed along with the tutorial and updating firmware is working very well except that the progress bar always reads 100%. Then I tried the update file SPIFFS example and I’m stuck. After disconnecting the ESP32 and clicking Tools/ESP32 Sketch Data Upload it fails as expected but the Debug window is blank. I have searched for .spiffs.bin but haven’t found any files. I am using MacOS 10.15.5 and Arduino 1.8.15.

    Reply
  30. HI, after I upload files with the file system,The uploaded file name cannot be found when use “spiffs.opendir (folder_name)”. i don’t know why.

    Reply

Leave a Reply to Sara Santos Cancel reply

Download our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.