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:
- 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
WiFiSSLClientsin pegar ningún certificado. - 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()yendMessage()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
onMessagesolo recibe el tamaño; llamas amessageTopic()y después aread()hasta queavailable()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
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.- El 1883 sin cifrar funciona pero el 8883 falla: actualiza el firmware del módulo Wi-Fi y asegúrate de haber usado
WiFiSSLClienten lugar deWiFiClient. - Error 4 (usuario o contraseña incorrectos) o 5 (sin autorización): revisa de nuevo los tres valores del portal, incluido el client ID.
- La conexión se corta al cabo de un rato: una llamada bloqueante en
loop()impidió que se ejecutarapoll(), u otro dispositivo usa el mismo client ID. - No llegan mensajes entrantes: no se registró
onMessage()o te suscribiste antes de queconnect()tuviera éxito. - 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.



