En este tutorial aprenderás a crear un termómetro sin contacto usando la UNIT Pulsar ESP32-C6 y el sensor MLX90614-DCC de DFRobot. El proyecto te guiará paso a paso para:
- Conectar el sensor por I2C y configurar la UNIT Pulsar ESP32-C6 en modo SoftAP, creando su propia red WiFi sin necesidad de conexión a internet.
- Acceder a una interfaz web responsiva desde tu celular o computadora, donde podrás:
- Obtener lecturas de temperatura del objeto y la temperatura ambiente.
- Borrar lecturas
INTRODUCCIÓN
Este proyecto permite medir la temperatura de objetos y del ambiente de forma precisa y visualizar los datos en una interfaz web, sin necesidad de internet, gracias a que la UNIT Pulsar ESP32-C6 crea su propia red WiFi. Es una solución práctica para makers, prototipos y aplicaciones industriales, como monitoreo de procesos, control de calidad o sistemas de automatización.
Ahora que conoces el objetivo del proyecto, comencemos con el desarrollo paso a paso. Sigue cada sección con atención para que puedas replicar el proyecto sin complicaciones.
MATERIALES
¡Manos a la obra! Antes de empezar, asegúrate de tener a la mano los siguientes materiales:
- UNIT Pulsar ESP32-C6
- MLX90614-DCC Sensor de Temperatura IR
- Arnés QWIIC 4 pines Pitch 1mm
- Cable USB Tipo C
Otros recursos que necesitaremos:
DESARROLLO
¡Listo! Ahora sí, comencemos con el tutorial. Sigue los pasos que se indican a continuación.
1. Configuración de entorno de programación
Para comenzar, utilizaremos el Arduino IDE como entorno de desarrollo. Asegúrate de tener lo siguiente listo:
- Instala el Arduino IDE
Descárgalo desde el sitio oficial:
👉 https://www.arduino.cc/en/software
⚠️(Si ya lo tienes instalado, puedes omitir este paso).
- Agrega la placas de desarrollo UNIT Electronics ESP32 a Arduino IDE
Abre el IDE y ve a Archivo > Preferencias.
En el campo “Gestor de URLs adicionales de tarjetas”, agrega la siguiente dirección:
👉 https://raw.githubusercontent.com/UNIT-Electronics/Uelectronics-ESP32-Arduino-Package/main/package_Uelectronics_esp32_index.json

- Instala las placas UNIT Electronics ESP32 desde el Gestor de placas de Arduino IDE
Después la URL al preferencias dirígete a la pestaña Herramientas > Placa > Gestor de placas, busca “UNIT Electronics ESP32” e instala las placas. En la siguiente imagen tienes la referencia.

DIAGRAMA DE CONEXIÓN
Las conexiones son muy simples. Puedes aprovechar el cable incluido con el sensor MLX90614 junto con un arnés QWIIC, lo que hará más rápida y ordenada la conexión con la UNIT Pulsar ESP32-C6.
Para simplificar las conexiones, se utilizara el puerto QWIIC de la UNIT Pulsar ESP32-C6, el cual está diseñado para trabajar con dispositivos I2C de manera rápida y segura. Este puerto no solo facilita la conexión, sino que también está optimizado para bajo consumo de energía.
En la siguiente imagen se muestra el diagrama de conexión que debes seguir para tener comunicación entre el sensor y la tarjeta.

MLX90614 (DFRobot) | UNIT Pulsar ESP32-C6 |
---|---|
VCC (3.3V) | 3.3V |
GND | GND |
SDA | GPIO6 / LP_SDA |
SCL | GPIO7 / LP_SCL |
Si no cuentas con un cable QWIIC, también puedes realizar la conexión directamente utilizando los pines GPIO22 (SDIO_DATA2) para SDA y GPIO23 (SDIO_DATA3) para SCL, manteniendo la misma funcionalidad en la comunicación con el sensor.
Si deseas que este proyecto sea portátil y de bajo consumo de energía, lo más recomendable es utilizar el puerto QWIIC. Además, puedes soldar un conector PH2.0mm en la parte inferior de la UNIT Pulsar ESP32-C6, lo que te permitirá conectar fácilmente una batería LiPo y alimentar el dispositivo sin depender de una fuente externa.
CÓDIGOS
Una vez que hayas realizado todas las conexiones, el siguiente paso es instalar la librería MLX90614 en el Arduino IDE, ya que esta es necesaria para que la UNIT Pulsar ESP32-C6 pueda comunicarse correctamente con el sensor.
Para hacerlo, descarga la librería del repositorio oficial de DFRobot en GitHub, en el siguiente enlace podrás descargar la librería. Luego, solo tendrás que importarla a Arduino IDE.
Una vez importada la librería MLX90614 en el Arduino IDE, el siguiente paso es verificar que las conexiones estén correctas y que el sensor esté tomando lecturas de manera adecuada.
Para esto, utilizaremos un código de ejemplo que hemos modificado para que sea compatible con la UNIT Pulsar ESP32-C6. Este código te permitirá visualizar en el monitor serie las lecturas obtenidas por el sensor, asegurando que todo funcione correctamente antes de avanzar con el proyecto.
Antes de cargar el código selecciona la placa UNIT Pulsar ESP32-C6, como se muestra a continuación:

Después selecciona el puerto COM que se le asigno a la tarjeta y verifica que tengas seleccionado los siguientes parámetros:

Estos parámetros que permiten a la UNIT Pulsar ESP32-C6 funcione correctamente y aproveche sus recursos al máximo. La frecuencia de 160MHz ofrece buen rendimiento con bajo consumo, mientras que la memoria Flash de 4MB se divide entre el programa y el sistema de archivos SPIFFS, ideal para guardar la interfaz web y otros recursos. Además, al habilitar USB CDC, permite establecer comunicación y visualizar en el monitor serie las lecturas del sensor.
Código para lecturas en el monitor serial
Ya configurados los parámetros antes mencionados compila y carga el siguiente código:
// Incluye la librería para comunicación I2C #include <Wire.h> // Incluye la librería para el sensor MLX90614 #include <DFRobot_MLX90614.h> // Define el pin SDA (Datos) para la comunicación I2C #define SDA_PIN 6 // Define el pin SCL (Reloj) para la comunicación I2C #define SCL_PIN 7 // Crea un objeto llamado 'sensor' para manejar el MLX90614 a través de I2C DFRobot_MLX90614_I2C sensor; void setup() { // Inicializa la comunicación serial a 115200 baudios para depuración Serial.begin(115200); // Inicializa el bus I2C con los pines definidos SDA y SCL Wire.begin(SDA_PIN, SCL_PIN); // Pequeña pausa para asegurar que el bus I2C esté listo antes de continuar delay(1000); // Mensaje informativo en el monitor serial Serial.println("Iniciando MLX90614..."); // --- Escaneo del bus I2C para detectar dispositivos conectados --- byte error, address; // Variables para manejar errores y direcciones detectadas int nDevices = 0; // Contador de dispositivos encontrados Serial.println("Escaneando bus I2C..."); // Recorre todas las direcciones I2C posibles (1 a 126) for(address = 1; address < 127; address++ ) { Wire.beginTransmission(address); // Inicia comunicación con la dirección actual error = Wire.endTransmission(); // Finaliza y guarda el resultado // Si no hubo error, significa que hay un dispositivo en esa dirección if (error == 0) { Serial.print("Dispositivo encontrado en: 0x"); if (address < 16) Serial.print("0"); // Formato correcto para direcciones menores a 0x10 Serial.println(address, HEX); // Muestra la dirección en formato hexadecimal nDevices++; // Aumenta el contador de dispositivos encontrados } } // Mensaje dependiendo de si se encontraron dispositivos o no if (nDevices == 0) { Serial.println("No se encontraron dispositivos I2C!"); } else { Serial.println("Escaneo completado"); // --- Inicialización del sensor MLX90614 --- // Si la inicialización es exitosa if (sensor.begin() == NO_ERR) { Serial.println("MLX90614 iniciado correctamente"); } else { // Si falla la inicialización Serial.println("Error al iniciar MLX90614"); } } } void loop() { // Verifica si el sensor sigue inicializando correctamente if (sensor.begin() == NO_ERR) { // Lee y muestra la temperatura del objeto detectado Serial.print("Objeto: "); Serial.print(sensor.getObjectTempCelsius()); Serial.print("°C, Ambiente: "); // Lee y muestra la temperatura ambiente Serial.print(sensor.getAmbientTempCelsius()); Serial.println("°C"); } else { // Si hay error de comunicación, muestra el mensaje Serial.println("Error de comunicación con sensor"); } // Espera 2 segundos antes de la siguiente lectura delay(2000); }
Este código permite conectar y verificar el funcionamiento del sensor MLX90614 con la UNIT Pulsar ESP32-C6 mediante comunicación I2C. Primero, realiza un escaneo del bus I2C para confirmar que el sensor está bien conectado. Luego, en el ciclo principal, lee y muestra en el monitor serial la temperatura del objeto detectado y la temperatura ambiente cada 2 segundos. Si ocurre un error en la comunicación, muestra un mensaje de advertencia para facilitar la detección de problemas en la conexión.
Al cargar el código abre el monitor serie y podrás visualizar que el sensor se inicia correctamente y si como sus lecturas de temperatura.

Código para SoftAP y Interfaz WEB
Ya que el sensor funciona correctamente ya podrás cargar el siguiente código completo del proyecto:
/* Código completo: UNIT Pulsar ESP32-C6 + MLX90614 + SoftAP - SDA = GPIO6, SCL = GPIO7 - SoftAP IP: 192.168.4.1 (configuración por defecto) - Rutas: / -> interfaz HTML /get -> devuelve JSON con objectTemp y ambientTemp /clear -> borra las lecturas (servidor) */ // Incluimos las librerías necesarias #include <WiFi.h> // Biblioteca para WiFi (maneja SoftAP) #include <WebServer.h> // Biblioteca para servidor HTTP simple #include <Wire.h> // Biblioteca I2C #include <DFRobot_MLX90614.h> // Biblioteca del sensor MLX90614 de DFRobot // Definición de pines I2C para ESP32-C6 (SDA y SCL) #define SDA_PIN 6 // SDA en GPIO6 (D13) #define SCL_PIN 7 // SCL en GPIO7 (D11) // Credenciales para la red WiFi en modo Access Point (SoftAP) const char *ssid = "UNIT-Termometro"; // Nombre de la red que generará el ESP const char *password = "12345678"; // Contraseña (mínimo 8 caracteres) // Crear instancia del servidor web en el puerto 80 (HTTP) WebServer server(80); // Crear instancia del objeto sensor MLX90614 usando la clase I2C DFRobot_MLX90614_I2C sensor; // Variables globales para almacenar lecturas y estados float objectTemp = 0.0; // Última lectura de temperatura del objeto (°C) float ambientTemp = 0.0; // Última lectura de temperatura ambiente (°C) bool hasReading = false; // Indica si hay una lectura válida disponible bool clearData = false; // Bandera para indicar que se borraron las lecturas // Función que devuelve la página HTML completa como string // Dentro del string HTML agregamos comentarios explicativos (<!-- -->) para cada sección String getHTML() { // Aquí devolvemos la interfaz de usuario como una cadena raw (sin procesar) // La página contiene: // - 2 campos de texto readonly para mostrar las temperaturas // - Botón "Obtener Lecturas" que pide /get al servidor // - Botón "Borrar" que pide /clear al servidor y limpia los campos localmente return R"rawliteral( <!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>UNIT Termómetro</title> <style> /* Estilos para un diseño responsivo y limpio */ * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: Arial, sans-serif; background-color: #f4f4f4; text-align: center; padding: 20px; } h1 { color: #333; margin-bottom: 20px; } .container { max-width: 400px; margin: auto; background: #fff; padding: 20px; border-radius: 10px; box-shadow: 0 0 10px rgba(0,0,0,0.1); } .input-group { margin-bottom: 15px; text-align: left; } label { font-weight: bold; display: block; margin-bottom: 5px; } input[type="text"] { width: 100%; padding: 10px; border: 1px solid #ccc; border-radius: 5px; font-size: 16px; text-align: center; } .buttons { display: flex; justify-content: space-between; gap: 10px; margin-top: 20px; } button { flex: 1; padding: 10px; font-size: 16px; border: none; border-radius: 8px; cursor: pointer; color: white; } .get-btn { background-color: #28a745; } .get-btn:hover { background-color: #218838; } .clear-btn { background-color: #dc3545; } .clear-btn:hover { background-color: #c82333; } @media (max-width: 500px) { .buttons { flex-direction: column; } } </style> </head> <body> <!-- Título --> <h1>UNIT TERMÓMETRO PARA OBJETOS</h1> <!-- Contenedor principal de la tarjeta --> <div class="container"> <!-- Campo para temperatura del objeto --> <div class="input-group"> <label for="obj">Temperatura Objeto (°C)</label> <!-- valor inicial "--" --> <input type="text" id="obj" readonly value="--"> </div> <!-- Campo para temperatura ambiente --> <div class="input-group"> <label for="amb">Temperatura Ambiente (°C)</label> <!-- valor inicial "--" --> <input type="text" id="amb" readonly value="--"> </div> <!-- Botones: Obtener Lecturas y Borrar --> <div class="buttons"> <button class="get-btn" onclick="getReading()">Obtener Lectura</button> <button class="clear-btn" onclick="clearFields()">Borrar</button> </div> </div> <script> // Función que solicita la lectura al servidor (ruta /get) async function getReading() { try { // Llamada fetch que espera respuesta JSON con las temperaturas const response = await fetch('/get'); const data = await response.json(); // Rellenar los campos con los datos recibidos document.getElementById('obj').value = data.objectTemp; document.getElementById('amb').value = data.ambientTemp; } catch (error) { // Si hay error (por ejemplo timeout o red), avisar al usuario alert('Error al obtener lectura'); } } // Función que limpia las casillas localmente y pide al servidor que borre su estado function clearFields() { fetch('/clear'); // petición al servidor para que ponga clearData = true // Limpiar visualmente los campos en el navegador document.getElementById('obj').value = '--'; document.getElementById('amb').value = '--'; } </script> </body> </html> )rawliteral"; } // fin de getHTML() // ===================== SETUP ===================== void setup() { Serial.begin(115200); // Inicia comunicación serial para mensajes de depuración Wire.begin(SDA_PIN, SCL_PIN); // Inicializa bus I2C en los pines definidos (SDA, SCL) delay(500); // Pequeña pausa para estabilizar // Configura y enciende el punto de acceso (SoftAP) Serial.println("Iniciando SoftAP..."); WiFi.softAP(ssid, password); // Inicia SoftAP con SSID y contraseña Serial.print("IP del AP: "); Serial.println(WiFi.softAPIP()); // Muestra la IP (debería ser 192.168.4.1 por defecto) // Intento de inicializar el sensor MLX90614 if (sensor.begin() == NO_ERR) { // sensor.begin() devuelve NO_ERR si la comunicación I2C está correcta Serial.println("MLX90614 iniciado correctamente"); } else { Serial.println("Error al iniciar MLX90614"); // Mensaje de error si no responde } // Ruta raíz: entrega la página HTML principal server.on("/", []() { server.send(200, "text/html", getHTML()); // Responde con la interfaz }); // Ruta /get: cuando el cliente solicita una lectura server.on("/get", []() { // Si previamente se había marcado 'borrado', lo desactivamos para permitir nuevas lecturas clearData = false; // Tomar lecturas del sensor (bloque corto) objectTemp = sensor.getObjectTempCelsius(); // Lectura de objeto en °C ambientTemp = sensor.getAmbientTempCelsius(); // Lectura de ambiente en °C hasReading = true; // Marcar que tenemos una lectura válida // Construir JSON manualmente con dos decimales String json = "{\"objectTemp\":\"" + String(objectTemp, 2) + "\",\"ambientTemp\":\"" + String(ambientTemp, 2) + "\"}"; // Enviar respuesta JSON al cliente que pidió /get server.send(200, "application/json", json); // Imprimir en serial para debug Serial.printf("Objeto: %.2f °C | Ambiente: %.2f °C\n", objectTemp, ambientTemp); }); // Ruta /clear: limpiado de lecturas (servidor) server.on("/clear", []() { clearData = true; // Activar bandera de borrado para evitar enviar lecturas hasta nueva petición hasReading = false; // No hay lectura válida objectTemp = 0.0; // Reset de variables ambientTemp = 0.0; server.send(200, "text/plain", "Lecturas borradas"); // Confirmación simple Serial.println("Lecturas borradas y variables reiniciadas"); }); // Iniciar el servidor HTTP server.begin(); Serial.println("Servidor web iniciado"); } // fin setup() // ===================== LOOP ===================== void loop() { // Procesa las peticiones entrantes al servidor de forma no bloqueante server.handleClient(); // (Aquí no hacemos lecturas periódicas; las hacemos solo cuando el usuario presiona "Obtener Lecturas") }
Este código convierte la UNIT Pulsar ESP32-C6 en un termómetro infrarrojo con interfaz web. Crea una red Wi-Fi propia (“UNIT-Termometro”) donde cualquier dispositivo conectado puede acceder a una página web para obtener temperaturas de objeto y ambiente desde el sensor MLX90614. Los usuarios pueden tomar nuevas lecturas o borrar los datos mostrados con solo pulsar botones en la interfaz. Ideal para medición remota sin contacto.
Una vez cargado el código, abre el monitor serial para verificar que todo funcione correctamente. Si la configuración es correcta, la UNIT Pulsar ESP32-C6 iniciará el SoftAP, activará el sensor y pondrá en marcha el servidor web. Luego, podrás conectarte a la red WiFi generada por la UNIT Pulsar ESP32-C6 y acceder a la interfaz web ingresando la dirección 192.168.4.1 en tu navegador, como se muestra en la siguiente imagen.
![]() | ![]() |
Explicación del código
Si tienes dudas sobre cómo funciona el código, aquí te explico los puntos más importantes.
1. I2C / Sensor
Wire.begin(SDA_PIN, SCL_PIN);
Inicializa el bus I2C usando los pines físicos del UNIT Pulsar ESP32-C6 (GPIO6 y GPIO7). Es importante hacerlo antes de usar la librería del sensor.sensor.begin()
Intenta establecer comunicación I2C con el MLX90614. Si falla, revisa cableado/pullups/voltaje.sensor.getObjectTempCelsius()
/sensor.getAmbientTempCelsius()
Devuelven la temperatura del objeto y la temperatura ambiente en °C. Si obtienes-273.15
indica fallo de lectura (no hay datos válidos).
2. SoftAP (Red autónoma)
WiFi.softAP(ssid, password)
Pone a la UNIT Pulsar ESP32-C6 en modo punto de acceso (crea una red WiFi propia). Conectar un teléfono/PC a esa red permite acceder a la IP del ESP (por defecto192.168.4.1
).WiFi.softAPIP()
Muestra la IP del AP (útil para confirmar).
Consejo: puedes usar WiFi.softAPConfig(local_IP, gateway, subnet)
si quieres forzar exactamente 192.168.4.1
. En la mayoría de casos softAP
usa esa IP por defecto.
3. Servidor HTTP y rutas
WebServer server(80);
crea el servidor.server.on("/", ...)
— entrega la página HTML.server.on("/get", ...)
— al llamar/get
:- Desactiva
clearData
. - Lee el sensor y construye un JSON con las dos temperaturas.
- Devuelve el JSON al navegador.
- Desactiva
server.on("/clear", ...)
— al llamar/clear
:- Setea
clearData = true
y reinicia las variables; devuelve texto confirmando.
- Setea
4. Interfaz web (HTML + JS)
- La interfaz tiene 2
input readonly
para mostrar lecturas y 2 botones. getReading()
envíafetch('/get')
, recibe JSON y actualiza las casillas.clearFields()
llama a/clear
y pone--
en los campos localmente.
5. Diseño responsivo
- CSS con
max-width
y media query para ajustar el layout en móviles. - Botones apilables en pantallas pequeñas.
FUNCIONAMIENTO
En el siguiente video se demuestra el funcionamiento del termómetro.
CONCLUSIONES
Has desarrollado un termómetro IR autónomo que combina simplicidad y funcionalidad. Utilizando la UNIT Pulsar ESP32-C6 y el sensor MLX90614 de DFRobot, lograste crear un dispositivo con red WiFi propia (SoftAP) y una interfaz web responsiva que permite obtener y borrar lecturas fácilmente desde cualquier dispositivo.
Gracias a su diseño eficiente y estable, este proyecto es ideal como prototipo para makers o como base para aplicaciones industriales ligeras, como estaciones de monitoreo o pruebas locales sin necesidad de conectividad externa. Además, ofrece un gran potencial para expandirse, incorporando funciones como registro de datos, alertas por umbrales, integración con MQTT, o mejoras en la interfaz de usuario para proyectos más avanzados.