Programación OTA en ESP32


Una de las mejores cosas de ESP32 es que su firmware se puede actualizar de forma inalámbrica. Este tipo de programación se llama «Over-The-Air» (OTA) permitiendo actualizar/cargar un nuevo programa al ESP32 a través de Wi-Fi sin tener que conectar el ESP32 a un ordenador a través de USB.

La funcionalidad OTA es útil cuando no hay acceso físico al módulo ESP pero 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.

La única desventaja es que debe incluir un código OTA con cada boceto que cargue para poder usar OTA en la próxima actualización.

Hay dos formas de implementar la funcionalidad OTA en el ESP32:

  • OTA básico : las actualizaciones se envían mediante el IDE de Arduino.
  • Web Updater OTA : las actualizaciones se entregan a través de un navegador web.

Cada uno tiene sus propios beneficios, por lo que puede usar el que funcione mejor para su proyecto.

OTA Básico

En este primer apartado veremos el proceso de implementación de OTA básico.  En resumen son 3 pasos simples para usar OTA básico con el ESP32

  1. Instalación de la serie Python 2.7.x: el primer paso es instalar la serie Python 2.7.x en su computadora.
  2. Carga de firmware OTA básico en serie: cargue el boceto que contiene el firmware OTA en serie. Este es un paso necesario para realizar las actualizaciones posteriores de forma inalámbrica.
  3. Carga de nuevos bocetos por aire: ahora puede cargar nuevos bocetos al ESP32 desde Arduino IDE por aire.

1: Instalación de Python 2.7.x

Para usar la funcionalidad OTA, primero debe instalar Python 2.7.x, si aún no está instalado en su máquina. Descargue Python 2.7.x para Windows (instalador MSI) desde el sitio web oficial de Python .

Inicie el instalador y continúe con el asistente de instalación

Asegúrese de que la opción «Agregar python.exe a la ruta» esté habilitada en la sección Personalizar Python 2.7.X.

2: Carga del firmware OTA básico en serie

Debido a que la imagen de fábrica del ESP32 carece de la capacidad de actualización OTA, primero debe cargar el firmware OTA en el ESP32 a través de la interfaz serial.

Es necesario actualizar primero el firmware para poder realizar actualizaciones inalámbricas posteriores.

El complemento ESP32 para Arduino IDE incluye una biblioteca OTA, así como un ejemplo de BasicOTA. Simplemente navegue a Archivo > Ejemplos > ArduinoOTA > BasicOTA .

Antes de comenzar a cargar el boceto, debe modificar las siguientes dos variables con sus credenciales de red para que el ESP32 pueda conectarse a una red existente.

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

Cuando haya terminado, siga adelante y cargue el boceto.

#include <WiFi.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

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

void setup() {
  Serial.begin(115200);
  Serial.println("Booting");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("Connection Failed! Rebooting...");
    delay(5000);
    ESP.restart();
  }

  // Port defaults to 3232
  // ArduinoOTA.setPort(3232);

  // Hostname defaults to esp3232-[MAC]
  // ArduinoOTA.setHostname("myesp32");

  // No authentication by default
  // ArduinoOTA.setPassword("admin");

  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
  // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");

  ArduinoOTA
    .onStart([]() {
      String type;
      if (ArduinoOTA.getCommand() == U_FLASH)
        type = "sketch";
      else // U_SPIFFS
        type = "filesystem";

      // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
      Serial.println("Start updating " + type);
    })
    .onEnd([]() {
      Serial.println("\nEnd");
    })
    .onProgress([](unsigned int progress, unsigned int total) {
      Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
    })
    .onError([](ota_error_t error) {
      Serial.printf("Error[%u]: ", error);
      if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
      else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
      else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
      else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
      else if (error == OTA_END_ERROR) Serial.println("End Failed");
    });

  ArduinoOTA.begin();

  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  ArduinoOTA.handle();
}

Ahora, abra el Serial Monitor a 115200 baudios y presione el botón EN en el ESP32. Si todo está bien, debería ver la dirección IP dinámica asignada por su enrutador. Tome nota de ello.

Paso 3: Carga del nuevo boceto por aire

Ahora, subamos un nuevo boceto por aire. Recuerde que debes incluir el código OTA en cada sketch que subas. De lo contrario, perderá la capacidad OTA y no podrá realizar la próxima carga inalámbrica. Por lo tanto, se recomienda que modifique el código anterior para incluir su nuevo código.

Como ejemplo, incluiremos un boceto Blink simple en el código OTA básico. Recuerda modificar las variables SSID y contraseña con sus credenciales de red.

Los cambios en el programa Basic OTA están resaltados con comentarios //******.

#include <WiFi.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

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


//******codigo programa*******
//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

//******fin codigo programa*******

void setup() {

//******codigo programa*******
pinMode(led, OUTPUT);
//******fin codigo programa*******
  
  Serial.begin(115200);
  Serial.println("Booting");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("Connection Failed! Rebooting...");
    delay(5000);
    ESP.restart();
  }

  // Port defaults to 3232
  // ArduinoOTA.setPort(3232);

  // Hostname defaults to esp3232-[MAC]
  // ArduinoOTA.setHostname("myesp32");

  // No authentication by default
  // ArduinoOTA.setPassword("admin");

  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
  // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");

  ArduinoOTA
    .onStart([]() {
      String type;
      if (ArduinoOTA.getCommand() == U_FLASH)
        type = "sketch";
      else // U_SPIFFS
        type = "filesystem";

      // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
      Serial.println("Start updating " + type);
    })
    .onEnd([]() {
      Serial.println("\nEnd");
    })
    .onProgress([](unsigned int progress, unsigned int total) {
      Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
    })
    .onError([](ota_error_t error) {
      Serial.printf("Error[%u]: ", error);
      if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
      else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
      else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
      else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
      else if (error == OTA_END_ERROR) Serial.println("End Failed");
    });

  ArduinoOTA.begin();

  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  ArduinoOTA.handle();  

//******codigo programa*******
//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);
 //******fin codigo programa*******
  }

}

Tenga en cuenta que no hemos utilizado la delay()función para hacer que el LED parpadee. Esto se debe a que la delay()función pausa el programa. Si se genera la siguiente solicitud OTA mientras el ESP32 está en pausa esperando a delay()que se complete, su programa perderá esa solicitud.

Después de copiar el boceto anterior en su IDE de Arduino, navegue hasta la opción Herramientas > Puerto . Busque algo como: esp32-xxxxxx en your_esp_ip_address . Si no puede localizarlo, es posible que deba reiniciar su IDE.

Elija el puerto y presione el botón Cargar. El nuevo boceto se cargará en cuestión de segundos. El LED integrado debería comenzar a parpadear.

Actualizador OTA via web

La programación OTA es útil cuando necesita actualizar el código de las placas ESP32 a las que no se puede acceder fácilmente. El ejemplo que mostraremos aquí funciona cuando el ESP32 y su navegador están en su red local.

La única desventaja de OTA Web Updater es que debe agregar el código para OTA en cada boceto que cargue, para que pueda usar OTA en el futuro.

¿Cómo funciona el Actualizador web OTA?

  • El primer boceto debe cargarse a través del puerto serie. Este boceto debe contener el código para crear el actualizador web OTA, de modo que pueda cargar el código más tarde con su navegador.
  • El boceto de OTA Web Updater crea un servidor web al que puede acceder para cargar un nuevo boceto a través del navegador web.
  • Luego, debe implementar rutinas OTA en cada boceto que cargue, de modo que pueda realizar las próximas actualizaciones/cargas por aire.
  • Si carga un código sin una rutina OTA, ya no podrá acceder al servidor web y cargar un nuevo boceto por aire.

Antes de continuar , debe tener instalado el complemento ESP32 en su IDE de Arduino. Veamos los pasos a seguir

1-Carga de OTAWebUpdater

Cuando instala el complemento ESP32 para Arduino IDE, instalará automáticamente la biblioteca ArduinoOTA. Vaya a Archivo > Ejemplos > ArduinoOTA > OTAWebUpdater .

otawebupdater-arduino-ide

Debería cargarse el siguiente código.

/*
 * 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 = 
"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);

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

Debe cambiar las siguientes líneas en el código para incluir sus propias credenciales de red:

const char* ssid = "";
const char* contraseña = "";

El ejemplo de OTAWebUpdater para ESP32 crea un servidor web asíncrono donde puede cargar código nuevo en su placa sin necesidad de una conexión en serie.Suba el código anterior a tu placa ESP32. No olvide ingresar sus credenciales de red y seleccionar la placa y el puerto serial correctos.

Después de cargar el código, abra el monitor serie a una velocidad de transmisión de 115200, presione el botón de activación de ESP32 y obtendrá la dirección IP de ESP32:

Ahora, puede cargar el código a su ESP32 por aire usando un navegador en su red local.

Para probar el Actualizador web OTA, puede desconectar el ESP32 de su computadora y encenderlo con un banco de energía, por ejemplo (esto es opcional, lo sugerimos para imitar una situación en la que el ESP32 no está conectado a su computadora).

2-Actualización del nuevo código usando el actualizador web OTA

Abra un navegador en su red e ingrese la dirección IP ESP32. Deberías obtener lo siguiente:

otawebupdater-usuario-contraseña

Introduzca el nombre de usuario y la contraseña:

  • Nombre de usuario : admin
  • contraseña : admin

Puede cambiar el nombre de usuario y la contraseña en el código.

Nota:  Después de ingresar el nombre de usuario y la contraseña, será redirigido a la URL /serverIndex . No necesita ingresar el nombre de usuario y la contraseña para acceder a la URL /serverIndex . Por lo tanto, si alguien conoce la URL para cargar el nuevo código, el nombre de usuario y la contraseña no protegen la página web para que otros no puedan acceder a ella.

Debería abrirse una nueva pestaña en la URL /serverIndex . Esta página le permite cargar un nuevo código a su ESP32. Debería cargar archivos .bin (veremos cómo hacerlo en un momento).

ota-web-updater-esp32

3-Preparación del nuevo sketch

Al cargar un nuevo boceto por aire, debe tener en cuenta que debe agregar código para OTA en su nuevo boceto, de modo que siempre pueda sobrescribir cualquier boceto con uno nuevo en el futuro. Por lo tanto, le recomendamos que modifique el boceto de OTAWebUpdater para incluir su propio código.

Con fines de aprendizaje, subamos un nuevo código que parpadee un LED (sin demora). Copie el siguiente código en su IDE de Arduino.

/*
 * 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 = 
"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) {
  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);
  }
}

Como puede ver, hemos agregado el código «parpadeo sin demora» al código OTAWebUpdater, para que podamos realizar actualizaciones más adelante.

Después de copiar el código en su IDE de Arduino, debe generar un archivo .bin .

4-Generación del archivo .bin en Arduino IDE

Guarde su boceto como LED_Web_Updater .

Para generar un archivo .bin a partir de su boceto, vaya a Boceto > Exportar binario compilado

exportar-archivo-bin-arduino-ide

Se debe crear un nuevo archivo en el boceto de la carpeta. Vaya a Bosquejo > Mostrar carpeta de bosquejo . Debe tener dos archivos en su carpeta Sketch: el archivo .ino y el archivo .bin . Debe cargar el archivo .bin mediante el actualizador web de OTA.

5-Carga del nuevo sketch por aire al ESP32

En su navegador, en la página ESP32 OTA Web Updater, haga clic en el botón Elegir archivo . Seleccione el archivo .bin generado anteriormente y luego haga clic en Actualizar .

Después de unos segundos, el código debería cargarse correctamente.

El LED incorporado ESP32 debe estar parpadeando.¡Felicidades! Ha subido un nuevo código a tu ESP32 por aire.

Las actualizaciones inalámbricas hemos visto que son útiles para cargar un nuevo código en su placa ESP32 cuando no es fácilmente accesible. En este segundo caso hemos visto el código OTA Web Updater como crea un servidor web al que puede acceder para cargar un nuevo código en su placa ESP32 utilizando un navegador web en su red local.

Fuentes

https://lastminuteengineers.com/esp32-ota-updates-arduino-ide/

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

Deja un comentario

Este sitio utiliza Akismet para reducir el spam. Conoce cómo se procesan los datos de tus comentarios.