{"id":78214,"date":"2018-11-29T12:07:49","date_gmt":"2018-11-29T12:07:49","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=78214"},"modified":"2020-06-12T09:07:31","modified_gmt":"2020-06-12T09:07:31","slug":"esp32-over-the-air-ota-programming","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp32-over-the-air-ota-programming\/","title":{"rendered":"ESP32 Over-the-air (OTA) Programming &#8211; Web Updater Arduino IDE"},"content":{"rendered":"<p>Quick guide that shows how to do over-the-air (OTA) programming with the ESP32 using the OTA Web Updater in Arduino IDE.\u00a0The 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.<\/p>\n<p><!--more--><\/p>\n<p><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" class=\"aligncenter wp-image-78257 size-full\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/OTAWebUpdates_ESP32_thumbnail.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"esp32-ota-web-updates\" width=\"1200\" height=\"675\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/OTAWebUpdates_ESP32_thumbnail.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/OTAWebUpdates_ESP32_thumbnail.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/OTAWebUpdates_ESP32_thumbnail.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/OTAWebUpdates_ESP32_thumbnail.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/p>\n<p>OTA programming is useful when you need to update code to ESP32 boards that are not easily accessible. The example we\u2019ll show here works when the ESP32 and your browser are on your local network.<\/p>\n<p>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&#8217;re able to use OTA in the future.<\/p>\n<h2>How does OTA Web Updater Work?<\/h2>\n<ul>\n<li>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.<\/li>\n<li>The OTA Web Updater sketch creates a web server you can access to upload a new sketch via web browser.<\/li>\n<li>Then, you need to implement OTA routines in every sketch you upload, so that you&#8217;re able to do the next updates\/uploads over-the-air.<\/li>\n<li>If you upload a code without a OTA routine you&#8217;ll no longer be able to access the web server and upload a new sketch over-the-air.<\/li>\n<\/ul>\n<h2>Prerequisites<\/h2>\n<p><span style=\"font-weight: 400;\">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\u2019t already.<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\"><a href=\"https:\/\/randomnerdtutorials.com\/installing-the-esp32-board-in-arduino-ide-windows-instructions\/\"><span style=\"font-weight: 400;\">Installing the ESP32 Board in Arduino IDE (Windows instructions)<\/span><\/a><\/li>\n<li style=\"font-weight: 400;\"><a href=\"https:\/\/randomnerdtutorials.com\/installing-the-esp32-board-in-arduino-ide-mac-and-linux-instructions\/\"><span style=\"font-weight: 400;\">Installing the ESP32 Board in Arduino IDE (Mac and Linux instructions)<\/span><\/a><\/li>\n<\/ul>\n<h2>ESP32 OTA Web Updater<\/h2>\n<p>When you install the ESP32 add-on for the Arduino IDE, it will automatically install the ArduinoOTA library. Go to <strong>File<\/strong> &gt; <strong>Examples<\/strong> &gt;<strong>ArduinoOTA<\/strong>&gt; <strong>OTAWebUpdater<\/strong>.<\/p>\n<p><img data-recalc-dims=\"1\" decoding=\"async\" class=\"aligncenter wp-image-78216 size-full\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/OTAwebupdater_example.png?resize=565%2C594&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"otawebupdater-arduino-ide\" width=\"565\" height=\"594\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/OTAwebupdater_example.png?w=565&amp;quality=100&amp;strip=all&amp;ssl=1 565w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/OTAwebupdater_example.png?resize=285%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 285w\" sizes=\"(max-width: 565px) 100vw, 565px\" \/><\/p>\n<p>The following code should load.<\/p>\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\n * OTAWebUpdater.ino Example from ArduinoOTA Library\n * Rui Santos \n * Complete Project Details http:\/\/randomnerdtutorials.com\n *\/\n\n#include &lt;WiFi.h&gt;\n#include &lt;WiFiClient.h&gt;\n#include &lt;WebServer.h&gt;\n#include &lt;ESPmDNS.h&gt;\n#include &lt;Update.h&gt;\n\nconst char* host = &quot;esp32&quot;;\nconst char* ssid = &quot;REPLACE_WITH_YOUR_SSID&quot;;\nconst char* password = &quot;REPLACE_WITH_YOUR_PASSWORD&quot;;\n\nWebServer server(80);\n\n\/*\n * Login page\n *\/\nconst char* loginIndex = \n &quot;&lt;form name='loginForm'&gt;&quot;\n    &quot;&lt;table width='20%' bgcolor='A09F9F' align='center'&gt;&quot;\n        &quot;&lt;tr&gt;&quot;\n            &quot;&lt;td colspan=2&gt;&quot;\n                &quot;&lt;center&gt;&lt;font size=4&gt;&lt;b&gt;ESP32 Login Page&lt;\/b&gt;&lt;\/font&gt;&lt;\/center&gt;&quot;\n                &quot;&lt;br&gt;&quot;\n            &quot;&lt;\/td&gt;&quot;\n            &quot;&lt;br&gt;&quot;\n            &quot;&lt;br&gt;&quot;\n        &quot;&lt;\/tr&gt;&quot;\n        &quot;&lt;td&gt;Username:&lt;\/td&gt;&quot;\n        &quot;&lt;td&gt;&lt;input type='text' size=25 name='userid'&gt;&lt;br&gt;&lt;\/td&gt;&quot;\n        &quot;&lt;\/tr&gt;&quot;\n        &quot;&lt;br&gt;&quot;\n        &quot;&lt;br&gt;&quot;\n        &quot;&lt;tr&gt;&quot;\n            &quot;&lt;td&gt;Password:&lt;\/td&gt;&quot;\n            &quot;&lt;td&gt;&lt;input type='Password' size=25 name='pwd'&gt;&lt;br&gt;&lt;\/td&gt;&quot;\n            &quot;&lt;br&gt;&quot;\n            &quot;&lt;br&gt;&quot;\n        &quot;&lt;\/tr&gt;&quot;\n        &quot;&lt;tr&gt;&quot;\n            &quot;&lt;td&gt;&lt;input type='submit' onclick='check(this.form)' value='Login'&gt;&lt;\/td&gt;&quot;\n        &quot;&lt;\/tr&gt;&quot;\n    &quot;&lt;\/table&gt;&quot;\n&quot;&lt;\/form&gt;&quot;\n&quot;&lt;script&gt;&quot;\n    &quot;function check(form)&quot;\n    &quot;{&quot;\n    &quot;if(form.userid.value=='admin' &amp;&amp; form.pwd.value=='admin')&quot;\n    &quot;{&quot;\n    &quot;window.open('\/serverIndex')&quot;\n    &quot;}&quot;\n    &quot;else&quot;\n    &quot;{&quot;\n    &quot; alert('Error Password or Username')\/*displays error message*\/&quot;\n    &quot;}&quot;\n    &quot;}&quot;\n&quot;&lt;\/script&gt;&quot;;\n \n\/*\n * Server Index Page\n *\/\n \nconst char* serverIndex = \n&quot;&lt;script src='https:\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/3.2.1\/jquery.min.js'&gt;&lt;\/script&gt;&quot;\n&quot;&lt;form method='POST' action='#' enctype='multipart\/form-data' id='upload_form'&gt;&quot;\n   &quot;&lt;input type='file' name='update'&gt;&quot;\n        &quot;&lt;input type='submit' value='Update'&gt;&quot;\n    &quot;&lt;\/form&gt;&quot;\n &quot;&lt;div id='prg'&gt;progress: 0%&lt;\/div&gt;&quot;\n &quot;&lt;script&gt;&quot;\n  &quot;$('form').submit(function(e){&quot;\n  &quot;e.preventDefault();&quot;\n  &quot;var form = $('#upload_form')[0];&quot;\n  &quot;var data = new FormData(form);&quot;\n  &quot; $.ajax({&quot;\n  &quot;url: '\/update',&quot;\n  &quot;type: 'POST',&quot;\n  &quot;data: data,&quot;\n  &quot;contentType: false,&quot;\n  &quot;processData:false,&quot;\n  &quot;xhr: function() {&quot;\n  &quot;var xhr = new window.XMLHttpRequest();&quot;\n  &quot;xhr.upload.addEventListener('progress', function(evt) {&quot;\n  &quot;if (evt.lengthComputable) {&quot;\n  &quot;var per = evt.loaded \/ evt.total;&quot;\n  &quot;$('#prg').html('progress: ' + Math.round(per*100) + '%');&quot;\n  &quot;}&quot;\n  &quot;}, false);&quot;\n  &quot;return xhr;&quot;\n  &quot;},&quot;\n  &quot;success:function(d, s) {&quot;\n  &quot;console.log('success!')&quot; \n &quot;},&quot;\n &quot;error: function (a, b, c) {&quot;\n &quot;}&quot;\n &quot;});&quot;\n &quot;});&quot;\n &quot;&lt;\/script&gt;&quot;;\n\n\/*\n * setup function\n *\/\nvoid setup(void) {\n  Serial.begin(115200);\n\n  \/\/ Connect to WiFi network\n  WiFi.begin(ssid, password);\n  Serial.println(&quot;&quot;);\n\n  \/\/ Wait for connection\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(500);\n    Serial.print(&quot;.&quot;);\n  }\n  Serial.println(&quot;&quot;);\n  Serial.print(&quot;Connected to &quot;);\n  Serial.println(ssid);\n  Serial.print(&quot;IP address: &quot;);\n  Serial.println(WiFi.localIP());\n\n  \/*use mdns for host name resolution*\/\n  if (!MDNS.begin(host)) { \/\/http:\/\/esp32.local\n    Serial.println(&quot;Error setting up MDNS responder!&quot;);\n    while (1) {\n      delay(1000);\n    }\n  }\n  Serial.println(&quot;mDNS responder started&quot;);\n  \/*return index page which is stored in serverIndex *\/\n  server.on(&quot;\/&quot;, HTTP_GET, []() {\n    server.sendHeader(&quot;Connection&quot;, &quot;close&quot;);\n    server.send(200, &quot;text\/html&quot;, loginIndex);\n  });\n  server.on(&quot;\/serverIndex&quot;, HTTP_GET, []() {\n    server.sendHeader(&quot;Connection&quot;, &quot;close&quot;);\n    server.send(200, &quot;text\/html&quot;, serverIndex);\n  });\n  \/*handling uploading firmware file *\/\n  server.on(&quot;\/update&quot;, HTTP_POST, []() {\n    server.sendHeader(&quot;Connection&quot;, &quot;close&quot;);\n    server.send(200, &quot;text\/plain&quot;, (Update.hasError()) ? &quot;FAIL&quot; : &quot;OK&quot;);\n    ESP.restart();\n  }, []() {\n    HTTPUpload&amp; upload = server.upload();\n    if (upload.status == UPLOAD_FILE_START) {\n      Serial.printf(&quot;Update: %s\\n&quot;, upload.filename.c_str());\n      if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { \/\/start with max available size\n        Update.printError(Serial);\n      }\n    } else if (upload.status == UPLOAD_FILE_WRITE) {\n      \/* flashing firmware to ESP*\/\n      if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {\n        Update.printError(Serial);\n      }\n    } else if (upload.status == UPLOAD_FILE_END) {\n      if (Update.end(true)) { \/\/true to set the size to the current progress\n        Serial.printf(&quot;Update Success: %u\\nRebooting...\\n&quot;, upload.totalSize);\n      } else {\n        Update.printError(Serial);\n      }\n    }\n  });\n  server.begin();\n}\n\nvoid loop(void) {\n  server.handleClient();\n  delay(1);\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/OTA_Web_Updater.ino\" target=\"_blank\">View raw code<\/a><\/p>\n<p>You should change the following lines on the code to include your own network credentials:<\/p>\n<pre>const char* ssid = \"\";\nconst char* password = \"\";<\/pre>\n<p>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.<\/p>\n<p>Upload the previous code to your ESP32 board. Don\u2019t forget to enter your network credentials and select the right board and serial port.<\/p>\n<p><img data-recalc-dims=\"1\" decoding=\"async\" class=\"aligncenter size-full wp-image-65439\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2016\/12\/arduino-ide-upload-button.png?resize=34%2C29&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" width=\"34\" height=\"29\" \/><\/p>\n<p>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:<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-78217\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/IP-address.jpg?resize=632%2C390&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" width=\"632\" height=\"390\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/IP-address.jpg?w=632&amp;quality=100&amp;strip=all&amp;ssl=1 632w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/IP-address.jpg?resize=300%2C185&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 632px) 100vw, 632px\" \/><\/p>\n<p>Now, you can upload code to your ESP32 over-the-air using a browser on your local network.<\/p>\n<p>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&#8217;re suggesting this to mimic a situation in which the ESP32 is not connected to your computer).<\/p>\n<h2>Update New Code using OTA Web Updater<\/h2>\n<p>Open a browser in your network and enter the ESP32 IP address. You should get the following:<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-78218 size-full\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/esp32-login-page.jpg?resize=667%2C396&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"otawebupdater-user-pass\" width=\"667\" height=\"396\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/esp32-login-page.jpg?w=667&amp;quality=100&amp;strip=all&amp;ssl=1 667w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/esp32-login-page.jpg?resize=300%2C178&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 667px) 100vw, 667px\" \/><\/p>\n<p>Enter the username and the password:<\/p>\n<ul>\n<li><strong>Username<\/strong>: admin<\/li>\n<li><strong>Password<\/strong>: admin<\/li>\n<\/ul>\n<p>You can change the username and password on the code.<\/p>\n<p><strong>Note:\u00a0<\/strong>After you enter the username and password, you are redirected to the <em>\/serverIndex<\/em> URL. You don&#8217;t need to enter the username and password to access the <em>\/serverIndex<\/em> URL. So, if someone knows the URL to upload new code, the username and password don&#8217;t protect the web page from being accessible from others.<\/p>\n<p>A new tab should open on the <em>\/serverIndex<\/em> URL. This page allows you to upload a new code to your ESP32. You should upload <em>.bin<\/em> files (we&#8217;ll see how to do that in a moment).<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-78224 size-full\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serverindex.jpg?resize=621%2C333&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ota-web-updater-esp32\" width=\"621\" height=\"333\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serverindex.jpg?w=621&amp;quality=100&amp;strip=all&amp;ssl=1 621w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serverindex.jpg?resize=300%2C161&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serverindex.jpg?resize=280%2C150&amp;quality=100&amp;strip=all&amp;ssl=1 280w\" sizes=\"(max-width: 621px) 100vw, 621px\" \/><\/p>\n<h2>Preparing the New Sketch<\/h2>\n<p>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\u00a0always overwrite any sketch with a new one in the future. So, we recommend that you modify the\u00a0OTAWebUpdater sketch to include your own code.<\/p>\n<p>For learning purposes let&#8217;s upload a new code that blinks an LED (without delay). Copy the following code to your Arduino IDE.<\/p>\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\n * Rui Santos \n * Complete Project Details http:\/\/randomnerdtutorials.com\n *\/\n\n#include &lt;WiFi.h&gt;\n#include &lt;WiFiClient.h&gt;\n#include &lt;WebServer.h&gt;\n#include &lt;ESPmDNS.h&gt;\n#include &lt;Update.h&gt;\n\nconst char* host = &quot;esp32&quot;;\nconst char* ssid = &quot;REPLACE_WITH_YOUR_SSID&quot;;\nconst char* password = &quot;REPLACE_WITH_YOUR_PASSWORD&quot;;\n\n\/\/variabls to blink without delay:\nconst int led = 2;\nunsigned long previousMillis = 0;        \/\/ will store last time LED was updated\nconst long interval = 1000;           \/\/ interval at which to blink (milliseconds)\nint ledState = LOW;             \/\/ ledState used to set the LED\n\nWebServer server(80);\n\n\/*\n * Login page\n *\/\n\nconst char* loginIndex = \n &quot;&lt;form name='loginForm'&gt;&quot;\n    &quot;&lt;table width='20%' bgcolor='A09F9F' align='center'&gt;&quot;\n        &quot;&lt;tr&gt;&quot;\n            &quot;&lt;td colspan=2&gt;&quot;\n                &quot;&lt;center&gt;&lt;font size=4&gt;&lt;b&gt;ESP32 Login Page&lt;\/b&gt;&lt;\/font&gt;&lt;\/center&gt;&quot;\n                &quot;&lt;br&gt;&quot;\n            &quot;&lt;\/td&gt;&quot;\n            &quot;&lt;br&gt;&quot;\n            &quot;&lt;br&gt;&quot;\n        &quot;&lt;\/tr&gt;&quot;\n        &quot;&lt;td&gt;Username:&lt;\/td&gt;&quot;\n        &quot;&lt;td&gt;&lt;input type='text' size=25 name='userid'&gt;&lt;br&gt;&lt;\/td&gt;&quot;\n        &quot;&lt;\/tr&gt;&quot;\n        &quot;&lt;br&gt;&quot;\n        &quot;&lt;br&gt;&quot;\n        &quot;&lt;tr&gt;&quot;\n            &quot;&lt;td&gt;Password:&lt;\/td&gt;&quot;\n            &quot;&lt;td&gt;&lt;input type='Password' size=25 name='pwd'&gt;&lt;br&gt;&lt;\/td&gt;&quot;\n            &quot;&lt;br&gt;&quot;\n            &quot;&lt;br&gt;&quot;\n        &quot;&lt;\/tr&gt;&quot;\n        &quot;&lt;tr&gt;&quot;\n            &quot;&lt;td&gt;&lt;input type='submit' onclick='check(this.form)' value='Login'&gt;&lt;\/td&gt;&quot;\n        &quot;&lt;\/tr&gt;&quot;\n    &quot;&lt;\/table&gt;&quot;\n&quot;&lt;\/form&gt;&quot;\n&quot;&lt;script&gt;&quot;\n    &quot;function check(form)&quot;\n    &quot;{&quot;\n    &quot;if(form.userid.value=='admin' &amp;&amp; form.pwd.value=='admin')&quot;\n    &quot;{&quot;\n    &quot;window.open('\/serverIndex')&quot;\n    &quot;}&quot;\n    &quot;else&quot;\n    &quot;{&quot;\n    &quot; alert('Error Password or Username')\/*displays error message*\/&quot;\n    &quot;}&quot;\n    &quot;}&quot;\n&quot;&lt;\/script&gt;&quot;;\n \n\/*\n * Server Index Page\n *\/\n \nconst char* serverIndex = \n&quot;&lt;script src='https:\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/3.2.1\/jquery.min.js'&gt;&lt;\/script&gt;&quot;\n&quot;&lt;form method='POST' action='#' enctype='multipart\/form-data' id='upload_form'&gt;&quot;\n   &quot;&lt;input type='file' name='update'&gt;&quot;\n        &quot;&lt;input type='submit' value='Update'&gt;&quot;\n    &quot;&lt;\/form&gt;&quot;\n &quot;&lt;div id='prg'&gt;progress: 0%&lt;\/div&gt;&quot;\n &quot;&lt;script&gt;&quot;\n  &quot;$('form').submit(function(e){&quot;\n  &quot;e.preventDefault();&quot;\n  &quot;var form = $('#upload_form')[0];&quot;\n  &quot;var data = new FormData(form);&quot;\n  &quot; $.ajax({&quot;\n  &quot;url: '\/update',&quot;\n  &quot;type: 'POST',&quot;\n  &quot;data: data,&quot;\n  &quot;contentType: false,&quot;\n  &quot;processData:false,&quot;\n  &quot;xhr: function() {&quot;\n  &quot;var xhr = new window.XMLHttpRequest();&quot;\n  &quot;xhr.upload.addEventListener('progress', function(evt) {&quot;\n  &quot;if (evt.lengthComputable) {&quot;\n  &quot;var per = evt.loaded \/ evt.total;&quot;\n  &quot;$('#prg').html('progress: ' + Math.round(per*100) + '%');&quot;\n  &quot;}&quot;\n  &quot;}, false);&quot;\n  &quot;return xhr;&quot;\n  &quot;},&quot;\n  &quot;success:function(d, s) {&quot;\n  &quot;console.log('success!')&quot; \n &quot;},&quot;\n &quot;error: function (a, b, c) {&quot;\n &quot;}&quot;\n &quot;});&quot;\n &quot;});&quot;\n &quot;&lt;\/script&gt;&quot;;\n\n\/*\n * setup function\n *\/\nvoid setup(void) {\n  pinMode(led, OUTPUT);\n  \n  Serial.begin(115200);\n\n  \/\/ Connect to WiFi network\n  WiFi.begin(ssid, password);\n  Serial.println(&quot;&quot;);\n\n  \/\/ Wait for connection\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(500);\n    Serial.print(&quot;.&quot;);\n  }\n  Serial.println(&quot;&quot;);\n  Serial.print(&quot;Connected to &quot;);\n  Serial.println(ssid);\n  Serial.print(&quot;IP address: &quot;);\n  Serial.println(WiFi.localIP());\n\n  \/*use mdns for host name resolution*\/\n  if (!MDNS.begin(host)) { \/\/http:\/\/esp32.local\n    Serial.println(&quot;Error setting up MDNS responder!&quot;);\n    while (1) {\n      delay(1000);\n    }\n  }\n  Serial.println(&quot;mDNS responder started&quot;);\n  \/*return index page which is stored in serverIndex *\/\n  server.on(&quot;\/&quot;, HTTP_GET, []() {\n    server.sendHeader(&quot;Connection&quot;, &quot;close&quot;);\n    server.send(200, &quot;text\/html&quot;, loginIndex);\n  });\n  server.on(&quot;\/serverIndex&quot;, HTTP_GET, []() {\n    server.sendHeader(&quot;Connection&quot;, &quot;close&quot;);\n    server.send(200, &quot;text\/html&quot;, serverIndex);\n  });\n  \/*handling uploading firmware file *\/\n  server.on(&quot;\/update&quot;, HTTP_POST, []() {\n    server.sendHeader(&quot;Connection&quot;, &quot;close&quot;);\n    server.send(200, &quot;text\/plain&quot;, (Update.hasError()) ? &quot;FAIL&quot; : &quot;OK&quot;);\n    ESP.restart();\n  }, []() {\n    HTTPUpload&amp; upload = server.upload();\n    if (upload.status == UPLOAD_FILE_START) {\n      Serial.printf(&quot;Update: %s\\n&quot;, upload.filename.c_str());\n      if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { \/\/start with max available size\n        Update.printError(Serial);\n      }\n    } else if (upload.status == UPLOAD_FILE_WRITE) {\n      \/* flashing firmware to ESP*\/\n      if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {\n        Update.printError(Serial);\n      }\n    } else if (upload.status == UPLOAD_FILE_END) {\n      if (Update.end(true)) { \/\/true to set the size to the current progress\n        Serial.printf(&quot;Update Success: %u\\nRebooting...\\n&quot;, upload.totalSize);\n      } else {\n        Update.printError(Serial);\n      }\n    }\n  });\n  server.begin();\n}\n\nvoid loop(void) {\n  server.handleClient();\n  delay(1);\n\n  \/\/loop to blink without delay\n  unsigned long currentMillis = millis();\n\n  if (currentMillis - previousMillis &gt;= interval) {\n    \/\/ save the last time you blinked the LED\n    previousMillis = currentMillis;\n\n    \/\/ if the LED is off turn it on and vice-versa:\n    ledState = not(ledState);\n\n    \/\/ set the LED with the ledState of the variable:\n    digitalWrite(led, ledState);\n  }\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/OTA_Web_Updater_LED.ino\" target=\"_blank\">View raw code<\/a><\/p>\n<p>As you can see, we&#8217;ve added the &#8220;blink without delay&#8221; code to the OTAWebUpdater code, so that we&#8217;re able to make updates later on.<\/p>\n<p>After copying the code to your Arduino IDE, you should generate a <em>.bin<\/em> file.<\/p>\n<h3>Generate a .bin file in Arduino IDE<\/h3>\n<p>Save your sketch as<em> LED_Web_Updater<\/em>.<\/p>\n<p>To generate a <em>.bin<\/em> file from your sketch, go to <strong>Sketch<\/strong> &gt; <strong>Export compiled Binary<\/strong><\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-78226 size-full\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/export-binary-file-arduino-ide.png?resize=651%2C231&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"export-bin-file-arduino-ide\" width=\"651\" height=\"231\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/export-binary-file-arduino-ide.png?w=651&amp;quality=100&amp;strip=all&amp;ssl=1 651w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/export-binary-file-arduino-ide.png?resize=300%2C106&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 651px) 100vw, 651px\" \/><\/p>\n<p>A new file on the folder sketch should be created. Go to <strong>Sketch<\/strong> &gt; <strong>Show Sketch<\/strong> <strong>Folder<\/strong>. You should have two files in your Sketch folder: the <em>.ino<\/em> and the <em>.bin<\/em> file. You should upload the <em>.bin<\/em> file using the OTA Web Updater.<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-78232\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/bin-file-folder.jpg?resize=343%2C197&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" width=\"343\" height=\"197\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/bin-file-folder.jpg?w=343&amp;quality=100&amp;strip=all&amp;ssl=1 343w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/bin-file-folder.jpg?resize=300%2C172&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 343px) 100vw, 343px\" \/><\/p>\n<h3>Upload a new sketch over-the-air to the ESP32<\/h3>\n<p>In your browser, on the ESP32 OTA Web Updater page, click the <strong>Choose File<\/strong> button. Select the <em>.bin<\/em> file generated previously, and then click <strong>Update<\/strong>.<\/p>\n<p>After a few seconds, the code should be successfully uploaded.<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-78233\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/bin-file-uploaded.jpg?resize=702%2C244&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" width=\"702\" height=\"244\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/bin-file-uploaded.jpg?w=702&amp;quality=100&amp;strip=all&amp;ssl=1 702w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/bin-file-uploaded.jpg?resize=300%2C104&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 702px) 100vw, 702px\" \/><\/p>\n<p>The ESP32 built-in LED should be blinking.<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-78234 size-full\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/DSC01830.jpg?resize=800%2C622&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"esp32-blinking-led\" width=\"800\" height=\"622\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/DSC01830.jpg?w=800&amp;quality=100&amp;strip=all&amp;ssl=1 800w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/DSC01830.jpg?resize=300%2C233&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/DSC01830.jpg?resize=768%2C597&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/p>\n<p>Congratulations! You&#8217;ve uploaded a new code to your ESP32 over-the-air.<\/p>\n<h2>Wrapping Up<\/h2>\n<p>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.<\/p>\n<p>We hope you&#8217;ve found this article interesting. If you like ESP32 you may also like:<\/p>\n<ul>\n<li><strong><a href=\"https:\/\/randomnerdtutorials.com\/learn-esp32-with-arduino-ide\/\">Learn ESP32 with Arduino IDE Course<\/a><\/strong><\/li>\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-web-server-spiffs-spi-flash-file-system\/\">ESP32 Web Server using SPIFFS (SPI Flash File System)<\/a><\/li>\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-static-fixed-ip-address-arduino-ide\/\">ESP32 Static\/Fixed IP Address<\/a><\/li>\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-access-point-ap-web-server\/\">How to Set an ESP32 Access Point (AP) for Web Server<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Quick guide that shows how to do over-the-air (OTA) programming with the ESP32 using the OTA Web Updater in Arduino IDE.\u00a0The OTA Web Updater allows you to update\/upload new code &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32 Over-the-air (OTA) Programming &#8211; Web Updater Arduino IDE\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp32-over-the-air-ota-programming\/#more-78214\" aria-label=\"Read more about ESP32 Over-the-air (OTA) Programming &#8211; Web Updater Arduino IDE\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":78257,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[276,277,299],"tags":[],"class_list":["post-78214","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp32","category-esp32-arduino-ide","category-0-esp32"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/OTAWebUpdates_ESP32_thumbnail.jpg?fit=1280%2C720&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/78214","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=78214"}],"version-history":[{"count":0,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/78214\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/78257"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=78214"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=78214"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=78214"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}