Over-the-Air (OTA) Programming on ESP32 – Basic OTA using Arduino IDE and Web Updater OTA

Over The Air Programming on ESP32

In this article, we will be discussing about Over-The-Air programming on our famous ESP32 Development board. We have previously built many ESP32 Projects and having an option to program these broads without having to connect them to computer every single time is really interesting. So in this article, we will also be looking into the two ways which can be used to program ESP32 wirelessly. One is the basic OTA method which requires an Arduino IDE and the other is a Web Updater OTA method which only requires a browser to update your program. We will look into both the methods and understand how to use them, so tune in till the end to learn everything.

 

What is OTA?

OTA stands for Over The Air. It allows uploading a new program to ESP32 using Wi-Fi instead of connecting the ESP32 to a computer via USB to do the update. It is extremely useful in situations where you don't have physical access to the module. This feature can be used to reprogram the devices that are fixed on a roof or any other place where connecting cable is difficult.

 

What is the Need of OTA?

Let us say, you have created a phenomenal project using ESP32. You fixed it in your home and powered it up. Everything is working fine and you have got comfortable into your smart home. But one day, you need to make slight changes to the code or maybe change the code with updated version of libraries and stuffs or maybe add some more features to it. Will you like the mess of plugging out the whole module, removing the connections, plugging it to your PC, uploading the code, re-doing the connections and then setting it all up again?

 

Well no! No one will. That is where OTA kicks in. For establishing OTA with ESP32, you need to include few extra lines to your code and after that, you can upload the codes wirelessly over the air.

 

How to Implement OTA with ESP32?

There are two ways to perform an OTA update on ESP32 board. They are Basic OTA, in which updates are sent via Arduino IDE and Web updater OTA, in which updates are sent via a webpage/web browser.

 

How to Use Basic OTA on ESP32

For using Basic OTA feature with your ESP32 board, you just need to follow these three steps. This method uses Arduino IDE to program our ESP32 board, so if you are completely new to ESP32 and Arduino, you can check out how to get started with ESP32 using Arduino IDE to understand better.

 

Step 1:- Installing Python in Your PC

In order to use the OTA functionality, you need to have Python 2.7.xx installed in your PC. You can download python from the official website.

Install Python in PC

The installation process is pretty straight forward. Just open the installer after downloading and follow the installation wizard. After installing Python in your PC, you can continue with the second step.

 

Step 2:- Uploading the Basic OTA Sketch

The ESP32 board does not support OTA updates by default, hence you need to upload the new firmware in order to perform the OTA updates.

 

This is a mandatory step as this will later allow you to push the new codes wirelessly via Wi-Fi. Firstly, you need to have the ESP32 boards package installed in your Arduino IDE. After installing the boards, go to  

File > Examples > ArduinoOTA > BasicOTA

 

This is the sketch that you need to install in order to give your ESP32 the power of OTA.

Basic OTA Sketch

The changes that you need to make in the code are ssid and password. You need to give this credentials so that the ESP can connect to your router in order to receive the updates. Once you are done with those, go ahead and upload the sketch.

 

Once you have uploaded the Basic OTA sketch. Open your Serial Monitor on a baud rate of 115200. If everything went alright, then you will see IP Address printed at the end of the monitor. Note the IP address.

OTA IP Address

Now, that you have completed all the steps. It's time to upload the new sketches over the air. Excited? So am I.

 

Step 3:- Uploading the Codes Over The Air

Now let us try uploading a new sketch wirelessly to ESP32.

Remember that you need to include the Basic OTA sketch with every sketch that you upload else you'll loose the OTA functionality after uploading the sketch. For example, if you want to upload a basic LED blinking sketch to, then you need to include the Basic OTA sketch in it also. Example of such sketch is given below.

#include <WiFi.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
const char* ssid = "..........";
const char* password = "..........";
//This is the part of the LED blinking code
const int led = 2; // ESP32 Pin to which onboard LED is connected
unsigned long previousMillis = 0;  // will store last time LED was updated
const long interval = 1000;  // interval at which to blink (milliseconds)
int ledState = LOW;  // ledState used to set the LED
void setup() {
pinMode(led, OUTPUT);
  Serial.begin(115200);
  Serial.println("Booting");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("Connection Failed! Rebooting...");
    delay(5000);
    ESP.restart();
  }
  // Port defaults to 3232
  // ArduinoOTA.setPort(3232); 
  // Hostname defaults to esp3232-[MAC]
  // ArduinoOTA.setHostname("myesp32"); 
  // No authentication by default
  // ArduinoOTA.setPassword("admin"); 
  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
  // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); 
  ArduinoOTA
    .onStart([]() {
      String type;
      if (ArduinoOTA.getCommand() == U_FLASH)
        type = "sketch";
      else // U_SPIFFS
        type = "filesystem";
      // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
      Serial.println("Start updating " + type);
    })
    .onEnd([]() {
      Serial.println("\nEnd");
    })
    .onProgress([](unsigned int progress, unsigned int total) {
      Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
    })
    .onError([](ota_error_t error) {
      Serial.printf("Error[%u]: ", error);
      if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
      else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
      else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
      else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
      else if (error == OTA_END_ERROR) Serial.println("End Failed");
    });
  ArduinoOTA.begin();
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
} 
void loop() {
  ArduinoOTA.handle();    
//Here is the LED blinking section
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
  // save the last time you blinked the LED
  previousMillis = currentMillis;
  // if the LED is off turn it on and vice-versa:
  ledState = not(ledState);
  // set the LED with the ledState of the variable:
  digitalWrite(led,  ledState);
  } 
}

 

Once you have written your program in such a manner that it includes the Basic OTA sketch as well, then just click on Tools and go to the ports section. You will see something like this "esp32-xxxxxx at your_esp_ip_address", Choose that board and hit on the upload button.

ESP32 OTA Programming

 

And Wallah! Just wait for few seconds and your code is sent to ESP32 Over The Air.

 

How to use Web updater OTA on ESP32

For using Web-updater OTA feature with your ESP32 board. You just need to follow these three steps.

 

Step 1:- Uploading the WebUpdater Sketch

The ESP32 board does not support OTA updates by default, hence you need to upload the new firmware in order to perform the OTA updates. This is a mandatory step as this will later allow you to push the new codes wirelessly via Wi-Fi.

 

Firstly, you need to have the ESP32 boards package installed in your Arduino IDE. After installing the boards, Go to-

File > Examples > ArduinoOTA > BasicOTA

OTA WebUpdater

This is the sketch that you need to install in order to give your ESP32 the power of OTA. The changes that you need to make in the code are ssid and password. You need to give this credentials so that the ESP can connect to your router in order to receive the updates. Once you are done with those, go ahead and upload the sketch.

 

Step 2:- Access the Web-Server Created by Your ESP32

Once you have uploaded the Basic OTA sketch. Open your Serial Monitor on a baud rate of 115200. If everything went alright, then you will see IP Address printed at the end of the monitor. Note the IP address.

ESP32 OTA Webupdater IP Address

 

Visit to this IP address with any browser, make sure you are connected with the same WiFi network as your ESP board.

ESP32 Webserver

You'll be greeted with a page like this. Both the default username and password are "admin", You may change them according to your wish in the code itself. Just change this line of the code.

"if(form.userid.value=='admin' && form.pwd.value=='admin')"

 

Step 3 :- Get the Binary File of Your Code

After you login, you'll see the page from which you can upload sketch but for that, we firstly need to generate the bin file of our sketch.

 

Below is the code that we are going to upload to our ESP32 over the air. The code is for blinking an LED while also keeping the OTA feature intact.

#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>
const char* host = "esp32";
const char* ssid = "xxxxxx";
const char* password = "xxxx";
const int led = 2; // ESP32 Pin to which onboard LED is connected
unsigned long previousMillis = 0;  // will store last time LED was updated
const long interval = 1000;  // interval at which to blink (milliseconds)
int ledState = LOW;  // ledState used to set the LED
WebServer server(80);
/*
* Login page
*/
const char* loginIndex = 
 "<form name='loginForm'>"
    "<table width='20%' bgcolor='A09F9F' align='center'>"
        "<tr>"
            "<td colspan=2>"
                "<center><font size=4><b>ESP32 Login Page</b></font></center>"
                "<br>"
            "</td>"
            "<br>"
            "<br>"
        "</tr>"
        "<td>Username:</td>"
        "<td><input type='text' size=25 name='userid'><br></td>"
        "</tr>"
        "<br>"
        "<br>"
        "<tr>"
            "<td>Password:</td>"
            "<td><input type='Password' size=25 name='pwd'><br></td>"
            "<br>"
            "<br>"
        "</tr>"
        "<tr>"
            "<td><input type='submit' onclick='check(this.form)' value='Login'></td>"
        "</tr>"
    "</table>"
"</form>"
"<script>"
    "function check(form)"
    "{"
    "if(form.userid.value=='admin' && form.pwd.value=='admin')"
    "{"
    "window.open('/serverIndex')"
    "}"
    "else"
    "{"
    " alert('Error Password or Username')/*displays error message*/"
    "}"
    "}"
"</script>";
/*
* Server Index Page
*/
const char* serverIndex = 
"https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"
"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"
   "<input type='file' name='update'>"
        "<input type='submit' value='Update'>"
    "</form>"
"<div id='prg'>progress: 0%</div>"
"<script>"
  "$('form').submit(function(e){"
  "e.preventDefault();"
  "var form = $('#upload_form')[0];"
  "var data = new FormData(form);"
  " $.ajax({"
  "url: '/update',"
  "type: 'POST',"
  "data: data,"
  "contentType: false,"
  "processData:false,"
  "xhr: function() {"
  "var xhr = new window.XMLHttpRequest();"
  "xhr.upload.addEventListener('progress', function(evt) {"
  "if (evt.lengthComputable) {"
  "var per = evt.loaded / evt.total;"
  "$('#prg').html('progress: ' + Math.round(per*100) + '%');"
  "}"
  "}, false);"
  "return xhr;"
  "},"
  "success:function(d, s) {"
  "console.log('success!')" 
 "},"
"error: function (a, b, c) {"
"}"
"});"
"});"
"</script>";
/*
* setup function
*/
void setup(void) {
  Serial.begin(115200);
  pinMode(led,  OUTPUT);
  // Connect to WiFi network
  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()); 
  /*use mdns for host name resolution*/
  if (!MDNS.begin(host)) { //http://esp32.local
    Serial.println("Error setting up MDNS responder!");
    while (1) {
      delay(1000);
    }
  }
  Serial.println("mDNS responder started");
  /*return index page which is stored in serverIndex */
  server.on("/", HTTP_GET, []() {
    server.sendHeader("Connection", "close");
    server.send(200, "text/html", loginIndex);
  });
  server.on("/serverIndex", HTTP_GET, []() {
    server.sendHeader("Connection", "close");
    server.send(200, "text/html", serverIndex);
  });
  /*handling uploading firmware file */
  server.on("/update", HTTP_POST, []() {
    server.sendHeader("Connection", "close");
    server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
    ESP.restart();
  }, []() {
    HTTPUpload& upload = server.upload();
    if (upload.status == UPLOAD_FILE_START) {
      Serial.printf("Update: %s\n", upload.filename.c_str());
      if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
        Update.printError(Serial);
      }
    } else if (upload.status == UPLOAD_FILE_WRITE) {
      /* flashing firmware to ESP*/
      if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
        Update.printError(Serial);
      }
    } else if (upload.status == UPLOAD_FILE_END) {
      if (Update.end(true)) { //true to set the size to the current progress
        Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
      } else {
        Update.printError(Serial);
      }
    }
  });
  server.begin();
} 
void loop(void) {
  server.handleClient();
  delay(1);
   unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
ledState = not(ledState);
// set the LED with the ledState of the variable:
digitalWrite(led,  ledState);
}
}

 

Now we need to generate the bin file of this code. For this, just go into the sketch tab in Arduino IDE and choose export compiled binary.

OTA Programming on ESP32 Binary File

 

Step 4:- Done! Upload the Code Over-the-Air through Web

Now that you have generated the binary file of your code, its time to upload the code to the board through the web page.

 

Open the /serverIndex page in your browser. Click on Choose File… Select the generated .bin file, and then click Update.

OTA Programming on ESP32

 

Wait for few seconds........ And Wallah! The code will be uploaded to the board over the air without the Arduino IDE. How cool is that?

Video

1 Comments