ESP32 OTA: cómo subir código por Wi-Fi sin cable (ArduinoOTA)
ESP32 OTA: sube código por Wi-Fi sin cable USB. Puerto de red de ArduinoOTA, página web de ElegantOTA, contraseña, esquema de particiones y cortes de conexión.
ESP32 OTA (Over-The-Air, actualización "por el aire") consiste en cargar código nuevo en tu placa a través de Wi-Fi, sin conectar un cable USB. Piensa en un sensor montado en el techo, un controlador de riego en el jardín o una placa de relés dentro de un cuadro eléctrico: en lugar de sacar la escalera, desmontar la placa y conectarla al ordenador para cada pequeño arreglo, envías la nueva versión desde el Arduino IDE o desde el navegador en unos segundos. La placa escribe el nuevo programa en su memoria en segundo plano, lo verifica y se reinicia sola.
En esta guía aprenderás paso a paso cómo funciona el OTA dentro del ESP32, tres métodos distintos (ArduinoOTA para el Arduino IDE, ElegantOTA para el navegador y HTTPUpdate para descargar desde un servidor), cómo elegir el esquema de particiones correcto, cómo proteger la carga con contraseña, qué pasa si la subida se interrumpe y cómo no perder el OTA en tu próximo sketch. Todo el código se ha compilado y probado con el núcleo Arduino del ESP32.

¿Qué es el OTA del ESP32 y cómo funciona?
La memoria flash del ESP32 no es un bloque único; se divide en partes con un mapa llamado tabla de particiones. Una tabla compatible con OTA tiene dos zonas iguales para el programa: app0 (ota_0) y app1 (ota_1). Mientras la placa funciona desde una de ellas, el nuevo programa se escribe en la otra. Una pequeña partición otadata guarda qué zona se ejecutará en el siguiente arranque. Así, el programa en marcha nunca se toca durante la carga, y la placa no abandona el programa antiguo hasta que el nuevo código está escrito y verificado por completo.
- El nuevo programa (el archivo .bin compilado) llega a la placa por Wi-Fi, trozo a trozo.
- El ESP32 escribe cada trozo en la partición de programa que no está en uso; mientras tanto, el código actual sigue con su trabajo.
- Cuando llega el archivo completo, se comprueban la cabecera de la imagen y su suma de verificación; un archivo dañado o incompleto se rechaza.
- Si la verificación es correcta, se actualiza otadata: en el siguiente arranque se ejecutará la nueva partición.
- La placa se reinicia y arranca con el nuevo programa. La siguiente actualización irá a la otra partición; las dos zonas se usan por turnos.
| Método | ¿Desde dónde envías el código? | Ideal para | Librería extra |
|---|---|---|---|
| ArduinoOTA | Desde el puerto de red del Arduino IDE | Desarrollar en tu mesa, en la misma red | Ninguna (viene con el núcleo) |
| ElegantOTA | Eligiendo un .bin en la página /update del navegador | Que alguien sin IDE actualice, subir desde el móvil | ElegantOTA |
| HTTPUpdate | La placa descarga ella misma un .bin desde un servidor | Muchos dispositivos, equipos remotos, actualizaciones automáticas | Ninguna (viene con el núcleo) |
Esquema de particiones (partition scheme) y tamaño de la flash
Este es el requisito del OTA que más se pasa por alto: debe existir una segunda zona libre donde escribir el nuevo programa. Por eso, el programa más grande que puedes subir por OTA es menor que la mitad de la flash. La tabla de particiones se elige en el Arduino IDE en Herramientas > Partition Scheme. En las placas ESP32 DevKit habituales con 4 MB de flash (ESP32 Dev Module), las opciones son:
| Partition Scheme | Zona de programa | OTA | Sistema de archivos (SPIFFS/LittleFS) |
|---|---|---|---|
| Default 4MB with spiffs | 2 × 1,25 MB (1.310.720 bytes) | Sí | 1,375 MB |
| Minimal SPIFFS (1.9MB APP with OTA) | 2 × 1,875 MB (1.966.080 bytes) | Sí | 128 KB |
| No OTA (2MB APP/2MB SPIFFS) | 1 × 2 MB | No | 1,875 MB |
| Huge APP (3MB No OTA/1MB SPIFFS) | 1 × 3 MB | No | 896 KB |
| Minimal (1.3MB APP/700KB SPIFFS) | 1 × 1,25 MB (para placas con 2 MB de flash) | No | 640 KB |
Cuánto ocupa tu programa lo ves en la salida de compilación: nuestro primer ejemplo con Wi-Fi y ArduinoOTA muestra "Sketch uses 758685 bytes (57%) ... Maximum is 1310720 bytes". Ese máximo es el tamaño de una sola zona de programa del esquema elegido. Si el uso pasa del 90 %, pronto tendrás que pasar a Minimal SPIFFS. Otra regla importante: la tabla de particiones no se puede cambiar por OTA. Si cambiaste el esquema, esa carga debe hacerse por USB; las siguientes actualizaciones OTA funcionarán con la nueva tabla. En placas con 8 MB o 16 MB de flash (como muchos modelos ESP32-S3), elegir el tamaño correcto en el menú Flash Size te da zonas OTA mucho más grandes.
Si quieres ver desde qué partición está funcionando realmente tu placa y cuánto espacio queda para el OTA, sube este pequeño sketch. No necesita ninguna librería y usa directamente las funciones OTA de ESP-IDF:
1#include <esp_ota_ops.h>
2
3void setup() {
4 Serial.begin(115200);
5 delay(1000);
6 const esp_partition_t* running = esp_ota_get_running_partition();
7 const esp_partition_t* next = esp_ota_get_next_update_partition(NULL);
8
9 Serial.printf("Flash boyutu / Flash size: %u KB\n", ESP.getFlashChipSize() / 1024);
10 Serial.printf("Program boyutu / Sketch size: %u KB\n", ESP.getSketchSize() / 1024);
11 Serial.printf("OTA icin bos alan / Free space for OTA: %u KB\n", ESP.getFreeSketchSpace() / 1024);
12 Serial.printf("Calisan bolum / Running partition: %s (0x%06x)\n", running->label, running->address);
13 if (next != NULL) {
14 Serial.printf("Siradaki OTA bolumu / Next OTA partition: %s (0x%06x)\n", next->label, next->address);
15 } else {
16 Serial.println("OTA bolumu yok: bolum tablosunu degistir / No OTA partition: change the partition scheme");
17 }
18}
19
20void loop() {
21}Con el esquema por defecto, tras la primera carga por USB la salida muestra "Running partition: app0 (0x010000)" y "Next OTA partition: app1 (0x150000)". Si vuelves a ejecutarlo después de una actualización OTA, verás que ahora funciona desde app1. El valor de ESP.getFreeSketchSpace() es el tamaño del programa más grande que puedes subir por OTA; si tu nuevo .bin es mayor, la actualización no empieza.
Método 1: carga inalámbrica desde el Arduino IDE con ArduinoOTA
La librería ArduinoOTA viene con el núcleo del ESP32, así que no hay que instalar nada. Cuando la placa se conecta a la red, se anuncia por mDNS; el Arduino IDE lo detecta y añade un puerto de red al menú Puerto. Al pulsar Subir, el IDE envía el programa por ese puerto de red en lugar del USB. En el ESP32 el servicio OTA escucha por defecto en el puerto 3232. El siguiente sketch se conecta al Wi-Fi, inicia el OTA con contraseña y hace parpadear el LED integrado como prueba:
1#include <WiFi.h>
2#include <ArduinoOTA.h>
3
4const char* WIFI_SSID = "AgAdi"; // Wi-Fi adın / your Wi-Fi name
5const char* WIFI_PASS = "AgSifresi"; // Wi-Fi şifren / your Wi-Fi password
6const int LED_PIN = 2; // çoğu DevKit'te dahili LED / onboard LED on most DevKits
7
8unsigned long lastBlink = 0;
9
10void setup() {
11 Serial.begin(115200);
12 pinMode(LED_PIN, OUTPUT);
13
14 WiFi.mode(WIFI_STA);
15 WiFi.begin(WIFI_SSID, WIFI_PASS);
16 while (WiFi.status() != WL_CONNECTED) { // bağlanana kadar bekle / wait until connected
17 delay(500);
18 Serial.print(".");
19 }
20 Serial.println();
21 Serial.print("IP: ");
22 Serial.println(WiFi.localIP());
23
24 ArduinoOTA.setHostname("bluegrays-esp32"); // IDE'de görünen ad / name shown in the IDE
25 ArduinoOTA.setPassword("ota1234"); // yükleme parolası / upload password
26
27 ArduinoOTA.onStart([]() {
28 // Güncelleme başlıyor: motorları, röleleri güvenli konuma al / update starting: put motors and relays in a safe state
29 String type = (ArduinoOTA.getCommand() == U_FLASH) ? "program" : "dosya sistemi / filesystem";
30 Serial.println("OTA basladi / started: " + type);
31 });
32 ArduinoOTA.onEnd([]() {
33 Serial.println("\nOTA bitti, yeniden baslatiliyor / done, rebooting");
34 });
35 ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
36 Serial.printf("Ilerleme / Progress: %u%%\r", progress * 100 / total);
37 });
38 ArduinoOTA.onError([](ota_error_t error) {
39 Serial.printf("Hata / Error[%u]: ", error);
40 if (error == OTA_AUTH_ERROR) Serial.println("parola / auth failed");
41 else if (error == OTA_BEGIN_ERROR) Serial.println("baslatilamadi, yer yok / begin failed, no space");
42 else if (error == OTA_CONNECT_ERROR) Serial.println("baglanti / connect failed");
43 else if (error == OTA_RECEIVE_ERROR) Serial.println("veri alinamadi / receive failed");
44 else if (error == OTA_END_ERROR) Serial.println("bitirilemedi / end failed");
45 });
46
47 ArduinoOTA.begin(); // OTA hizmetini başlat / start the OTA service
48}
49
50void loop() {
51 ArduinoOTA.handle(); // her turda çağır, unutma / call on every pass, never forget
52
53 // delay() yerine millis(): OTA isteklerini kaçırmamak için / millis() instead of delay() so OTA requests aren't missed
54 if (millis() - lastBlink >= 500) {
55 lastBlink = millis();
56 digitalWrite(LED_PIN, !digitalRead(LED_PIN));
57 }
58}| Línea | ¿Para qué sirve? |
|---|---|
| ArduinoOTA.setHostname("bluegrays-esp32") | El nombre que aparece en la lista de puertos del IDE y en la red. Si tienes varias placas, dale a cada una un nombre distinto. |
| ArduinoOTA.setPassword("ota1234") | Sin contraseña, cualquiera en tu red puede cargar código en tu placa. El IDE pide esta contraseña antes de subir. |
| onStart / onEnd | Se ejecutan al empezar y al terminar la actualización. El lugar ideal para parar motores, apagar relés o mostrar "Actualizando" en una pantalla. |
| onProgress | Da el porcentaje; puedes dibujar una barra de progreso en una LCD u OLED. |
| onError | Indica el tipo de error: contraseña, falta de espacio, conexión, recepción o finalización. |
| ArduinoOTA.handle() | Comprueba si llegan peticiones OTA. Si no se llama a menudo dentro de loop(), la placa no puede responder al IDE. |
Paso a paso: tu primera carga OTA
- Cambia los valores WIFI_SSID y WIFI_PASS del código por los de tu red. El ESP32 solo se conecta a redes de 2,4 GHz.
- En el menú Herramientas elige tu placa (p. ej. ESP32 Dev Module) y un Partition Scheme con OTA (Default o Minimal SPIFFS).
- Haz la primera carga con el cable USB. Es obligatorio porque la placa todavía no tiene código OTA.
- Abre el Monitor Serie a 115200 baudios y apunta la dirección IP que muestra la placa.
- Desconecta el cable USB y, si quieres, alimenta la placa con otra fuente. En 10–20 segundos aparecerá en Herramientas > Puerto, bajo puertos de red, una línea como "bluegrays-esp32 at 192.168.1.x"; selecciónala.
- Cambia la velocidad del LED en el código de 500 a 100 y pulsa Subir. Cuando el IDE pida la contraseña, escribe "ota1234".
- En la ventana de salida verás el porcentaje de avance y al final una línea como "Done" o "Result: OK". La placa se reinicia y el LED parpadea ahora rápido.
Hay una limitación que debes conocer: el puerto de red sirve solo para subir código y el Monitor Serie no funciona de forma inalámbrica. Para ver los mensajes de la placa, vuelve a conectar el USB o muestra el estado en una página web, en una pantalla o con mensajes MQTT. Mientras desarrollas en tu mesa también puedes dejar la placa conectada por USB y subir igualmente por la red; así tienes cargas rápidas y el Monitor Serie a la vez.
Protección con contraseña y seguridad
Una placa con el servicio OTA abierto es una puerta por la que cualquiera en tu red puede cargar código. En ArduinoOTA, setPassword() guarda la contraseña en texto plano dentro del código; si vas a compartir el código, puedes pasar el hash MD5 de la contraseña con setPasswordHash() para que la contraseña no aparezca en el código fuente. ElegantOTA protege la página /update con usuario y contraseña (HTTP Basic Auth).
- Da a cada dispositivo una contraseña distinta y difícil de adivinar: valores como "1234" o "admin" son lo primero que se prueba.
- No expongas la placa a internet: abrir el OTA o la página /update al exterior con redirección de puertos en el router es un riesgo serio; estos métodos funcionan sobre HTTP sin cifrar.
- Usa HTTPUpdate para equipos remotos: como es la placa la que pide la actualización, basta con una conexión saliente; si descargas por internet, usa HTTPS con WiFiClientSecure.
- Pasa a un estado seguro durante la actualización: dentro de onStart para los motores y apaga los relés de calefactores y bombas. El reinicio tarda unos segundos y durante ese tiempo los pines pueden quedar indefinidos.
Método 2: subir un .bin desde el navegador con ElegantOTA
ElegantOTA añade una página /update muy cuidada al servidor web que corre en el ESP32. Abres esa página desde el móvil o desde cualquier ordenador sin Arduino IDE, eliges el archivo .bin compilado y lo subes; la barra de progreso aparece en el navegador. Es el método más práctico cuando entregas el dispositivo a otra persona o lo actualizas en el lugar de instalación.
- En el Arduino IDE abre el Gestor de Librerías, busca ElegantOTA (Ayush Sharma) e instálala.
- Edita el código de abajo y súbelo la primera vez por USB.
- Abre en el navegador la dirección que muestra el Monitor Serie (p. ej. http://192.168.1.42/update) e inicia sesión con el usuario "admin" y la contraseña "ota1234".
- Deja seleccionado el modo Firmware y arrastra el archivo .bin; al terminar la carga, la placa se reinicia sola.
1#include <WiFi.h>
2#include <WebServer.h>
3#include <ElegantOTA.h>
4
5const char* WIFI_SSID = "AgAdi"; // Wi-Fi adın / your Wi-Fi name
6const char* WIFI_PASS = "AgSifresi"; // Wi-Fi şifren / your Wi-Fi password
7
8WebServer server(80);
9unsigned long otaProgressMillis = 0;
10
11void onOTAStart() {
12 Serial.println("OTA basladi / OTA started"); // röleleri kapat / switch relays off
13}
14
15void onOTAProgress(size_t current, size_t final) {
16 if (millis() - otaProgressMillis > 1000) { // saniyede bir yaz / print once per second
17 otaProgressMillis = millis();
18 Serial.printf("%u / %u bayt / bytes\n", current, final);
19 }
20}
21
22void onOTAEnd(bool success) {
23 Serial.println(success ? "OTA basarili / OTA successful" : "OTA hatasi / OTA failed");
24}
25
26void setup() {
27 Serial.begin(115200);
28 WiFi.mode(WIFI_STA);
29 WiFi.begin(WIFI_SSID, WIFI_PASS);
30 while (WiFi.status() != WL_CONNECTED) {
31 delay(500);
32 Serial.print(".");
33 }
34 Serial.println();
35 Serial.print("Adres / Address: http://");
36 Serial.print(WiFi.localIP());
37 Serial.println("/update");
38
39 server.on("/", []() {
40 server.send(200, "text/plain", "BlueGrays ESP32 - surum / version 1.0");
41 });
42
43 ElegantOTA.begin(&server, "admin", "ota1234"); // /update sayfası + kullanıcı/parola / /update page + user/password
44 ElegantOTA.onStart(onOTAStart);
45 ElegantOTA.onProgress(onOTAProgress);
46 ElegantOTA.onEnd(onOTAEnd);
47
48 server.begin();
49}
50
51void loop() {
52 server.handleClient(); // web isteklerini işle / handle web requests
53 ElegantOTA.loop(); // başarılı yüklemeden sonra yeniden başlatır / reboots after a successful upload
54}Por defecto ElegantOTA trabaja con la clase síncrona WebServer que viene con el núcleo, por eso las llamadas server.handleClient() y ElegantOTA.loop() dentro de loop() son obligatorias. Si tu proyecto ya usa ESPAsyncWebServer, puedes poner a 1 la opción ELEGANTOTA_USE_ASYNC_WEBSERVER de la librería y usarla con el servidor asíncrono; explicamos cómo montar el servidor asíncrono en el artículo Servidor web asíncrono y WebSocket con ESP32. El modo Filesystem de la página actualiza la imagen de LittleFS o SPIFFS (archivos de la web, archivos de configuración) en lugar del programa.
Cómo obtener el archivo .bin: exportar el binario compilado
Para ElegantOTA y HTTPUpdate necesitas el archivo del programa compilado. En el Arduino IDE ejecuta Programa > Exportar binarios compilados (Sketch > Export Compiled Binary). El IDE compila el programa y deja varios archivos en una carpeta build dentro de la carpeta del sketch. Solo uno de ellos sirve para OTA:
| Archivo | Contenido | ¿Se usa en OTA? |
|---|---|---|
| miproyecto.ino.bin | Solo la aplicación (tu programa) | Sí, este es el archivo que debes subir |
| miproyecto.ino.bootloader.bin | Bootloader (cargador de arranque) | No |
| miproyecto.ino.partitions.bin | Tabla de particiones | No |
| miproyecto.ino.merged.bin (núcleo 3.x) | Bootloader, tabla y programa juntos | No, solo se graba por USB en la dirección 0x0 |
Método 3: actualizaciones automáticas desde un servidor con HTTPUpdate
Imagina que tienes cinco placas de sensores repartidas por la casa. En lugar de cargar cada una desde el IDE, pones el nuevo .bin en un servidor y las placas lo descargan ellas mismas. La librería HTTPUpdate, incluida en el núcleo del ESP32, lo hace con una sola línea. En el ejemplo de abajo, la actualización empieza al pulsar el botón BOOT (GPIO 0) de la placa:
1#include <WiFi.h>
2#include <HTTPUpdate.h>
3
4const char* WIFI_SSID = "AgAdi";
5const char* WIFI_PASS = "AgSifresi";
6// Bilgisayarındaki ya da sunucundaki .bin dosyası / the .bin file on your computer or server
7const char* FIRMWARE_URL = "http://192.168.1.50:8000/firmware.bin";
8const int BUTTON_PIN = 0; // karttaki BOOT butonu / the BOOT button on the board
9
10void setup() {
11 Serial.begin(115200);
12 pinMode(BUTTON_PIN, INPUT_PULLUP);
13 WiFi.begin(WIFI_SSID, WIFI_PASS);
14 while (WiFi.status() != WL_CONNECTED) delay(500);
15 Serial.println("Hazir: guncellemek icin BOOT'a bas / Ready: press BOOT to update");
16}
17
18void loop() {
19 if (digitalRead(BUTTON_PIN) == LOW) { // butona basıldı / button pressed
20 WiFiClient client;
21 httpUpdate.rebootOnUpdate(true); // başarılıysa yeniden başlat / reboot on success
22 t_httpUpdate_return ret = httpUpdate.update(client, FIRMWARE_URL);
23
24 switch (ret) {
25 case HTTP_UPDATE_FAILED:
26 Serial.printf("Hata / Error (%d): %s\n", httpUpdate.getLastError(),
27 httpUpdate.getLastErrorString().c_str());
28 break;
29 case HTTP_UPDATE_NO_UPDATES:
30 Serial.println("Guncelleme yok / No update");
31 break;
32 case HTTP_UPDATE_OK:
33 Serial.println("Tamam / OK"); // buraya genelde gelinmez, kart yeniden başlar / usually not reached, the board reboots
34 break;
35 }
36 delay(1000);
37 }
38}Para probarlo, guarda el .bin en una carpeta de tu ordenador con el nombre firmware.bin y ejecuta python3 -m http.server 8000 en esa carpeta; cambia la IP del código por la IP local de tu ordenador. En un uso real sustituyes el botón por un temporizador: por ejemplo, cada hora la placa lee un pequeño archivo "version.txt" y, si el número de versión del servidor es mayor que el suyo, inicia la actualización. Así tampoco entra en un bucle de descargar el mismo archivo y reiniciarse una y otra vez.
¿Qué pasa si se corta la conexión durante el OTA?
Respuesta corta: tu placa no se estropea. Como el nuevo programa se escribe en la partición que no se usa y la partición de arranque solo se cambia cuando todo el archivo está verificado, si la carga se interrumpe la placa sigue funcionando con el programa antiguo. Verás "Error Uploading" en el IDE, OTA_RECEIVE_ERROR en ArduinoOTA o un resultado fallido en ElegantOTA; soluciona el problema y repite la carga. Si se va la luz a mitad de la carga ocurre lo mismo: la placa arranca con el programa antiguo. El único riesgo real es que el nuevo programa sea defectuoso: si subes un programa que no se conecta al Wi-Fi o que no incluye el código OTA, necesitarás el cable para la próxima actualización.
- Señal Wi-Fi débil: si la carga se queda parada hacia el 30–60 %, acerca la placa al router o usa un módulo con antena externa. Si WiFi.RSSI() en el Monitor Serie es peor que -75 dBm, habrá cortes; tienes más detalles en El ESP32 no se conecta al Wi-Fi.
- Alimentación insuficiente: escribir en la flash y transmitir por Wi-Fi consumen corriente a la vez. Un puerto USB débil o un cable fino pueden reiniciar la placa durante la carga; se ve como un error de brownout. Usa una fuente de 5 V sólida que dé al menos 500 mA.
- Esperas largas en loop(): pausas como delay(5000) retrasan la llamada a handle() y el IDE muestra "No response from the ESP". Haz la temporización con millis().
- Cortafuegos: con ArduinoOTA, al empezar la carga el ESP32 se conecta de vuelta a tu ordenador. Si el Firewall de Windows o un antivirus bloquea esa conexión entrante, la carga falla al instante; en la ventana de permisos que aparece la primera vez, permite el acceso en redes privadas.
Mantener el OTA en cada sketch nuevo
La decepción más habitual con el OTA es esta: subes por OTA un proyecto totalmente distinto, ese proyecto no tiene código ArduinoOTA y la placa ya no aparece como puerto de red. El programa nuevo sustituye por completo al anterior; el OTA no es algo que "se queda en la placa", cada programa tiene que llevarlo consigo. Para no volver a subir la escalera hasta el equipo del techo, convierte estas reglas en costumbre:
- Usa una plantilla: pon la conexión Wi-Fi y la configuración de ArduinoOTA en una función aparte (p. ej. setupOTA()) y empieza cada proyecto nuevo con ese archivo.
- Pon la llamada a handle() al principio de loop() y nunca dejes dentro de loop() un bucle que bloquee durante mucho tiempo.
- Reconecta si se cae el Wi-Fi: usa WiFi.setAutoReconnect(true) o comprueba la conexión con regularidad; una placa sin conexión no puede recibir actualizaciones.
- Añade una ventana de mantenimiento a los proyectos con deep sleep: una placa dormida no oye la petición OTA. Escribe un modo que espere 60 segundos al OTA antes de dormir si al arrancar hay un botón pulsado o ha llegado un indicador por MQTT. Sobre los modos de sueño, mira el artículo ESP32 Deep Sleep.
- Prueba antes en una segunda placa en tu mesa: antes de enviarlo al equipo instalado, ejecuta el mismo código en una placa a tu lado; si se conecta al Wi-Fi y aparece como puerto de red, es seguro enviarlo.
- Muestra un número de versión: guarda una constante FW_VERSION al principio del código y muéstrala en la página web o en la pantalla; siempre sabrás qué versión corre en cada placa.
OTA en ESP8266 y Raspberry Pi Pico W
El código de ArduinoOTA y ElegantOTA de esta guía también funciona con pequeños cambios en placas ESP8266 (NodeMCU, Wemos D1 Mini): se usa ESP8266WiFi.h en lugar de WiFi.h, ESP8266WebServer en lugar de WebServer, y el puerto OTA es el 8266. En placas ESP8266 con 4 MB de flash debes elegir en el menú Flash Size una opción que deje suficiente espacio de programa para el OTA. En la Raspberry Pi Pico W, el núcleo arduino-pico ofrece soporte para ArduinoOTA; allí el nuevo programa se descarga primero en el sistema de archivos LittleFS y se copia a su sitio al arrancar. Por eso, en la Pico W tienes que reservar en el menú Flash Size un sistema de archivos mayor que tu programa. MicroPython no trae una herramienta OTA lista; se pueden escribir pequeños scripts que descarguen y sustituyan archivos .py por la red, pero eso no es una actualización verificada de dos particiones como en el ESP32.
Ideas de proyectos con OTA
- Sensor de techo o pared: cambia los umbrales de una placa que mide temperatura, humedad y movimiento sin tocar ningún cable.
- Relé domótico: actualiza por OTA las reglas horarias de la placa de relés del cuadro eléctrico; pon los relés en un estado seguro dentro de onStart.
- Dispositivos para Home Assistant: añade nuevas funciones por la red a sensores conectados a Home Assistant por MQTT.
- Controlador de riego del jardín: cambia las horas de riego y el umbral de humedad del suelo sin abrir la caja estanca.
- Barra de progreso en una LCD: muestra el valor de onProgress como porcentaje y barra en una LCD de 16x2; el proyecto ESP32 OTA de BlueGrays hace exactamente eso.
- Actualización de flota: haz que varias placas consulten cada noche el mismo servidor con HTTPUpdate en busca de una versión nueva.
Errores frecuentes y soluciones
| Síntoma | Causa probable | Solución |
|---|---|---|
| No hay puerto de red en el menú Puerto | Placa en otra red, mDNS bloqueado, el código no llama a ArduinoOTA.begin() | Usa la misma red de 2,4 GHz, reinicia el IDE, comprueba que la IP aparece en el Monitor Serie |
| "No response from the ESP" | delay() largo en loop(), placa ocupada o cortafuegos | Usa millis() en lugar de delay(), permite el IDE en el cortafuegos |
| "Authentication Failed" | Contraseña OTA incorrecta | Introduce el valor de setPassword del código; si la olvidaste, sube una vez por USB |
| "Not Enough Space" / Begin Failed | Esquema Huge APP o No OTA, el programa no cabe en la segunda zona | Elige Minimal SPIFFS y sube una vez por USB; reduce el programa |
| La carga se corta a la mitad | Señal débil, bajada de tensión, conexión perdida | Acerca la placa al router, usa una fuente de 5 V sólida, vuelve a intentarlo; el programa antiguo sigue funcionando |
| La placa no se conecta a la red tras la carga | El nuevo código no tiene Wi-Fi ni OTA, SSID incorrecto | Corrígelo por USB; a partir de ahora empieza cada proyecto con la plantilla OTA |
| "Wrong Magic Byte" o error de activación en ElegantOTA | Se eligió merged.bin, bootloader.bin o un archivo compilado para otro chip | Sube solo el archivo miproyecto.ino.bin |
El OTA es la clave para llevar los proyectos con ESP32 de la mesa a un lugar real: una vez bien configurado, los arreglos, las funciones nuevas y los cambios de umbral llegan sin cables en segundos. En la app BlueGrays encontrarás el proyecto ESP32 OTA Update (con la IP y el progreso en una LCD) junto a los proyectos de conexión Wi-Fi, Async Web Server, mDNS y NTP, todos con esquema de circuito y código paso a paso.
Preguntas frecuentes
¿Qué es el OTA del ESP32?
OTA (Over-The-Air) significa cargar un programa nuevo en el ESP32 por Wi-Fi en lugar de con un cable USB. La placa escribe el código nuevo en una partición de programa libre, lo verifica y se reinicia con la nueva versión. El primer sketch con OTA debes subirlo una vez por USB.
¿Por qué no aparece el puerto de red del ESP32 en el Arduino IDE?
Las causas más comunes son que el ordenador y la placa estén en redes distintas, que una red de invitados aísle los dispositivos o que la llamada ArduinoOTA.begin() del código nunca se ejecute. Comprueba en el Monitor Serie que la placa obtuvo una IP, reinicia el IDE y espera unos segundos.
¿Qué partition scheme elijo para el OTA del ESP32?
En placas con 4 MB de flash elige Default (zona de programa de 2 × 1,25 MB) o, si tu programa es grande, Minimal SPIFFS (2 × 1,875 MB). Huge APP y No OTA no tienen segunda zona de programa, así que el OTA no funciona con ellos. La primera carga después de cambiar el esquema debe hacerse por USB.
¿Se puede estropear el ESP32 si se corta una carga OTA?
No. El nuevo programa se escribe en una partición vacía y la partición de arranque solo cambia cuando todo el archivo está verificado. Si se cae la conexión o la luz, la placa arranca con el programa antiguo y puedes repetir la carga sin más.
¿Puedo usar el Monitor Serie al subir por OTA?
El puerto de red solo sirve para subir código; el Monitor Serie no funciona sin cable. Para ver mensajes puedes dejar la placa conectada por USB o mostrar la información en una página web, una pantalla o por MQTT.
¿Cómo pongo una contraseña al OTA del ESP32?
En ArduinoOTA llamas a ArduinoOTA.setPassword("contraseña") antes de begin(); el IDE pide esa contraseña antes de subir. Si no quieres que la contraseña se vea en el código, pasa su hash MD5 con setPasswordHash(). En ElegantOTA proteges la página con begin(&server, "usuario", "contraseña").
Proyectos para hacer después de leer esto
Ver todos los proyectos
Actualización OTA del ESP32 — Instalación inalámbrica del firmware (con pantalla LCD)
En este proyecto aprenderás a instalar un nuevo firmware en el ESP32 a través de Wi-Fi, sin necesidad de un cable USB. Con la biblioteca ArduinoOTA, el ESP32 se hace visible en la red y aparece automáticamente como bluegrays-ota en la pestaña «Puerto de red» del IDE de Arduino. La primera instalación se realiza mediante USB; a partir de ahí, todas las actualizaciones se realizan de forma inalámbrica, lo cual es una característica fundamental para los dispositivos de campo. En la pantalla LCD

Conexión Wi-Fi STA con ESP32 (con pantalla LCD)
En este proyecto, conectamos el ESP32 a la red Wi-Fi doméstica en modo Station (STA) de forma segura y tolerante a fallos. Separamos el SSID y la contraseña en el archivo secrets.h para evitar que se filtren a Git, configuramos un mecanismo de reconexión automática y mostramos el nivel de señal RSSI y la dirección IP en una pantalla LCD I2C. El LED interno actúa como indicador de estado.

Servidor web asíncrono ESP32 (con indicación de IP en la pantalla LCD)
En este proyecto, convertimos el ESP32 en un servidor web asíncrono que puedes controlar desde tu teléfono o tu ordenador, siempre que estén conectados a la misma red Wi-Fi. Gracias a la biblioteca ESPAsyncWebServer, el servidor puede procesar varias solicitudes al mismo tiempo (a diferencia del clásico WebServer.h, que se bloquea con una sola solicitud).

ESP32 mDNS: Acceso al dispositivo mediante bluegrays-esp.local (con pantalla LCD)
En este proyecto, al añadir el servicio mDNS (Multicast DNS) al ESP32, permitimos el acceso mediante un nombre de host legible, como bluegrays-esp.local, en lugar de una dirección IP. Aunque la IP asignada por el DHCP cambie, siempre podrás acceder al dispositivo con el mismo nombre. Además, al ejecutar un pequeño servidor web en él, enviamos comandos de control de los LED desde el navegador mediante la dirección http://bluegrays-esp.local/. En la pantalla LCD I2C se muestran el nombre de ho

Contador ESP32 WebSocket (2 botones + pantalla LCD + web en tiempo real)
En este proyecto, dos botones conectados al ESP32 (GPIO 5 suma, GPIO 4 resta) cambian un contador. El valor se actualiza al instante en una pantalla LCD I2C de 16x2 y, gracias al soporte WebSocket de ESPAsyncWebServer, en todos los navegadores conectados sin recargar la página. En lugar del sondeo HTTP se usa una única conexión persistente y el ESP32 envía el nuevo valor a todos con ws.textAll().

ESP32: hora real desde Internet con NTP
El ESP32 se conecta a Wi-Fi y obtiene la hora real con precisión de milisegundos desde servidores NTP (Network Time Protocol). Gracias a configTzTime(), se aplica automáticamente la zona horaria de Turquía (TRT, UTC+3) y el cambio DST se gestiona mediante la cadena POSIX TZ. La hora se muestra en el monitor serie y en una pantalla LCD I2C opcional. configTzTime() inicia el servicio SNTP; se realizan resincronizaciones periódicas mientras hay acceso a la red, y el reloj del sistema sigue avan

ESP32 HTTPClient + API del tiempo (con pantalla LCD)
En este proyecto, utilizamos el ESP32 para realizar una llamada a la API REST de la página web de información meteorológica (wttr.in) a través de Internet, utilizando HTTPClient.h. Analizamos la respuesta JSON devuelta con ArduinoJson v7 y mostramos la información sobre la ciudad, la temperatura, la humedad, el tiempo y el viento en una pantalla LCD I2C, tanto en turco como en inglés. wttr.in es gratuito y no requiere clave API: basta con escribir el nombre de cualquier ciudad para obtener su

Modo de suspensión profunda del ESP32 — Ahorro de batería (OLED + contador en RTC RAM)
El modo «Deep Sleep» del ESP32 reduce el consumo de corriente a unos 10 µA al desactivar la CPU y la mayoría de los periféricos, lo cual es de vital importancia para los dispositivos IoT que funcionan con pilas. En este proyecto utilizamos tres fuentes de activación diferentes: el temporizador (15 s), un pin externo (EXT0 — botón GPIO 33) y el sensor táctil (T0/GPIO 4). Las variables marcadas con RTC_DATA_ATTR se conservan durante el modo Deep Sleep: el contador de arranque, el contador de act
Más artículos
App BlueGrays
Monta este circuito paso a paso en tu teléfono
Esquema, código y lista de piezas en una sola pantalla. Más de 200 proyectos de Arduino, ESP32 y Pico listos para montar.
Escanea con tu teléfono
Apunta la cámara al código y se abrirá la tienda de apps de tu teléfono.
o ábrela en la tienda

