ESP32 Over-the-air (OTA) Programming – Web Updater Arduino IDE

Quick guide that shows how to do over-the-air (OTA) programming with the ESP32 using the OTA Web Updater in Arduino IDE. The OTA Web Updater allows you to update/upload new code to your ESP32 using a browser, without the need to make a serial connection between the ESP32 and your computer.

esp32-ota-web-updates

OTA programming is useful when you need to update code to ESP32 boards that are not easily accessible. The example we’ll show here works when the ESP32 and your browser are on your local network.

The only disadvantage of the OTA Web Updater is that you have to add the code for OTA in every sketch you upload, so that you’re able to use OTA in the future.

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 a OTA routine you’ll no longer be able to access the web server and upload a new sketch over-the-air.

Prerequisites

Before proceeding with this tutorial you should have the ESP32 add-on installed in your Arduino IDE. Follow one of the next tutorials to install the ESP32 on the Arduino IDE, if you haven’t already.

ESP32 OTA Web Updater

When you install the ESP32 add-on for the Arduino IDE, it will automatically install the ArduinoOTA library. Go to File > Examples >ArduinoOTA> OTAWebUpdater.

otawebupdater-arduino-ide

The following code should load.

/*
 * OTAWebUpdater.ino Example from ArduinoOTA Library
 * Rui Santos 
 * Complete Project Details https://randomnerdtutorials.com
 */

#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>

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

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 = 
"<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
"<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);

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

View raw code

You should change the following lines on the code to include your own network credentials:

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

The OTAWebUpdater example for the ESP32 creates an asynchronous web server where you can upload new code to your board without the need for a serial connection.

Upload the previous code to your ESP32 board. Don’t forget to enter your network credentials and select the right board and serial port.

After uploading the code, open the Serial Monitor at a baud rate of 115200, press the ESP32 enable button, and you should get the ESP32 IP address:

Now, you can upload code to your ESP32 over-the-air using a browser on your local network.

To test the OTA Web Updater you can disconnect the ESP32 from your computer and power it using a power bank, for example (this is optional, we’re suggesting this to mimic a situation in which the ESP32 is not connected to your computer).

Update New Code using OTA Web Updater

Open a browser in your network and enter the ESP32 IP address. You should get the following:

otawebupdater-user-pass

Enter the username and the password:

  • Username: admin
  • Password: admin

You can change the username and password on the code.

Note: After you enter the username and password, you are redirected to the /serverIndex URL. You don’t need to enter the username and password to access the /serverIndex URL. So, if someone knows the URL to upload new code, the username and password don’t protect the web page from being accessible from others.

A new tab should open on the /serverIndex URL. This page allows you to upload a new code to your ESP32. You should upload .bin files (we’ll see how to do that in a moment).

ota-web-updater-esp32

Preparing the New Sketch

When uploading a new sketch over-the-air, you need to keep in mind that you need to add code for OTA in your new sketch, so that you can always overwrite any sketch with a new one in the future. So, we recommend that you modify the OTAWebUpdater sketch to include your own code.

For learning purposes let’s upload a new code that blinks an LED (without delay). Copy the following code to your Arduino IDE.

/*
 * Rui Santos 
 * Complete Project Details https://randomnerdtutorials.com
 */

#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>

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

//variabls to blink without delay:
const int led = 2;
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 = 
"<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
"<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) {
  pinMode(led, OUTPUT);
  
  Serial.begin(115200);

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

  //loop to blink without delay
  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);
  }
}

View raw code

As you can see, we’ve added the “blink without delay” code to the OTAWebUpdater code, so that we’re able to make updates later on.

After copying the code to your Arduino IDE, you should generate a .bin file.

Generate a .bin file in Arduino IDE

Save your sketch as LED_Web_Updater.

To generate a .bin file from your sketch, go to Sketch > Export compiled Binary

export-bin-file-arduino-ide

A new file on the folder sketch should be created. Go to Sketch > Show Sketch Folder. You should have two files in your Sketch folder: the .ino and the .bin file. You should upload the .bin file using the OTA Web Updater.

Upload a new sketch over-the-air to the ESP32

In your browser, on the ESP32 OTA Web Updater page, click the Choose File button. Select the .bin file generated previously, and then click Update.

After a few seconds, the code should be successfully uploaded.

The ESP32 built-in LED should be blinking.

esp32-blinking-led

Congratulations! You’ve uploaded a new code to your ESP32 over-the-air.

Wrapping Up

Over-the-air updates are useful to upload new code to your ESP32 board when it is not easily accessible. The OTA Web Updater code creates a web server that you can access to upload new code to your ESP32 board using a web browser on your local network.

We hope you’ve found this article interesting. If you like ESP32 you may also like:



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database 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!

107 thoughts on “ESP32 Over-the-air (OTA) Programming – Web Updater Arduino IDE”

  1. Thanks, very useful!
    Would it be possible in zhis example to access the server from outside the local net?
    If not, how could this be achieved?
    Thanks again!

    Reply
    • Paul,
      You can do this in a couple of steps:

      1. Use a dynamic DNS service to assign a domain name to your home network. So the outside world can get the your home LAN using something like: my router.dnsservice.com
      Google: dynamic DNS home router

      2. Enable port forwarding on your home router. So a web browser request can be sent to ”myrouter.dnsservice.com:5000” and your router will pass it along from Port 5000 to the IP address assigned to your Arduino/ESP32 device.
      Google: port forwarding

      The are some security implications in all of this – but Google searches will highlight these for you.

      -Kim

      Reply
    • thank you for this question – that exactly what I need
      and thanks to Author for good answer and good article

      btw
      there should be the way to do that without static ip, portforwarding, etc.
      u can use HttpClient, obtain your updates from eg AWS S3 and then just use Update

      Reply
    • Hi.
      I just understand Portuguese and English (I’ve used Google Translator to understand what you mean).
      At the moment, we don’t have an example like this is micropython. But I’ll do a research about that, and probably write a blog post about that soon.
      Thank you so much for supporting our work.
      Regards,
      Sara 🙂

      Reply
      • Hello Sara,
        that will be fantastic. I’d like to move to Micropython, but for me, ability of OTA Programmierung is a precondition.
        Thank you very much for all the great work here.
        Kind regards,
        Äd

        Reply
        • Hi.
          At the moment, we don’t have any tutorial for OTA with micropython.
          We’ll release a new tutorial in a week or two about OTA for ESP32 (but with Arduino IDE and PlatformIO)
          Regards,
          Sara

          Reply
  2. Rui,

    How difficult would it be to make this work on a ESP8266 featherwing?

    This solution is what I am looking for to allow clients to update the ESP8266 without having to connect a USB cable.

    Reply
  3. Your tutorial is great but there is some ambiguity in your explanation. I am not certain if “REPLACE_WITH_YOUR_SSID” and “REPLACE_WITH_YOUR_PASSWORD” refers to the SSID and password on my local network (the router wifi login credentials) or one I am creating for my ESP device. If it is my local router does that mean that I can only update the ESP when I am in range of that router? What I need is the ability to distribute ESP devices to many different remote locations and the users at those locations need to be able to get updates whenever they are available. Also, I do not have a web server that they can connect to. So what I need is to email them the latest BIN file which they then save on their local PC. Then they connect their PC to the ESP via WiFi using the SSID and password set up in the ESP code. Then they enter the IP set up in the ESP code (192.168.1.114 for example). Then the ESP serves then an initial menu page with everything that they can do with their ESP, including updating the ESP firmware. When they choose that option, the ESP web server serves them the same page that you showed by pointing the browser to 192.168.1.148/serverIndex, allowing them to point to the location that they stored the BIN file. And when they click the Update button, the update proceeds. Could you show a way to accomplish this? It would be immensely helpful!

    Reply
    • Hi.
      SSID and Password refers to the router wifi login credentials. With this example, you can only update code when the ESP is in the range of the router.
      I think you’ve just described what you need to do. I don’t understand what is really your question.
      Regards,
      Sara.

      Reply
  4. vc precisará abrir uma porta no firewall da rede, ou no roteador que tem em casa, endereçar esta porta na hora de chamar a pagina. Exemplo: http://www.suarede.com/xxx onde suarede é o endereço IP perante o mundo (endereço que sua rede tem para o mundo e não a rede interna) e xxx é o numero da porta que vc liberou no seu roteador

    Reply
  5. Great Tutorial Guys! Thanks a lot!
    In regards to OTA updates, is there a way to only update Config parameters and not write the entire FW? For example to simple update the reporting interval or specific Config settings/Config file from the server without being on the same network?

    Thanks and keep the great tutorials coming! 🙂

    Reply
    • Perhaps have the config files on an external Db (MySQL) and get the ESP32 to check for updates routinely or each time it wakes

      Reply
  6. For some reason this site will not let me reply to your reply to my question so I am posting it as a top level question.

    Sorry I wasn’t clear. I need to distribute identical ESPs to many different people, all with router logins that I do not and cannot know. Since your code requires knowing their SSIDs and passwords and entering them into the code, I cannot use your code as written. Is there a way to do this without knowing the SSID and password of my clients’ routers? If so, could you show the code? Thank you!

    Reply
  7. Is it possible /serverIndex to open in the same tab? Also if the login failure happens, the address bar to NOT show the whole link including the pass and userid?

    In case I need to include some small icons, which directory/where do I need to put them in the code?

    Thank you!

    Reply
    • This method is not secure, so I wouldn’t rely on the login, because anyone with the URL we’ll be able to access the web page. This sketch comes with the OTA library. In the future, I plan to create a real login to prevent anyone to access and upload a new firmware. Thanks for asking.

      Reply
  8. Boa tarde!

    O código funciona bem quando fazemos upload de um sketch pela primeira vez, mas se fizermos upload de outro sketch deixa de funcionar.
    É possível solucionar este problema?

    Reply
    • Olá Francisco.
      Quando faz upload the um novo sketch, esse sketch precisa de ter o código para OTA.
      Se fizer upload de um sketch que não tem a parte de código para OTA, deixa de existir OTA a correr na ESP32.
      Espero que tenha sido claro.
      Cumprimentos,
      Sara 🙂

      Reply
      • Sim, já estava a falar de sketch’s que incluíam o código OTA.
        Mas mesmo assim o segundo upload não funciona.

        Cumprimentos,

        Francisco

        Reply
  9. Hello, I’m a little new to the Esp32 and OTA updates. Can someone explain how the server.on callback works with the /update? I see two inline functions, where the first one has the ESP.restart. How does the ESP32 collect the data from the second inline function before performing the software restart?

    Reply
  10. Is it possible to use this OTA capability along with a web server application? I have an IOT application that uses a server to provide a web page for control of a device (similar to your server example). I’d like to be able to use OTA updates so the devices would not need to be accessed to update the software. How could these be integrated together?
    Thanks,
    Leon

    Reply
    • Hi Leon.
      The OTA example we provide here uses the and libraries to create a web server in which you can upload new code on the /serverIndex URL.
      One solution is to build your web server on a different URL using these libraries. However, I don’t have any example or tutorial about this.
      Anyway, I hope this suggestion can help you.
      Regards,
      Sara

      Reply
      • I had exactly the same question. It would be really useful to have some guidance on how to do this. I also have a webserver application that I would like to update remotely. I am not an html person, but quite capable of adapting an example

        Reply
        • I found your message just now, after our long discussion on the subject. I am therefore placing a link here to our exchange, which may perhaps be able to enlighten the path of all those who seek to achieve the same thing:

          https://rntlab.com/question/using-webserver-and-ota-updates/

          As promised, as soon as I have the time, I will prepare an example to illustrate my words, which you can easily reproduce to adapt to your needs.

          Reply
          • Any news on this? Would love to see a tutorial on this, or at least some quick guidance on how to combine the two. I think we understand each of the parts by itself, but its the combining that is tricky.

          • It seems to me you’ve already found the answer to your question…

            You probably followed the discussion I had with David, or you saw my post announcing the publication of my project on GitHub :

            https://rntlab.com/question/esp32-web-apps-with-websockets-ota-web-updates/

            By the way, I answered your questions about GitHub…

            I hope you were able to apply the technique I implemented for your own projects. I took care to comment my code to make it easier to understand.

  11. This works great. Now I want to use OTA reprogramming on an ESP32 that is asleep in light sleep mode most of the time, and not easily accessible to plug in with wires. How long does it need to be awake for to be able to reprogram it?

    Reply
    • Hi Steve.
      I haven’t tested how much time it needs to completely update the code via OTA.
      You need to test it yourself. But I think that maybe 20 to 30 seconds is enough (it probably needs less time).
      Sorry that I can’t help much.
      Thank you for supporting our work.
      Regards.

      Reply
  12. Hi All,

    I’ve done an Android app that communicates with my ESP32 via BLE. I am thinking of using the Android app to download a new software image to the ESP32. My thought are to store the ESP32 image on Firebase. The phone will check every so often to see if there is a new image. If there is, it will download it onto itself and then program the ESP32.
    Questions:
    1) Has anyone done this before?
    2) Are there better ways of doing it?
    3) How do I transfer the image from the phone to the esp32? (Some server listening for an image or a command to download the file as described above or a direct Wifi connection?
    4) Any code available?
    Any suggestions will be appreciated

    Reply
    • Hi.
      That’s quite of a project!
      Unfortunately, we don’t have any tutorials related with what you want to do, and I’m not familiar with those specific subjects to give you advice.
      I’m sorry that I can’t help much.
      Regards,
      Sara

      Reply
  13. Nice article – I was able to learn many new things here. Simple Understandable Instructions with snapshots. Was easy to learn.
    Good Luck,

    My question : I want to blink GPIO 26 instead of the onboard LED.
    How do I go about it – I tried “const int led=26” – did not work .

    Appreciate a reply.
    Shashi

    Reply
    • Hi Shashi.
      Have you changed anything else in the code?
      Changing the pin to 26 should work. Please make sure that you’ve wired the LED correctly.
      Regards,
      Sara

      Reply
  14. For the ones asking to use the ESP32 as a webserver AND some OTA, try IOTAppstory. I have tried to combine this Santos-OTA with webserver applications and was not successful

    Reply
  15. Hi,

    Great tutorial to explain how to do OTA. My question is: I am going to create an application that will search for the Wi-Fi enabled device and connect to it. If my mobile application connects to the ESP32 and I just want to update the SSID and PASSWORD inside of ESP32 to connect it with Home router how will I achieve this? Just SSID and PASSWORD OTA without creating and uploading .bin file and all.

    Reply
    • Hi.
      I think you’re looking for something like WiFi Manager: github.com/zhouhan0126/WIFIMANAGER-ESP32
      I hope this helps.
      Regards,
      Sara

      Reply
  16. Hi Random Nerds,
    I use an ESP32 and separate the code to the two core. One shall handle the Wifi and Modbus connection to my Home Central. The other shall handle the main program with fetching data from sensors and execute actors.
    At which core shall I assign the web server for the OTA functions?
    In the Arduino IDE is an option under Tools to change code and Wifi. I think this must be set to code only, right?

    Reply
  17. Thank you! After wasting a lot of time on other forums and blogs your tutorial just works as it should. You are doing a great servide to the maker community; keep up the good work!

    James

    Reply
  18. There is a grammatical error in the title of the section named “How does OTA Web Updater Works?”. It should instead say “How Does OTA Web Updater Work?” (“does” -> “Does” and “Works?” to “Work?”).

    BTW, I love your ESP8266 pinout guide!

    Reply
  19. Yet another great tutorial – thank you.
    I now have my esp32 workshop environs controller using esp NOW many to many to pass sensor readings back and forth between two workshops and the house and they are OTA capable with a Web accessed dashboard.
    I am on a roll.
    Thanks again Rui and Sara

    Reply
  20. I’m using Basic OTA rather than Web Updater OTA. But in any case I understood that OTA updates only allow you to use up to 50% of program memory, since during the update both the old and new copies of the application need to be stored. After successful update the updater would then switch to using the new version.

    At this point my application is well over 50% but OTA still works fine:
    Sketch uses 876226 bytes (66%) of program storage space. Maximum is 1310720 bytes.
    Global variables use 46784 bytes (14%) of dynamic memory, leaving 280896 bytes for local variables. Maximum is 327680 bytes.

    How is it that my updates still succeed, and is there some OTHER hard limit at which OTA updates will not work?

    Reply
  21. Hello Sara!
    how are you?
    Congratulations on the work!
    The update is stopping at 12% and does not end, would you have any idea why?
    I’m using esp32 cam!
    Thank you for your help

    Reply
    • You probably have the answer by now but my suggestion would be to check partition type, it may be of type with “No OTA” and select something like “Minimal SPIFFS with OTA”.

      Reply
    • I have the same issue like you. First time on arduino example it worked, now when I uploaded my code with web upload I see that upload sto on laptop on 24% and on phone on 53%. Can somebody help please?

      Reply
          • I have used timerAlarmDisable(timer) ; in this part of the code:

            if (upload.status == UPLOAD_FILE_START) {
            timerAlarmDisable(timer) ;
            Serial.printf(“Update: %s\n”, upload.filename.c_str());
            if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
            Update.printError(Serial);
            }

            WDT Timer like this:
            github.com/espressif/arduino-esp32/issues/841

  22. Hi all,
    I am trying to use this OTA example but into my .ino program I am getting “WebServer does not name a type” error .

    Any idea ?

    Thank

    Reply
    • Hi.
      Make sure you have the OTAWebUpdater library installed and that you have an ESP32 selected when compiling and uploading the code.
      Regards,
      Sara

      Reply
  23. Great article!
    How could this be implemented with the ESP32 Now-Many to one? I tried and it does an uploadonce but fails to connect to the IP after that.

    thanks.

    dave

    Reply
  24. Thanks for sharing this great information with us.
    I’m trying to find ESPmDNS library but unfortunately, I couldn’t find it.
    Could you please share with me a link where I can download the library?

    Many thanks,
    Nadav

    Reply
  25. Hi,
    Another great tutorial, thank you.
    I do have a query though.
    I have complied the example using PlatformIO and it works fine by serial or by uploading the .bin file but the compiler reports this:
    RAM: [= ] 12.7% (used 41504 bytes from 327680 bytes)
    Flash: [====== ] 58.5% (used 767182 bytes from 1310720 bytes)
    This does correspond with the .bin file size of 750k.
    So, the ‘Flash’ (58%), the amount that will be used out of the total, in which case as it is greater than half, how does it fit in along with the current running code.
    Or is this 58% of ‘AVAILABLE’ flash?
    It also raises another question, it reports I have 1310720 bytes (1.3MB), so where is the rest as it is supposed to have 4MB of flash.
    Thanks
    Martin

    Reply
  26. Hi,

    Just wanted to thank you both for your excellent work. I have read several of your tutorials and they are very well written, concise and clear. Muchas gracias!

    Reply
  27. Great tutorial. I have done the OTA update lessons and they have worked great. I have also purchased your How to make esp32 a server book. However, I need something different. I have an esp32 in the field behind a router (that I have no access to) that I want to do OTA with. I also cannot put ngrok server on the local network with the esp32 to make it accessible from the outside of its local network. At my home base (from where I want to load the OTA) I can make a server accessible from the outside via a port forward on my router. So, can I have the esp32 in the field initiate contact with my local server periodically to ask it if there is an OTA available and it so, download it and update itself. Since the esp32 in the field is making the contact there would no need to be able to initiate the the contact with it via a gnrok arrangement. I hope I have made myself clear. Any help would be appreciated.

    Reply
      • Sara
        Thanks for the response. I was not aware of AppStory. It sounds like exactly what I was trying to do. I will check it out. I was just trying to do this by having the code in the remote esp32 “call back to my server” at my home for an update. Then a connection could created directly between the two. The server could then push a binary to the remote esp32 to allow it to update itself. This seems what appstory is doing except in that case the remote esp32 connects to their cloud service instead of my home server. Sounds simple to do but I’ll check appstory out.
        Ed
        BTW you guys have a great website!

        Reply
        • Thanks Ed.
          I haven’t experimented with the IoT App Story myself, but I heard good things about it.
          Regards,
          Sara

          Reply
  28. Hello Random Nerd team,
    I followed your tutorial which definitely helped me achieving OTA capabilities. Additionally, could you kindly suggest if there is a way to POST the bin over network without manually opening the form on browser? I have seen some examples where the ESP was used as a client which downloaded the file? But can we keep the server capabilities intact and yet download the file in the same manner ?

    Thank you again.

    Regards,
    Shariq

    Reply
    • Hello All,
      Thankfully I was able to solve my own problem by doing a post request using a python script. Pasting it here for any future reference..

      #!Python
      import requests
      files = {‘file’: open(r””, ‘rb’)}

      final_resp = requests.post(“http://update”, files=files)

      Regards,
      Shariq

      Reply
    • This uses the asyncwebserver library. So, it it easy to integrate and it is compatible with web servers built using the asyncwebserver library.
      It also allows to upload files to the filesystem.
      Regards,
      Sara

      Reply
  29. Hello everyone!

    Is it possble to make ESP download the bin from url and to burn it itself? I want to code web API for this, but I cannot understand how wifi client will download bin and run it.

    Best,
    Uliana

    Reply
  30. Hi,

    i’ve tried your code but get the following error message on browser after having selected a *.bin-file and pressed the upload button:

    “Not found:/serverIndex”

    The only thing i changed in the code is Wifi-AP instead of station.
    Can you help me? What does this message meach ;-(

    Reply
  31. Hi Sara,
    Thanks for your work with these libraries. It seems that ElegantOTA is locked into Wifi access only. Is there a way to use it over GSM?
    Best Paul

    Reply
  32. Hi house, i was trying use OTA programming with esp32. The example given in the arduino ide only to set the esp as station not as AP. So i cannot use OTA without using a router. But i want to use only my computer with the esp because i need to program the esp on the field which no access to router.

    I checked online but i didnt see something substantial. I decided to do it my way and it worked. Its very easy and i decided to share the idea.

    From the example given in the arduino.

    Changed STA to AP using WiFi.mode(WIFI_AP);
    Wifi.softAP instead of wifi.begin
    I forced the local IP address to 192.168.4.1 with. “IPAddress local_IP(192,168,4,1);”
    I removed the while loop so i dont need to check if wifi is connected.

    Boom…. It worked…. I can now upload program to esp32 without a router.

    Reply
  33. What happens if the OTA is interrupted in between, say the power in unplugged or the WiFi goes off? Will I lose the old firmware that was running before the OTA?

    Reply
  34. Thanks for this (and all the other excellent) tutorials!
    I am just a little bit concerned about the lack of security in this one. The username and password are visible in the HTML code of the login page, but you do not even need those, you can directly go to the completely unsecured /update page.
    Your tutorial https://randomnerdtutorials.com/esp32-esp8266-web-server-http-authentication/ shows how it is done correctly, and that it is really easy: just send a 401 response code (which makes the browser ask the user for credentials) until you receive a valid “Authorization: Basic …” Header. No need for a login page and much more secure.

    Reply
  35. Hello, the “Hello” part is working for me, but not the upload.
    It jumps to 18% and stays stuck there. Tried in 2 different esp32 boards, different browsers. The code is copy/paste from the tutorial.

    I also noticed it reboots the ESP on upload, I get this:
    “abort() was called at PC 0x40081f62 on core 1”
    ….
    “Rebooting”

    Any clues?

    Reply
  36. Hi,
    Thank you for the amazing tutorials. I followed your steps to install ESP32 for IDE 2 (I am on 2.0.4) but I get the error about WebServer.h:

    C:.…\Arduino\OTA_WEBUPDATE\OTA_WEBUPDATE.ino:4:10: fatal error: WebServer.h: No such file or directory
    4 | #include <WebServer.h>

    What is the correct WebServer.H file?

    I also tried this on the Cloud Editor and it didn’t like Update.h.

    Any help?

    Reply
  37. Very useful!!
    But probably a validation via TOKEN on the upload page itself would be more useful than this login screen, which in reality just hides the upload URL.

    Reply
  38. Hi:
    just to report a strange situation. I’ve an esp32 that simply does not update over OTA. The software works well on others ESP32. Only this one doesn’t work. It will however update using a cable connection. This is of course result from a chine bad esp32 board…

    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.