Cloud, DevOps e IoT en español

Parte 20 de 22 de la serie Domótica con ESP32 y AWS desde cero

Flashear un ESP32 desde el navegador con ESP Web Tools, sin instalar nada

11 de octubre de 2026 · Steven Carvajal · Tutoriales

Código de este artículo en GitHub →

Instalar el firmware en un ESP32 suele requerir una terminal o Arduino IDE: borrar la flash con esptool, compilar eligiendo la placa correcta y cargar el programa. Funciona, pero solo si sabes qué estás haciendo y tienes todo instalado.

Con ESP Web Tools se convierte en un botón de una página web: conectas la placa por USB, haces clic, el navegador detecta si es un ESP32-S3 o un ESP32-C3 e instala el firmware que le corresponde. En esta parte lo agregamos al panel web de la serie.

La pieza clave: Web Serial

Los navegadores basados en Chromium (Chrome y Edge de escritorio) implementan la Web Serial API, que permite a una página, con tu permiso, hablar con un dispositivo conectado por un puerto serie USB. Con eso, el mismo protocolo que usa esptool para cargar firmware se puede ejecutar dentro del navegador.

La limitación: no funciona en Safari, Firefox ni en iPhone o iPad. Para una herramienta de instalación que se usa desde un computador, suele ser aceptable.

Dos caminos: construirlo o usar ESP Web Tools

Encima de Web Serial hay dos opciones:

esptool-js a manoESP Web Tools
Qué esLa librería oficial de Espressif para cargar firmware desde el navegadorUn componente web listo, de los creadores de ESPHome, el que usa Home Assistant
InterfazLa haces tú: conectar, detectar, confirmar, progreso, erroresTrae su propio diálogo
MantenimientoTuyoDe un proyecto grande y activo
IdiomaEl que quierasEl diálogo está en inglés

Para la mayoría de los casos, ESP Web Tools es la mejor opción: una librería probada por miles de usuarios frente a código propio el primer día. La única contra real es que su diálogo está en inglés; lo que lo rodea en tu página puede estar en español.

El manifiesto: un botón, dos chips

ESP Web Tools lee un archivo manifest.json que describe qué firmware instalar según el chip:

{
  "name": "Casa Demo",
  "version": "1.0.0",
  "builds": [
    { "chipFamily": "ESP32-S3", "parts": [{ "path": "/firmware/hub.bin", "offset": 0 }] },
    { "chipFamily": "ESP32-C3", "parts": [{ "path": "/firmware/nodo.bin", "offset": 0 }] }
  ]
}

Después de conectarse, el componente pregunta al chip qué es y elige la entrada correspondiente. En el proyecto de ejemplo, un ESP32-S3 recibe el firmware del hub y un ESP32-C3 el del nodo, sin que nadie tenga que elegir. Los nombres de chipFamily llevan guion: "ESP32-S3", "ESP32-C3".

Por qué hay que borrar la memoria

Si tu firmware guarda la configuración (Wi-Fi, certificado) en la partición NVS de la flash (parte 6). Un firmware no ocupa toda la memoria: si solo escribes el programa, la configuración vieja se queda, y la placa "reinstalada" sigue usando los datos anteriores.

ESP Web Tools borra toda la flash por defecto en una instalación nueva, a menos que el manifiesto diga lo contrario con la opción new_install_prompt_erase.

Un solo archivo por firmware

Un firmware de Arduino para ESP32 son varios archivos que van en posiciones distintas de la memoria: el bootloader, la tabla de particiones, un pequeño archivo de arranque y el programa. Se pueden unir con esptool merge_bin, pero las versiones recientes del core de ESP32 para Arduino generan el archivo unificado solas al exportar los binarios.

arduino-cli compile --fqbn esp32:esp32:esp32s3 --export-binaries --output-dir build/hub firmware/hub
arduino-cli compile --fqbn esp32:esp32:esp32c3 --export-binaries --output-dir build/nodo firmware/nodo
# Copia los *.ino.merged.bin a public/firmware/ como hub.bin y nodo.bin

Si quieres comprobarlo, ábrelo con un visor hexadecimal: en la posición 0x0 está la firma del bootloader, en 0x8000 la de la tabla de particiones, y la zona de NVS está llena de 0xFF, que es memoria borrada. Escribir ese archivo en la posición 0 deja la placa como nueva.

Compilar y copiar los binarios puede ser un paso manual o un job de CI que se ejecute cuando cambia el firmware.

El componente en React

ESP Web Tools es un custom element, <esp-web-install-button>. En React se usa así:

import "esp-web-tools";  // registra el custom element

export function FlashFirmwareTab() {
  return (
    <section>
      <h2>Flashear firmware</h2>
      <p className="warning">
        Esto borra toda la configuración de la placa. Después tendrás que configurarla de nuevo desde su red Wi-Fi.
      </p>
      <esp-web-install-button manifest="/firmware/manifest.json">
        <button slot="activate">Conectar y flashear placa</button>
        <span slot="unsupported">Tu navegador no puede flashear placas. Usa Chrome o Edge en un computador.</span>
        <span slot="not-allowed">Abre el panel por HTTPS para poder flashear.</span>
      </esp-web-install-button>
    </section>
  );
}

Los slots unsupported y not-allowed los ofrece el propio componente: muestran un mensaje cuando el navegador no tiene Web Serial o la página no está en HTTPS. Así no hay que detectar nada a mano.

TypeScript y los custom elements

TypeScript no conoce <esp-web-install-button> y marca error. Con la configuración "jsx": "react-jsx", los elementos JSX se validan contra el espacio de nombres JSX del módulo react, así que la declaración va ahí:

// src/types/esp-web-tools.d.ts
import "react";

declare module "react" {
  namespace JSX {
    interface IntrinsicElements {
      "esp-web-install-button": React.DetailedHTMLProps<
        React.HTMLAttributes<HTMLElement> & { manifest?: string },
        HTMLElement
      >;
    }
  }
}

Si el build falla por una dependencia

ESP Web Tools depende de @material/web con un rango de versiones (^2.x). Si una versión menor de esa librería reorganiza sus archivos internos, el build de Vite puede fallar con un error de importación dentro de esp-web-tools. La solución es fijar la versión de @material/web que usan los autores de ESP Web Tools, que puedes ver en el package-lock.json de su repositorio:

{
  "dependencies": {
    "@material/web": "<la versión de su lockfile>",
    "esp-web-tools": "^10.4.0"
  }
}

Lección general: el semver es una promesa, no una garantía. Cuando una dependencia de una dependencia rompe, el lockfile del proyecto original te dice qué versión funciona de verdad.

No precachear los binarios

Si la web app es una PWA (parte 15), su service worker guarda en caché todos los archivos del build. Los binarios pesan varios MB y solo se usan al flashear, así que conviene excluirlos:

VitePWA({
  workbox: {
    globIgnores: ["**/firmware/**"],
  },
});

Cómo se ve al usarlo

  1. Conecta la placa por USB y haz clic en el botón.
  2. El navegador muestra un selector de puertos: elige el de la placa.
  3. El diálogo detecta el chip, confirma la instalación y muestra el progreso del borrado y la escritura.
  4. Al terminar, la placa se reinicia con el firmware nuevo. Si tu firmware tiene portal de configuración (parte 16), aparecerá su red Wi-Fi.

Preguntas frecuentes

¿Por qué el navegador no detecta mi placa?

Revisa que el cable USB transmita datos (muchos solo cargan), que uses Chrome o Edge de escritorio y que la página esté en HTTPS o localhost. En Windows, algunas placas con conversor USB-serie externo necesitan su driver; las Super Mini usan el USB nativo del chip y no suelen necesitarlo.

¿Puedo actualizar sin borrar la configuración?

Sí: con new_install_prompt_erase: true en el manifiesto, el diálogo pregunta si borrar o no.

¿Esto sirve para actualizar dispositivos ya instalados en casas?

No, porque requiere conectar la placa por USB. Para actualizar a distancia hace falta OTA: lo explico en la guía para flashear y actualizar un ESP32.

Sigue leyendo