¿Estás buscando una forma conveniente de actualizar el firmware de tu ESP32 a través de la web? ¡Entonces estás en el lugar correcto! En este artículo, aprenderás cómo utilizar el IDE de Arduino para implementar un actualizador Over The Air (OTA) para tu ESP32. ¡Sigue leyendo para descubrir cómo mantener tu dispositivo siempre actualizado de forma sencilla y eficiente!
Una de las mejores cosas del ESP32 es que su firmware se puede actualizar de forma inalámbrica. Este tipo de programación se llama “Over-The-Air” (OTA).
¿Qué es la programación OTA en ESP32?
programación OTA le permite actualizar/cargar un nuevo programa al ESP32 a través de WiFi sin tener que conectar el ESP32 a la computadora a través de USB.
La funcionalidad OTA es conveniente cuando no hay acceso físico al módulo ESP. Además, reduce el tiempo necesario para actualizar cada módulo ESP durante el mantenimiento.
Una ventaja clave de OTA es que una única ubicación central puede enviar una actualización a varios ESP en la misma red.
El único inconveniente es que debes proporcionar un código OTA con cada boceto cargado para poder utilizar OTA en la próxima actualización.
Formas de implementar OTA en ESP32
Hay dos formas de implementar la funcionalidad OTA en ESP32.
- OTA básica – Las actualizaciones se proporcionan a través del IDE de Arduino.
- Actualizador web OTA – Las actualizaciones se entregan a través de un navegador web.
Cada uno tiene sus propias ventajas, por lo que puedes utilizar el que mejor se adapte a tu proyecto.
Este tutorial lo guiará a través del proceso de implementación de Web Updater OTA. Si desea obtener más información sobre OTA básica, visite el tutorial a continuación.
3 sencillos pasos para usar Web Updater OTA con el ESP32
- Sube la rutina OTA en serie: El primer paso es cargar en serie el boceto utilizando el firmware OTA. Este es un paso necesario para realizar actualizaciones posteriores de forma inalámbrica.
- Acceso al servidor web: El boceto OTA crea un servidor web en modo STA al que se puede acceder a través de un navegador web. Una vez que haya iniciado sesión en el servidor web, podrá cargar nuevos bocetos.
- Cargue un nuevo boceto de forma inalámbrica: Ahora puede cargar nuevos bocetos al ESP32 generando y cargando un archivo .bin compilado a través de un servidor web.
Paso 1: Cargue la rutina OTA en serie
Dado que la imagen de fábrica del ESP32 no tiene capacidad de actualización OTA, primero debe cargar el firmware OTA en el ESP32 a través del puerto serie.
Para poder realizar actualizaciones inalámbricas posteriores, primero se debe actualizar el firmware.
El complemento ESP32 para Arduino IDE incluye una biblioteca OTA y un ejemplo de OTAWebUpdater. Simplemente navega hasta archivo > Ejemplos > ArduinoOTA > Actualizador Web OTA.
La interfaz de usuario de OTA Web Updater es extremadamente poco atractiva. Entonces optimizamos el código para que se vea mejor. Primero, conecte su ESP32 a su computadora y cargue el siguiente boceto.
Antes de comenzar a cargar el boceto, debe cambiar las dos variables siguientes con sus credenciales de red para permitir que el ESP32 se conecte a una red existente.
const char* ssid = "---";
const char* password = "----";
Cuando hayas terminado, sube el boceto.
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>
const char* host = "esp32";
const char* ssid = "---";
const char* password = "----";
WebServer server(80);
/* Style */
String style =
"<style>#file-input,input{width:100%;height:44px;border-radius:4px;margin:10px auto;font-size:15px}"
"input{background:#f1f1f1;border:0;padding:0 15px}body{background:#3498db;font-family:sans-serif;font-size:14px;color:#777}"
"#file-input{padding:0;border:1px solid #ddd;line-height:44px;text-align:left;display:block;cursor:pointer}"
"#bar,#prgbar{background-color:#f1f1f1;border-radius:10px}#bar{background-color:#3498db;width:0%;height:10px}"
"form{background:#fff;max-width:258px;margin:75px auto;padding:30px;border-radius:5px;text-align:center}"
".btn{background:#3498db;color:#fff;cursor:pointer}</style>";
/* Login page */
String loginIndex =
"<form name=loginForm>"
"<h1>ESP32 Login</h1>"
"<input name=userid placeholder='User ID'> "
"<input name=pwd placeholder=Password type=Password> "
"<input type=submit onclick=check(this.form) class=btn value=Login></form>"
"<script>"
"function check(form) {"
"if(form.userid.value=='admin' && form.pwd.value=='admin')"
"{window.open('/serverIndex')}"
"else"
"{alert('Error Password or Username')}"
"}"
"</script>" + style;
/* Server Index Page */
String 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' id='file' onchange='sub(this)' style=display:none>"
"<label id='file-input' for='file'> Choose file...</label>"
"<input type='submit' class=btn value='Update'>"
"<br><br>"
"<div id='prg'></div>"
"<br><div id='prgbar'><div id='bar'></div></div><br></form>"
"<script>"
"function sub(obj){"
"var fileName = obj.value.split('\\');"
"document.getElementById('file-input').innerHTML = ' '+ fileName[fileName.length-1];"
"};"
"$('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) + '%');"
"$('#bar').css('width',Math.round(per*100) + '%');"
"}"
"}, false);"
"return xhr;"
"},"
"success:function(d, s) {"
"console.log('success!') "
"},"
"error: function (a, b, c) {"
"}"
"});"
"});"
"</script>" + style;
/* 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: %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);
}
Paso 2: Accede al servidor web
El boceto OTA Web Updater crea un servidor web en modo STA al que se puede acceder a través de un navegador web y se puede usar para cargar nuevos bocetos a su ESP32 de forma inalámbrica.
Para acceder al servidor web, abra el Monitor serie a 115200 baudios y presione la tecla EN en el ESP32. Si todo está bien, verá la dirección IP dinámica obtenida de su enrutador.
A continuación, inicie un navegador y navegue hasta la dirección IP que se muestra en el monitor serie. El ESP32 debería mostrar una página web solicitando información de inicio de sesión.
Ingrese el siguiente ID de usuario y contraseña:
User ID: admin
Password: admin
Si desea cambiar el ID de usuario y la contraseña, edite el siguiente código en su boceto.
"if(form.userid.value=='admin' && form.pwd.value=='admin')"
Después de iniciar sesión serás redirigido al /serverIndex
Página. Esta página le permite cargar de forma inalámbrica nuevos bocetos a su ESP32.
Tenga en cuenta que el nuevo boceto que desea cargar debe estar en el .bin
(binario compilado). En el siguiente paso, aprenderá cómo generar el archivo .bin de su boceto.
Advertencia:
La página /serverIndex no está protegida por la función de inicio de sesión. Este error podría permitir a los usuarios acceder al sistema sin iniciar sesión.
Paso 3: sube un nuevo boceto de forma inalámbrica
Ahora carguemos un nuevo boceto de forma inalámbrica.
Recuerda que debes incluir el código OTA en cada sketch subido. De lo contrario, perderá la capacidad OTA y no podrá realizar la siguiente carga inalámbrica. Por lo tanto, se recomienda modificar el código anterior para incluir el nuevo código.
Como ejemplo, agregaremos un boceto simple de Blink en el código del actualizador web OTA. Recuerde cambiar las variables SSID y contraseña con sus credenciales de red.
Los cambios en el programa Web Updater OTA están resaltados en azul.
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>
const char* host = "esp32";
const char* ssid = "---";
const char* password = "----";
//variabls for blinking an LED with Millis
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);
/* Style */
String style =
"<style>#file-input,input{width:100%;height:44px;border-radius:4px;margin:10px auto;font-size:15px}"
"input{background:#f1f1f1;border:0;padding:0 15px}body{background:#3498db;font-family:sans-serif;font-size:14px;color:#777}"
"#file-input{padding:0;border:1px solid #ddd;line-height:44px;text-align:left;display:block;cursor:pointer}"
"#bar,#prgbar{background-color:#f1f1f1;border-radius:10px}#bar{background-color:#3498db;width:0%;height:10px}"
"form{background:#fff;max-width:258px;margin:75px auto;padding:30px;border-radius:5px;text-align:center}"
".btn{background:#3498db;color:#fff;cursor:pointer}</style>";
/* Login page */
String loginIndex =
"<form name=loginForm>"
"<h1>ESP32 Login</h1>"
"<input name=userid placeholder='User ID'> "
"<input name=pwd placeholder=Password type=Password> "
"<input type=submit onclick=check(this.form) class=btn value=Login></form>"
"<script>"
"function check(form) {"
"if(form.userid.value=='admin' && form.pwd.value=='admin')"
"{window.open('/serverIndex')}"
"else"
"{alert('Error Password or Username')}"
"}"
"</script>" + style;
/* Server Index Page */
String 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' id='file' onchange='sub(this)' style=display:none>"
"<label id='file-input' for='file'> Choose file...</label>"
"<input type='submit' class=btn value='Update'>"
"<br><br>"
"<div id='prg'></div>"
"<br><div id='prgbar'><div id='bar'></div></div><br></form>"
"<script>"
"function sub(obj){"
"var fileName = obj.value.split('\\');"
"document.getElementById('file-input').innerHTML = ' '+ fileName[fileName.length-1];"
"};"
"$('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) + '%');"
"$('#bar').css('width',Math.round(per*100) + '%');"
"}"
"}, false);"
"return xhr;"
"},"
"success:function(d, s) {"
"console.log('success!') "
"},"
"error: function (a, b, c) {"
"}"
"});"
"});"
"</script>" + style;
/* 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: %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);
//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);
}
}
Tenga en cuenta que no usamos eso delay()
Función para hacer que el LED parpadee. Esto se debe a que el delay()
La función pausa el programa. Cuando se genera la siguiente solicitud OTA mientras el ESP32 está en pausa y esperando la delay()
Para completar el proceso, su programa no cumplirá con este requisito.
Generar un archivo .bin en el IDE de Arduino
Para cargar un nuevo boceto al ESP32, primero debe generar un archivo binario compilado .bin
Archivo de tu boceto.
Para hacer esto, navegue hasta Bosquejo > Exportar binario compilado.
Después de compilar exitosamente el boceto, el .bin
El archivo se genera en la carpeta de bocetos. Para abrir la carpeta Sketch, seleccione Bosquejo > Mostrar carpeta de bocetos.
Sube nuevos bocetos de forma inalámbrica al ESP32
Después de generar el .bin
archivo, el nuevo boceto se puede cargar de forma inalámbrica al ESP32.
Inicie su navegador y navegue hasta /serverIndex
Página. Haga clic en Seleccionar archivo… Seleccione el archivo recién generado .bin
Archivo y haga clic en Actualizar.
El nuevo boceto se cargará en unos segundos.
Y el LED integrado debería empezar a parpadear.
Programación ESP32 Web Updater Over The Air (OTA) en el IDE de Arduino
Una de las mejores características del ESP32 es que su firmware se puede actualizar de forma inalámbrica. Este tipo de programación se llama «Over-The-Air» (OTA).
¿Qué es la programación OTA en ESP32?
La programación OTA te permite actualizar/subir un nuevo programa al ESP32 a través de Wi-Fi sin tener que conectar el ESP32 a la computadora mediante USB. La funcionalidad OTA resulta útil cuando no se tiene acceso físico al módulo ESP. Además, reduce el tiempo requerido para actualizar cada módulo ESP durante el mantenimiento. Una ventaja clave de OTA es que una única ubicación central puede enviar una actualización a varios ESP en la misma red. La única desventaja es que debes incluir un código OTA con cada sketch que cargas para poder utilizar OTA en la próxima actualización.
Formas de Implementar OTA en ESP32
Hay dos formas de implementar la funcionalidad OTA en el ESP32:
- OTA básica: las actualizaciones se entregan utilizando el IDE de Arduino.
- Web Updater OTA: las actualizaciones se entregan a través de un navegador web.
Cada una tiene sus propios beneficios, por lo que puedes utilizar la que mejor funcione para tu proyecto.
3 Pasos Simples para Usar Web Updater OTA con el ESP32
- Subir OTA Rutina en Serie: El primer paso es cargar en serie el sketch que contiene el firmware OTA. Este es un paso necesario para realizar las actualizaciones posteriores de manera inalámbrica.
- Acceder al Servidor Web: El sketch OTA Web Updater crea un servidor web en modo STA al que se puede acceder a través de un navegador web. Una vez que te hayas conectado al servidor web, puedes cargar nuevos sketches.
- Cargar un Nuevo Sketch Over-The-Air: Ahora puedes cargar nuevos sketches en el ESP32 generando y subiendo un archivo .bin compilado a través de un servidor web.
Paso 1: Subir OTA Rutina en Serie
Debido a que la imagen de fábrica de ESP32 carece de la capacidad de actualización OTA, primero debes cargar el firmware OTA en el ESP32 a través de la interfaz serie. Para comenzar, conecta tu ESP32 a tu computadora y carga el sketch que se proporciona anteriormente.
Para continuar leyendo acerca de la implementación de Web Updater OTA en el ESP32, visita la fuente original.
¡Excelente tutorial! Muy útil para actualizar de forma remota mis proyectos en ESP32. ¡Gracias por compartir!
Se ve genial, ¡necesito probar esto en mis proyectos de ESP32! ¡Gracias por la información! 👍😊
Muy interesante, definitivamente ahorra mucho tiempo y esfuerzo. ¡Gracias por la guía! 😊👍