ESP32 y Arduino

Tutorial Arduino UNO R4 WiFi MQTT: publica datos de sensores con ArduinoMqttClient

Conecta el Arduino UNO R4 WiFi a un broker MQTT con WiFiS3 y ArduinoMqttClient, publica lecturas analógicas, controla la matriz LED desde tu PC y pasa a TLS en el puerto 8883.

Placa Arduino UNO R4 WiFi con su matriz LED encendida, ilustrando una conexión Arduino UNO R4 WiFi MQTT con la nube
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

El Arduino UNO R4 WiFi lleva el Wi-Fi al conocido formato UNO, lo que lo convierte en una gran primera placa para un proyecto Arduino UNO R4 WiFi MQTT. En este tutorial usarás la librería WiFiS3 y la librería oficial ArduinoMqttClient para publicar lecturas de un sensor analógico, recibir comandos que dibujan en la matriz LED integrada y después pasar a una conexión TLS cifrada con tus propias credenciales.

Cómo se comunica el UNO R4 WiFi con la red

El UNO R4 WiFi tiene dos chips. El microcontrolador principal es un Renesas RA4M1 que ejecuta tu sketch. De la red se encarga un módulo ESP32-S3 que actúa como coprocesador Wi-Fi. Tu sketch se comunica con él a través de la librería WiFiS3, que viene con el paquete "Arduino UNO R4 Boards".

Esta división tiene dos consecuencias prácticas:

  1. El handshake TLS se ejecuta en el módulo ESP32-S3, que incluye un paquete de certificados raíz habituales. Las conexiones cifradas con brokers que usan certificados de confianza amplia, como Let's Encrypt, suelen funcionar con WiFiSSLClient sin pegar ningún certificado.
  2. El coprocesador tiene su propio firmware. Si las conexiones se comportan de forma extraña, actualizar ese firmware es una de las primeras soluciones que conviene probar.

Para el protocolo MQTT en sí usarás ArduinoMqttClient, la librería oficial que mantiene Arduino. Funciona con cualquier objeto Client, incluidos WiFiClient y WiFiSSLClient de WiFiS3.

Qué necesitas

Elemento Notas
Arduino UNO R4 WiFi No el UNO R4 Minima, que no tiene radio
Arduino IDE 2.x Con "Arduino UNO R4 Boards" instalado desde el Gestor de tarjetas
ArduinoMqttClient Instálala desde el Gestor de librerías
Un potenciómetro o cualquier sensor analógico Conectado a A0 (opcional, el código funciona con el pin al aire)
Herramientas CLI de Mosquitto Para hacer pruebas desde tu PC
Una red Wi-Fi de 2,4 GHz El módulo no se une a redes de 5 GHz

Antes de empezar, abre Archivo → Ejemplos → WiFiS3 → CheckFirmwareVersion y súbelo. Si el monitor serie indica un firmware desactualizado, actualízalo con el actualizador de firmware del Arduino IDE (Herramientas → Firmware Updater) o siguiendo las instrucciones oficiales de docs.arduino.cc.

Paso 1: publica en el servidor público gratuito

La primera versión se conecta sin cifrado a broker.connectmq.com en el puerto 1883, el servidor MQTT público gratuito que ofrece ConnectMQ para pruebas y prototipos. Se aceptan conexiones anónimas siempre que el client ID no esté vacío. Usa un prefijo de topic único y no envíes datos privados ni de producción, porque cualquiera puede suscribirse al área pública.

Crea una segunda pestaña en el sketch llamada arduino_secrets.h:

#define SECRET_SSID "YOUR_WIFI"
#define SECRET_PASS "YOUR_WIFI_PASSWORD"

Y después el sketch principal:

#include <WiFiS3.h>
#include <ArduinoMqttClient.h>
#include "Arduino_LED_Matrix.h"
#include "arduino_secrets.h"

const char broker[] = "broker.connectmq.com";
const int  port     = 1883;

const char deviceId[]       = "unor4-8d21f0";   // hazlo único
const char topicTelemetry[] = "connectmq/demo/unor4-8d21f0/telemetry";
const char topicCommand[]   = "connectmq/demo/unor4-8d21f0/matrix/set";
const char topicStatus[]    = "connectmq/demo/unor4-8d21f0/status";

WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
ArduinoLEDMatrix matrix;

unsigned long lastPublish = 0;

// Dos fotogramas sencillos para la matriz de 12x8
const uint32_t FRAME_ON[]  = { 0xffffffff, 0xffffffff, 0xffffffff };
const uint32_t FRAME_OFF[] = { 0x00000000, 0x00000000, 0x00000000 };

void connectWifi() {
  Serial.print("Connecting to ");
  Serial.println(SECRET_SSID);
  while (WiFi.begin(SECRET_SSID, SECRET_PASS) != WL_CONNECTED) {
    Serial.print(".");
    delay(3000);
  }
  // WiFiS3 puede indicar 0.0.0.0 durante un momento; espera a una dirección real
  while (WiFi.localIP() == IPAddress(0, 0, 0, 0)) delay(200);
  Serial.print("\nIP address: ");
  Serial.println(WiFi.localIP());
}

void onMqttMessage(int messageSize) {
  String topic = mqttClient.messageTopic();
  String payload;
  while (mqttClient.available()) {
    payload += (char)mqttClient.read();
  }
  Serial.print("Received on ");
  Serial.print(topic);
  Serial.print(": ");
  Serial.println(payload);

  if (payload == "ON")  matrix.loadFrame(FRAME_ON);
  if (payload == "OFF") matrix.loadFrame(FRAME_OFF);
}

bool connectMqtt() {
  mqttClient.setId(deviceId);
  mqttClient.setKeepAliveInterval(30 * 1000L);   // milisegundos

  // El Last Will debe configurarse antes de connect()
  mqttClient.beginWill(topicStatus, true, 1);
  mqttClient.print("offline");
  mqttClient.endWill();

  Serial.print("Connecting to MQTT broker... ");
  if (!mqttClient.connect(broker, port)) {
    Serial.print("failed, error = ");
    Serial.println(mqttClient.connectError());
    return false;
  }
  Serial.println("connected");

  mqttClient.onMessage(onMqttMessage);
  mqttClient.subscribe(topicCommand, 1);

  mqttClient.beginMessage(topicStatus, true, 1);   // retenido, QoS 1
  mqttClient.print("online");
  mqttClient.endMessage();
  return true;
}

void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 3000) {}
  matrix.begin();
  connectWifi();
  while (!connectMqtt()) delay(5000);
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) connectWifi();
  if (!mqttClient.connected()) {
    delay(5000);
    connectMqtt();
    return;
  }

  mqttClient.poll();   // envía los pings de keep alive y entrega los mensajes

  if (millis() - lastPublish > 5000) {
    lastPublish = millis();
    int raw = analogRead(A0);
    mqttClient.beginMessage(topicTelemetry);
    mqttClient.print("{\"a0\":");
    mqttClient.print(raw);
    mqttClient.print(",\"rssi\":");
    mqttClient.print(WiFi.RSSI());
    mqttClient.print(",\"uptime\":");
    mqttClient.print(millis() / 1000);
    mqttClient.print("}");
    mqttClient.endMessage();
  }
}

Observa los mensajes y dibuja en la matriz desde tu PC:

mosquitto_sub -h broker.connectmq.com -p 1883 -i pc-8d21f0 -t "connectmq/demo/unor4-8d21f0/#" -v
mosquitto_pub -h broker.connectmq.com -p 1883 -i ctl-8d21f0 -t "connectmq/demo/unor4-8d21f0/matrix/set" -m ON

Gira el potenciómetro y el valor a0 debería seguirlo en menos de cinco segundos.

En qué se diferencia ArduinoMqttClient de PubSubClient

Si ya has usado PubSubClient, notarás tres diferencias:

  • Los mensajes se envían en streaming. beginMessage(), print() y endMessage() te permiten construir un payload por partes sin un gran buffer de cadena. Eso encaja muy bien con la RAM del UNO R4.
  • Los mensajes entrantes se leen como un stream. El callback onMessage solo recibe el tamaño; llamas a messageTopic() y después a read() hasta que available() devuelva cero.
  • Se admite publicar con QoS 1 y 2, además de los retained messages y un Last Will construido con beginWill()/endWill().

Aun así, debes llamar a poll() con regularidad, igual que llamas a loop() en PubSubClient. Las llamadas largas a delay() en loop() retrasan los pings de keep alive y los mensajes entrantes. Nuestra guía de la librería ArduinoMqttClient cubre toda la API, incluido el significado de cada valor de connectError().

Paso 2: Arduino UNO R4 WiFi MQTT sobre TLS

Para cualquier cosa que vaya más allá de los experimentos, usa un broker privado con credenciales y TLS. En un broker MQTT gestionado como ConnectMQ, creas un broker en el portal y recibes un usuario, una contraseña y un client ID. Gracias al paquete de certificados del módulo Wi-Fi, pasar a TLS solo requiere cambiar unas pocas líneas:

WiFiSSLClient wifiClient;            // antes WiFiClient
MqttClient mqttClient(wifiClient);

const char broker[] = "broker.connectmq.com";
const int  port     = 8883;          // MQTT sobre TLS

bool connectMqtt() {
  mqttClient.setId("YOUR_CLIENT_ID");
  mqttClient.setUsernamePassword("YOUR_USERNAME", "YOUR_PASSWORD");
  mqttClient.setKeepAliveInterval(30 * 1000L);
  if (!mqttClient.connect(broker, port)) {
    Serial.print("TLS MQTT failed, error = ");
    Serial.println(mqttClient.connectError());
    return false;
  }
  // suscríbete y publica como antes
  return true;
}

Guarda las credenciales en arduino_secrets.h y no en el sketch principal para no subirlas al repositorio por error. ConnectMQ vincula los client IDs a las credenciales emitidas, así que copia el client ID exactamente. En un broker privado también puedes prescindir del prefijo connectmq/demo/ y diseñar un árbol de topics para tu proyecto. El artículo de buenas prácticas de seguridad MQTT enumera más medidas de refuerzo.

Diseña topics y payloads que escalen

Una sola placa en el servidor público puede usar cualquier estructura, pero compensa diseñar los topics como si el mes que viene fueras a tener diez placas. Una estructura predecible permite que los dashboards se suscriban con comodines y mantiene los comandos claramente separados de la telemetría.

Topic Dirección QoS Retenido Finalidad
<prefix>/<deviceId>/telemetry La placa publica 0 No Lecturas periódicas de sensores
<prefix>/<deviceId>/status La placa publica, Will 1 Sí Presencia online / offline
<prefix>/<deviceId>/matrix/set La placa se suscribe 1 No Comandos desde apps o scripts
<prefix>/<deviceId>/config La placa se suscribe 1 Sí Ajustes aplicados en cada arranque

El topic config retenido es un truco muy práctico: publica una vez el intervalo de publicación o el umbral deseados con el flag retain, y cada vez que la placa se reconecte recibirá al instante los ajustes más recientes, sin lógica de petición adicional en tu firmware.

Mantén los payloads compactos. El RA4M1 del UNO R4 tiene 32 KB de SRAM, una cantidad generosa comparada con el UNO clásico pero aún pequeña, así que evita construir objetos String grandes en sketches de larga duración. Enviar en streaming con print(), como hace el ejemplo, mantiene estable el uso de memoria. Para entradas analógicas con ruido, promedia varias muestras de analogRead() antes de publicar y plantéate publicar solo cuando el valor cambie más allá de un pequeño umbral. Menos mensajes y más significativos son más amables con la red y más fáciles de leer en un dashboard.

Lista de comprobación para solucionar problemas

  1. connectError() devuelve -2 (conexión rechazada) o la llamada a connect falla al instante: host o puerto incorrectos, o no hay Wi-Fi. Confirma que la placa tiene una dirección IP real, no 0.0.0.0.
  2. El 1883 sin cifrar funciona pero el 8883 falla: actualiza el firmware del módulo Wi-Fi y asegúrate de haber usado WiFiSSLClient en lugar de WiFiClient.
  3. Error 4 (usuario o contraseña incorrectos) o 5 (sin autorización): revisa de nuevo los tres valores del portal, incluido el client ID.
  4. La conexión se corta al cabo de un rato: una llamada bloqueante en loop() impidió que se ejecutara poll(), u otro dispositivo usa el mismo client ID.
  5. No llegan mensajes entrantes: no se registró onMessage() o te suscribiste antes de que connect() tuviera éxito.
  6. La subida funciona pero el monitor serie sigue vacío: configura el monitor a 115200 baudios; el R4 usa USB nativo, así que abre el monitor cuando termine la subida.

Siguientes pasos

Cuando tengas una conexión fiable, añade un sensor real y crea un dashboard. Si necesitas más GPIO, Bluetooth o procesamiento local, quizá te convenga más un ESP32; el tutorial de IoT con ESP32 recorre un proyecto completo. Si tienes otro Arduino, la guía de Arduino Nano 33 IoT MQTT sigue el mismo patrón de librería con WiFiNINA.

Conecta tu UNO R4 con ConnectMQ

ConnectMQ es un broker MQTT en la nube compatible con MQTT 3.1.1 y 5.0, TLS en el 8883 y WebSockets para dashboards en el navegador. El portal incluye un cliente MQTT en el navegador y un explorador de topics en vivo para que veas llegar las lecturas de tu UNO. Crea un broker Serverless gratuito en app.connectmq.com sin tarjeta de crédito y pasa hoy mismo tu sketch a TLS.

Preguntas frecuentes

¿Tengo que cargar un certificado raíz en el UNO R4 WiFi?

Normalmente no. El módulo Wi-Fi ESP32-S3 incluye un paquete de certificados raíz habituales, así que WiFiSSLClient puede verificar brokers que usan autoridades de confianza amplia como Let's Encrypt. Si la verificación falla, actualiza primero el firmware del módulo.

¿Puedo usar PubSubClient en el UNO R4 WiFi?

Sí, PubSubClient funciona con cualquier Client de Arduino, incluidos los clientes de WiFiS3. ArduinoMqttClient es la opción con soporte oficial y añade la publicación con QoS 1 y 2.

¿Admite MQTT 5 el UNO R4 WiFi?

ArduinoMqttClient implementa MQTT 3.1.1, que ConnectMQ admite por completo junto con MQTT 5. Tus dashboards y backends MQTT 5 pueden suscribirse a los mismos topics.

¿Por qué mi UNO R4 WiFi muestra la IP 0.0.0.0?

WiFiS3 puede indicar que está conectado antes de que termine el DHCP. Espera hasta que WiFi.localIP() devuelva una dirección real antes de conectarte al broker, como hace el ejemplo.

Artículos relacionados

Ejemplo de ESP-IDF MQTT: crea un cliente esp-mqtt desde cero

Construye un proyecto ESP-IDF desde una carpeta vacía con el componente esp-mqtt: configuración de Wi-Fi en modo estación, el manejador de eventos MQTT, publicación y suscripción, propiedades de MQTT 5 y TLS con el bundle de certificados.

9 min de lectura

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.