fbpx

Uploading Code on ESP32 over Wi-Fi – Web-updater OTA

If you have been a regular viewer of Techiesms you must know that we love working with ESP32. It has got so many of mesmerizing features. It has got great processing powers and BLE along with Wi-Fi.

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. One such example is mentioned here.

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 to your ESP32 board.

  1. Basic OTA – Updates are sent via Arduino IDE
  2. Web updater OTA – Updates are sent via a webpage/web browser.

In this tutorial we will be implementing Web-Updater OTA. You can read about BasicOTA from HERE!

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

  1. Upload the Web-updater sketch to ESP32
  2. Access the Web-server created by your ESP32
  3. Get the binary file of your code
  4. Done! Upload the code Over-the-Air through web

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.

Firsty, you need to have the ESP32 boards package installed in your Arduino IDE. If you don’t have those then you can watch this video of mine to get started with ESP32.

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.

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 alight then you will see IP Address printed at the end of the monitor. Note the IP address.

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

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 a 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: %sn", 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: %unRebooting...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.

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.

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?

Conclusion:-

Yeah, I know it is a bit of headache to include the Basic OTA sketch to each of your code but the functionality it gives is flawless. If you are going to sell your product in the market then you need to provide your customers with an option to update the firmare when needed. That can easily be fullfilled by this OTA feature. Still the implementations depend from user to user.