ESP8266 OTA Over The Air Programming using AsyncElegantOTA Library and Arduino IDE

In this tutorial, we will learn ESP8266 OTA programming using Arduino IDE. We will learn an interesting feature of the ESP8266 NodeMCU module that will allow us to perform over-the-air OTA updates. This means that the ESP8266 module like other Wi-Fi enabled microcontrollers supports 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 ESP8266’s LittleFS without any physical connection. All the updating will occur over the air (OTA) without physically connecting the ESP8266 module to a computer via a USB cable.

ESP8266 OTA Over The Air Programming using Arduino IDE

We also have a similar guide for ESP32

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.

ESP8266 OTA Updates using AsyncElegantOTA library

Through OTA programming, the ESP8266 board will wirelessly update new sketches. With the help of the AsyncElegantOTA library, there will also be a feature to upload files onto the ESP8266 LittleFS. 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 ESP8266’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 ESP8266, 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 ESP8266 module as well as upload files to the ESP8266 LittleFS

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 ESP8266 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 ESP8266 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 ESP8266 development board. Thus, you should have the latest version of Arduino IDE. Additionally, you also need to install the ESP8266 plugin. If your IDE does not have the plugin installed you can visit the link below:

 Installing ESP8266 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. ESPAsyncTCP 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 ESP8266 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 the ESPAsync TCP library for free, click here to download. You will download the library as a .zip folder which you will extract and rename as ‘ESPAsyncTCP.’ 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 ESP8266

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 ESP8266 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 and upload files to ESP8266 LittleFS.

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>

const char* ssid = "Your_SSID";   //replace with your SSID
const char* password = "Your_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 ESP8266. 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, ESP8266WiFi.h, ESPAsyncWebServer.h, ESPAsyncTCP.h and AsyncElegantOTA.h. As we have to connect our ESP8266 to a wireless network hence we need ESP8266WiFi.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 <ESP8266WiFi.h>
#include <ESPAsyncTCP.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 = "Your_SSID";   //replace with your SSID
const char* password = "Your_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 ESP8266 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());

ESP8266 Handling Requests

We will deal with the /root URL request which the ESP8266 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 ESP8266. 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 NodeMCU 1.0

select ESP8266 NodeMCU board

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

ESP8266 COM Port

Click on the upload button to upload the code to the ESP8266 development board.
After you have uploaded your code to the ESP8266 development board press its RST button.

ESP8266 NodeMCU reset button

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

ESP8266 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:

ESP8266 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.

ESP8266 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 ESP8266 filesystem wirelessly (Example 3)

Example 2: Uploading new firmware (ESP8266 OTA Updates)

Now, we will show you how to upload new sketches to the ESP8266 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: ESP8266 NodeMCU WebSocket Server using Arduino IDE and LittleFS – Control GPIOs. In that tutorial, we created an ESP8266 web server by using a WebSocket communication protocol and Arduino IDE. The web server controlled the onboard LED of the ESP8266 module. We will take that project a step ahead and include OTA functionality inside it. Previously, we used a serial connection between the ESP8266 board to upload the code. Now, we will create the same WebSocket web server but upload the code to ESP8266 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 ‘ESP8266_WebSocket_Webserver_OTA.’ Remember to replace the network credentials with your values.

// Import required libraries
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>

// Replace network credentials with your own WiFi details
const char* ssid = "Your_SSID";   //replace with your SSID
const char* password = "Your_Password";   //replace with your 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>ESP8266 NodeMCU 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: #D3D3D3;
    background-color:#130ffa;  
    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:#000000 ; 
     transform: translateY(2px);
   }
   .state {
     font-size: 1.5rem;
     color:#120707;
     font-weight: bold;
   }
  </style>
<title>ESP8266 NodeMCU Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
</head>
<body>
  <div class="topnav">
    <h1>ESP8266 NodeMCU 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 = "OFF";
    }
    else{
      state = "ON";
    }
    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 ESP8266 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.240.127/update. You will use the IP address for your own ESP8266 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. After a few moments the process will be completed.

ESP8266 OTA updates via AsyncElegantOTA example2 demo1

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

ESP8266 OTA updates via AsyncElegantOTA example2 demo3

Now click the toggle button. The onboard LED of the ESP8266 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.

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

Example 3: Uploading files to ESP8266 filesystem via ElegantOTA

Now, we will learn how to upload files to the ESP8266’s filesystem LittleFS 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: ESP8266 NodeMCU WebSocket Server using Arduino IDE and LittleFS – Control GPIOs. In that tutorial, we created a Web Socket web server with ESP8266 using LittleFS and Arduino IDE in Example 2. This was done by storing the CSS, HTML and JavaScript files in the file system of ESP8266 and building a web server through those files. With LittleFS, we can save HTML, CSS, and JavaScript files in ESP8266 NodeMCU flash file system. Whenever a web client makes an HTTP request, we can serve these files directly from LittleFS.

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 ESP8266 board to upload the code. Now, we will create the same LittleFS web server but upload the files to the ESP8266’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 ESP8266 NodeMCU Filesystem Uploader in your Arduino IDE so that you are able to upload the LittleFS files on your board. If you haven’t, you can follow this tutorial:

LittleFS Introduction & Install ESP8266 NodeMCU Filesystem Uploader in Arduino IDE

Creating Files for LittleFS

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

Note: You should place HTML, CSS and JavaScript files inside the data folder. Otherwise, LittleFS 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 the toggle button.

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

<!DOCTYPE HTML><html>
<head>
  <title>ESP8266 NodeMCU Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <link rel="stylesheet" type="text/css" href="style.css">

<title>ESP8266 NodeMCU Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
</head>
<body>
  <div class="topnav">
    <h1>ESP8266 NodeMCU 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>
  http://script.js
</body>
</html>

CSS file

Copy the following content to style.css file.

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

JavaScript file

Copy the following content to script.js file.

 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 = "OFF";
    }
    else{
      state = "ON";
    }
    document.getElementById('state').innerHTML = state;
  }
  function onLoad(event) {
    initWebSocket();
    initButton();
  }
  function initButton() {
    document.getElementById('button').addEventListener('click', toggle);
  }
  function toggle(){
    websocket.send('toggle');
  }

Arduino Sketch LittleFS WebSocket 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 ‘ESP8266_WebSocket_LittleFS_WebServer.’ Remember to replace the network credentials with your values.

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "LittleFS.h"
#include <AsyncElegantOTA.h>


// Replace network credentials with your own WiFi details
const char* ssid = "Your_SSID";   //replace with your SSID
const char* password = "Your_Password";   //replace with your password

bool GPIO_State = 0;
const int Led_Pin = 2;
String stateled = "OFF";

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


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);
  if (!LittleFS.begin()) {
    Serial.println("An error has occurred while mounting LittleFS");
  }
  else{
   Serial.println("LittleFS mounted successfully");
  }
  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(LittleFS, "/index.html", "text/html",false,processor);
  });
   server.serveStatic("/", LittleFS, "/");

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

}

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

To understand how the code works you can have a look at the article here Example 2. 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:

ESP8266 OTA updates via AsyncElegantOTA example3

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

Now go to Tools > ESP8266 LittleFS Data Upload.

LittleFS sketch data upload to esp8266 filesystem

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

ESP8266 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.

ESP8266 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:

ESP8266 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.240.127/update. You will use the IP address for your own ESP8266 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.

ESP8266 OTA updates via AsyncElegantOTA example3 pic4

After few moments, the process will be completed.

ESP8266 OTA updates via AsyncElegantOTA example2 demo2

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

ESP8266 OTA updates via AsyncElegantOTA example3 pic5

Now, press the toggle button 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, CSS, and JavaScript files to the ESP8266 filesystem to create a web server.

Conclusion

In conclusion, we were able to learn a very useful feature of ESP8266 through this article today. In this comprehensive guide, we learned how to update new firmware in ESP8266 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 ESP8266’s LittleFS. We incorporated examples from previously performed projects where we created asynchronous web servers using the ESPAsyncWebServer library.

1 thought on “ESP8266 OTA Over The Air Programming using AsyncElegantOTA Library and Arduino IDE”

  1. Hi, I’d like to know if there’s a possibility to have a fixed IP on the 8266. My problem is: I have a meteo station driven by an BME280 along with an ESP8266. It is asked for the values once a minute by an Raspberry PI 3. So I need it would have always the same IP. Router which manages the DHCP is a 4G mobile internet type and cannot give always the same IP.
    Now I:
    – don’t want to buy another router,
    – don’t want the 8266 to be the active one because it can’t deliver exact timestamp.
    The solution would be the fixed IP, but I was unsuccessful until now.
    Would you have idea?

    Reply

Leave a Comment