Tutorial
Cómo crear un monitor serial web
Comunica una página HTML con placas ESP32, Arduino y otros dispositivos mediante la Web Serial API.
Un monitor serial permite observar los mensajes que una placa envía por USB y, cuando hace falta, devolverle comandos desde la computadora. En este tutorial construiremos una versión que funciona directamente en el navegador, donde el usuario selecciona el puerto, elige la velocidad, recibe datos de manera asíncrona y puede enviar texto con distintos finales de línea. El resultado es una herramienta útil para depurar firmware, inspeccionar sensores y controlar prototipos sin instalar una aplicación de escritorio.
Por qué usar un monitor serial en el navegador
Cuando se programa un ESP32, una placa Arduino o cualquier microcontrolador con comunicación serial, la primera ventana hacia el dispositivo suele ser el monitor serial. El firmware puede imprimir estados de inicialización, lecturas de sensores, mensajes de error y resultados de pruebas. Esa salida convierte en observable un programa que, de otro modo, estaría ejecutándose dentro de una placa sin una interfaz visible.
Las herramientas tradicionales, como el monitor de Arduino IDE, PlatformIO o una terminal del sistema, cumplen muy bien esa función. Sin embargo, una interfaz web puede ser conveniente cuando se desea compartir una herramienta, integrarla con documentación o combinar la consola con controles gráficos. Un mismo documento HTML puede mostrar botones, campos de entrada, gráficas y comandos específicos para el experimento.
La página utilizada como referencia para este artículo es la de Serial Studio. Se trata de un monitor bidireccional que muestra lo que llega desde la placa y también permite escribir mensajes hacia ella.
Qué es la Web Serial API
La Web Serial API es una interfaz del navegador que permite leer y escribir bytes en dispositivos que el sistema operativo presenta como puertos seriales. Una placa conectada mediante USB suele aparecer como un puerto serial, aunque internamente utilice un conversor USB-UART o una interfaz USB nativa.
La página no recibe los datos a través de un servidor. El navegador solicita permiso para acceder al puerto local y mantiene la comunicación directamente con el dispositivo conectado a la computadora. Esta arquitectura permite publicar la herramienta como una página estática, siempre que se cumplan las condiciones de seguridad del navegador.
El flujo general tiene cuatro momentos:
- El usuario pulsa Conectar y selecciona un puerto.
- La página abre el puerto con la velocidad de transmisión elegida.
- Un lector asíncrono obtiene los bytes y los convierte en texto.
- El usuario puede enviar texto mediante un escritor y cerrar la conexión cuando termina.
Requisitos
Para utilizar el monitor se necesita lo siguiente:
- Una placa con comunicación serial, por ejemplo ESP32, Arduino Uno, RP2040 u otra placa compatible.
- Un cable USB que permita transferencia de datos. Algunos cables solo sirven para cargar la batería.
- Un firmware que inicialice el puerto serial y envíe o reciba datos.
- Un navegador compatible con Web Serial API. La página comprueba la existencia de
navigator.serialantes de habilitar la conexión. - Una página servida mediante HTTPS cuando se accede desde Internet. Durante el desarrollo, un origen local
como
http://localhosttambién puede considerarse contexto seguro en los navegadores que lo permiten. - La misma velocidad de transmisión en el firmware y en el monitor, por ejemplo
115200baudios.
El acceso al puerto siempre requiere una decisión explícita del usuario. La llamada
navigator.serial.requestPort() debe ejecutarse como consecuencia de una acción, como pulsar un
botón. La página no puede seleccionar silenciosamente cualquier dispositivo conectado.
Un firmware mínimo para probar la conexión
Antes de escribir el monitor, conviene tener un programa pequeño que produzca una salida reconocible y responda a un mensaje. Este ejemplo utiliza funciones disponibles tanto en Arduino como en muchas variantes de ESP32:
El firmware inicia el puerto a 115200 baudios, envía una señal inicial y después produce una línea
por segundo. También escucha los datos recibidos y devuelve un eco. El monitor no necesita conocer el significado
de cada línea: puede mostrar texto arbitrario y dejar que una capa posterior lo interprete como CSV, JSON o un
protocolo propio.
En un proyecto real es importante que cada mensaje tenga un formato definido. Por ejemplo, un sensor podría
transmitir IMU,0.012,-0.034,0.997 y una interfaz especializada podría separar sus campos para
construir una gráfica o una tabla.
La estructura HTML de la interfaz
La interfaz necesita un selector para los baudios, botones de conexión, un área de consola y controles para enviar información. Los identificadores permiten que JavaScript encuentre cada elemento y modifique su estado.
En la página publicada, los controles de envío se desactivan hasta que existe una conexión. Así se evita intentar
escribir en un puerto que todavía no está abierto. La consola utiliza textContent y
white-space: pre-wrap para conservar los saltos de línea sin interpretar el texto recibido como HTML.
Detectar compatibilidad y solicitar el puerto
El primer paso consiste en detectar la API. Si no existe, el botón de conexión se desactiva y la consola muestra un mensaje que orienta al usuario. Si existe, la selección del puerto se solicita dentro del evento de clic:
requestPort() devuelve una promesa. Cuando el usuario elige un dispositivo, el resultado es un objeto
SerialPort. La llamada open() inicia la comunicación con la velocidad indicada. Si el
firmware trabaja a 9600 y la página abre el puerto a 115200, los bytes se interpretarán
incorrectamente y la consola mostrará caracteres ilegibles.
Leer el puerto como un flujo asíncrono
La llegada de datos no debe detener la interfaz. Web Serial utiliza Streams API, por lo que el monitor obtiene un
lector y espera los datos con await reader.read(). El navegador resuelve esa espera cada vez que llega
un nuevo fragmento.
Un detalle importante es que reader.read() no necesariamente devuelve una línea completa. Puede
entregar solo una parte de ella o varias líneas juntas. Por eso la implementación mostrada es adecuada para una
consola de texto, pero una aplicación que necesite analizar mensajes debe acumular los fragmentos y separar las
tramas mediante un delimitador, normalmente \n.
Enviar datos hacia la placa
La comunicación serial es bidireccional. Para escribir se obtiene temporalmente un escritor, se convierte el texto
a bytes con TextEncoder y se libera el escritor después de terminar. El final de línea se agrega según
la selección del usuario.
El terminador debe coincidir con lo que espera el firmware. Muchas implementaciones basadas en
readStringUntil('\n') requieren nueva línea; otras esperan retorno de carro o ambos caracteres.
Ofrecer las tres opciones evita tener que modificar el monitor cada vez que cambia el protocolo.
Desconectar y liberar recursos
Cerrar la conexión requiere detener la lectura pendiente, liberar el lector y cerrar el puerto. Si se omite este paso, otra aplicación puede encontrar el dispositivo ocupado hasta que se cierre la pestaña o se desconecte el cable.
reader.cancel() interrumpe la espera de lectura y permite que el bloque finally libere
el lector. Después, port.close() cierra la comunicación. La función toggleUI() reactiva
el selector de baudios y deshabilita los controles que requieren un puerto abierto.
Conservar una interfaz clara
La lógica de comunicación debe mantenerse separada de la presentación. La consola solo muestra texto; los botones
cambian el estado de la conexión; y una función independiente, como appendLog(), centraliza el
desplazamiento automático:
La salida se agrega mediante textContent en lugar de innerHTML. Así, si la placa envía
símbolos como < o una cadena que parece una etiqueta, el navegador la muestra como texto y no la
interpreta como contenido de la página.
Adaptar el monitor a sensores y comandos
Una vez establecida la comunicación, el monitor puede convertirse en la base de una interfaz más específica. Hay dos estrategias frecuentes:
- Conservar la consola y añadir un parser para mensajes delimitados, como CSV, JSON o paquetes con una palabra inicial.
- Ocultar la consola y actualizar directamente indicadores, gráficas o tablas a partir de cada trama recibida.
Por ejemplo, si el firmware envía TEMP,24.6, el código puede separar el nombre de la variable y su
valor. Para mensajes JSON, JSON.parse() permite convertir cada línea en un objeto. En ambos casos
conviene validar el formato antes de actualizar la interfaz y mostrar los errores en la consola.
La misma conexión puede utilizarse para enviar comandos: cambiar el periodo de muestreo, activar un actuador, solicitar una lectura inmediata o modificar parámetros de calibración. El protocolo debe documentar claramente los comandos, sus argumentos y la respuesta esperada.
Problemas frecuentes
- El navegador no muestra el selector de puertos. Comprueba que la llamada a
requestPort()ocurra después de pulsar un botón, que la página use HTTPS o un origen local permitido y que el navegador implemente Web Serial API. - No aparece la placa. Revisa el cable USB, cierra el monitor de Arduino IDE o PlatformIO y confirma que el sistema operativo haya creado un puerto serial. Algunas placas requieren un controlador para el conversor USB.
- La consola muestra caracteres extraños. Usa la misma velocidad en ambos extremos y revisa los parámetros de la conexión. En la mayoría de las placas basta con coincidir en los baudios.
- La placa recibe el mensaje incompleto. Selecciona el final de línea que espera el firmware. También verifica que el código de la placa no descarte los caracteres de retorno de carro.
- La lectura se detiene después de desconectar. Cancela el lector antes de cerrar el puerto y
libera su bloqueo con
releaseLock(). - La página funciona en un equipo pero no en otro. La compatibilidad de Web Serial depende del navegador y del sistema operativo. Mantén la detección de características y proporciona un mensaje de error claro.
Seguridad y límites prácticos
El permiso se concede por sitio y por dispositivo. El usuario debe seleccionar el puerto desde el diálogo del navegador, y la página solo obtiene acceso a los dispositivos autorizados. Aun así, una página con permiso puede enviar datos a la placa, por lo que conviene conectarse únicamente a sitios de confianza y revisar el código antes de conceder acceso.
Web Serial no convierte automáticamente cualquier USB en un puerto serial. La placa debe exponer una interfaz compatible con esta API y el sistema operativo debe reconocerla. Tampoco establece por sí sola un protocolo de mensajes: la velocidad, los terminadores, el formato de las tramas y la interpretación de los datos son decisiones del proyecto.
Conclusión
Un monitor serial web combina una interfaz HTML sencilla con dos ideas esenciales de JavaScript: las promesas para abrir y cerrar el puerto, y los streams para leer datos sin bloquear la página. Con un firmware que envíe líneas bien definidas, esta base puede crecer hasta convertirse en una consola de depuración, un panel de sensores o una interfaz de control para un prototipo.
Referencias
- Chrome for Developers. (2020). Read from and write to a serial port. Recuperado el 5 de septiembre de 2026.
- Mozilla Developer Network. (2026). Web Serial API. Recuperado el 5 de septiembre de 2026.
- Santos-Ruiz, I. (2026). Serial Studio [Aplicación web]. Recuperado el 5 de septiembre de 2026.