ArduinoMqttClient es la librería MQTT oficial que mantiene Arduino, y funciona en todo tipo de placas, desde el UNO R4 WiFi y el Nano 33 IoT hasta las placas MKR y el ESP32. Esta guía recorre la API de ArduinoMqttClient en el orden en que la usarás: configurar, conectar, hacer poll, publicar, recibir y definir un mensaje Will. Todos los ejemplos se conectan a un broker real para que puedas probar mientras lees.
Por qué elegir ArduinoMqttClient
ArduinoMqttClient envuelve cualquier objeto Client de Arduino, como WiFiClient, WiFiSSLClient, EthernetClient o un cliente celular, y añade MQTT 3.1.1 por encima. Su decisión de diseño más destacada es que tanto los mensajes salientes como los entrantes se tratan como streams, así que nunca necesitas un buffer del tamaño de tu mensaje más grande.
| Capacidad | ArduinoMqttClient |
|---|---|
| Protocolo | MQTT 3.1.1 |
| QoS de publicación | 0, 1 y 2 |
| QoS de suscripción | 0, 1 y 2 |
| Retained messages | Sí |
| Mensaje Will | Sí, en streaming con beginWill() / endWill() |
| Gestión del payload | En streaming (print() / read()) |
| Modelo de eventos | Polling con poll(), callback al recibir mensajes |
| Mantenedor | Arduino |
Si ya conoces PubSubClient, el tutorial de PubSubClient para Arduino es un buen punto de comparación; las dos librerías resuelven el mismo problema con distintas ventajas e inconvenientes.
Instalar la librería
Abre Herramientas → Gestionar bibliotecas en el Arduino IDE, busca "ArduinoMqttClient" e instálala. También necesitas la librería de red de tu placa:
| Placa | Librería de red | Cliente sin cifrar | Cliente TLS |
|---|---|---|---|
| UNO R4 WiFi | WiFiS3 | WiFiClient |
WiFiSSLClient |
| Nano 33 IoT, MKR WiFi 1010 | WiFiNINA | WiFiClient |
WiFiSSLClient |
| ESP32 | WiFi (núcleo) | WiFiClient |
WiFiClientSecure |
| Placas con shield Ethernet | Ethernet | EthernetClient |
No integrado |
Configurar el cliente
Crea primero el cliente de red y pásalo después a MqttClient:
#include <WiFiNINA.h> // o WiFiS3.h, WiFi.h ...
#include <ArduinoMqttClient.h>
WiFiClient net;
MqttClient mqttClient(net);
Antes de llamar a connect(), configura los parámetros de la sesión:
mqttClient.setId("acm-51e09b"); // client ID, nunca vacío
mqttClient.setUsernamePassword("YOUR_USERNAME", "YOUR_PASSWORD"); // opcional
mqttClient.setKeepAliveInterval(30 * 1000L); // ¡milisegundos!
mqttClient.setConnectionTimeout(10 * 1000L); // milisegundos
mqttClient.setCleanSession(true);
Atención a las unidades: a diferencia de PubSubClient, los valores de keep alive y de timeout van en milisegundos. Pasar 30 en lugar de 30000 se convierte en un keep alive de cero segundos tras la división entera, lo que desactiva por completo el keep alive, de modo que el broker no detecta las conexiones muertas y tu mensaje Will nunca se dispara.
Conectar y leer connectError()
connect(host, port) devuelve 1 si tiene éxito y 0 si falla. Cuando falla, connectError() te dice por qué:
| connectError() | Constante | Significado y solución |
|---|---|---|
| -2 | MQTT_CONNECTION_REFUSED |
No se pudo abrir el socket: problema de Wi-Fi, DNS, puerto o TLS |
| -1 | MQTT_CONNECTION_TIMEOUT |
No llegó el CONNACK a tiempo: tipo de puerto incorrecto o enlace deficiente |
| 0 | MQTT_SUCCESS |
Conectado |
| 1 | MQTT_UNACCEPTABLE_PROTOCOL_VERSION |
El broker rechazó MQTT 3.1.1 (poco frecuente) |
| 2 | MQTT_IDENTIFIER_REJECTED |
Client ID vacío o no permitido |
| 3 | MQTT_SERVER_UNAVAILABLE |
El broker no acepta conexiones en este momento |
| 4 | MQTT_BAD_USER_NAME_OR_PASSWORD |
Credenciales incorrectas |
| 5 | MQTT_NOT_AUTHORIZED |
Cliente no permitido, p. ej. el client ID no coincide con las credenciales |
Una función de conexión completa y reutilizable:
bool connectMqtt(const char* host, int port) {
Serial.print("Connecting to ");
Serial.print(host);
Serial.print(':');
Serial.println(port);
if (!mqttClient.connect(host, port)) {
Serial.print("MQTT connect failed, connectError = ");
Serial.println(mqttClient.connectError());
return false;
}
Serial.println("MQTT connected");
return true;
}
Para probar, usa broker.connectmq.com en el puerto 1883, el servidor MQTT público gratuito de ConnectMQ. Acepta conexiones anónimas con cualquier client ID único y no vacío. Está pensado para pruebas y prototipos, no para datos de producción: mantén tus topics bajo un prefijo único como connectmq/demo/<your-id>/ y no publiques nada sensible.
Por qué importa poll()
poll() es el latido de ArduinoMqttClient. Cada llamada:
- Lee los bytes entrantes del cliente de red y analiza los paquetes completos.
- Llama a tu callback
onMessage(o deja el mensaje disponible paraparseMessage()). - Responde a los handshakes de QoS 1 y QoS 2 de los mensajes entrantes.
- Envía un PINGREQ cuando el intervalo de keep alive está a punto de vencer.
Si no se llama a poll() durante más tiempo que el intervalo de keep alive, el broker cierra la conexión. Evita llamadas a delay() más largas que una fracción de tu keep alive y sustitúyelas por temporización basada en millis():
unsigned long lastSend = 0;
void loop() {
mqttClient.poll();
if (millis() - lastSend >= 10000) {
lastSend = millis();
// publica aquí
}
}
Publicar mensajes
Publicar es un stream en tres pasos:
// Mensaje QoS 0 simple
mqttClient.beginMessage("connectmq/demo/acm-51e09b/temperature");
mqttClient.print(22.7);
mqttClient.endMessage();
// Retenido, QoS 1
mqttClient.beginMessage("connectmq/demo/acm-51e09b/status", true, 1);
mqttClient.print("online");
mqttClient.endMessage();
La firma completa es beginMessage(topic, retain = false, qos = 0, dup = false). También hay una sobrecarga que recibe de antemano el tamaño del payload, beginMessage(topic, size, retain, qos, dup). Cuando conozcas el tamaño exacto, úsala: la librería puede escribir los datos directamente en la red en lugar de almacenar antes todo el mensaje, algo importante con payloads grandes en placas con poca RAM.
endMessage() devuelve 1 si tiene éxito. Con QoS 1 y 2, la librería gestiona los paquetes de confirmación durante las llamadas posteriores a poll().
Como print() acepta números, cadenas y floats, puedes construir JSON sin un buffer temporal:
mqttClient.beginMessage(topicTelemetry);
mqttClient.print("{\"t\":");
mqttClient.print(temperature, 2);
mqttClient.print(",\"h\":");
mqttClient.print(humidity, 1);
mqttClient.print("}");
mqttClient.endMessage();
Recibir mensajes
Suscríbete tras una conexión correcta, y de nuevo tras cada reconexión cuando uses una sesión limpia:
mqttClient.onMessage(onMqttMessage);
mqttClient.subscribe("connectmq/demo/acm-51e09b/cmd/#", 1);
El callback solo recibe el tamaño del mensaje. Tú lees el topic y el payload en streaming:
void onMqttMessage(int messageSize) {
String topic = mqttClient.messageTopic();
Serial.print("Topic: ");
Serial.print(topic);
Serial.print(", QoS ");
Serial.print(mqttClient.messageQoS());
Serial.print(", retained ");
Serial.println(mqttClient.messageRetain());
char payload[128];
int n = 0;
while (mqttClient.available() && n < (int)sizeof(payload) - 1) {
payload[n++] = (char)mqttClient.read();
}
payload[n] = '\0';
Serial.println(payload);
}
Los bytes que no leas se descartan cuando llega el siguiente mensaje. Eso hace que los mensajes demasiado grandes sean seguros: simplemente dejas de leer al llegar al límite de tu buffer.
Como alternativa al callback, puedes llamar a int size = mqttClient.parseMessage(); en loop() y gestionar los mensajes en línea cuando size sea mayor que cero. Usa un estilo u otro, no ambos.
Mensajes Will
El broker publica un mensaje Will (Last Will and Testament) si tu dispositivo se desconecta sin despedirse, por ejemplo tras un corte de luz o una pérdida del Wi-Fi. Configúralo antes de connect():
const char willTopic[] = "connectmq/demo/acm-51e09b/status";
mqttClient.beginWill(willTopic, true, 1); // retenido, QoS 1
mqttClient.print("offline");
mqttClient.endWill();
if (connectMqtt("broker.connectmq.com", 1883)) {
mqttClient.beginMessage(willTopic, true, 1);
mqttClient.print("online");
mqttClient.endMessage();
}
Publicar un online retenido en el mismo topic justo después de conectar proporciona a todos los dashboards un indicador de presencia preciso: online mientras está conectado y offline en cuanto el broker detecta que el dispositivo ha desaparecido, lo que ocurre tras aproximadamente un intervalo y medio de keep alive.
Un patrón completo y seguro ante reconexiones
Junta todas las piezas con esta lista:
- Conecta el Wi-Fi y espera a tener una dirección IP válida.
- Configura el ID, las credenciales, el keep alive y el Will.
- Conecta; si falla, imprime
connectError()y reintenta tras una espera que crezca con cada fallo. - Si tiene éxito, registra
onMessage, suscríbete y publicaonlineretenido. - En
loop(), comprueba el Wi-Fi, compruebamqttClient.connected(), llama apoll()y publica con un temporizador basado enmillis().
Tienes versiones de este patrón para placas concretas en el tutorial de Arduino UNO R4 WiFi MQTT y en la guía de Nano 33 IoT MQTT con WiFiNINA. Para un proyecto más amplio, el tutorial de IoT con ESP32 muestra cómo encaja el lado del dispositivo con dashboards y alertas.
Errores habituales con ArduinoMqttClient
- Llamar a
beginWill()después deconnect(). El Will forma parte del paquete CONNECT, así que debe configurarse antes. - Suscribirse solo en
setup(). Tras una reconexión con sesión limpia, el broker ha olvidado tus suscripciones. Suscríbete dentro de tu función de conexión. - Reutilizar un mismo client ID en varias placas. El broker desconecta la sesión anterior cada vez que se conecta otra placa, lo que provoca un bucle de reconexión sin fin.
- Publicar desde dentro de
onMessage. Funciona, pero termina primero de leer el payload entrante; si no, los bytes sin leer se pierden. - Olvidar
endMessage(). Sin él no se envía nada, y la siguiente llamada abeginMessage()falla.
Producción: TLS y credenciales
Para despliegues reales, cambia a un cliente TLS y al puerto 8883, y autentícate con tus propias credenciales. Un broker MQTT gestionado como ConnectMQ emite un usuario, una contraseña y un client ID para cada broker que creas en el portal; el client ID está vinculado a esas credenciales, así que configúralo exactamente con setId(). El certificado de ConnectMQ procede de Let's Encrypt, en el que los módulos Wi-Fi de las placas Arduino actuales confían de serie. Revisa las buenas prácticas de seguridad MQTT antes de poner tu proyecto en producción.
Empieza con ConnectMQ
ConnectMQ es un broker MQTT en la nube con MQTT 3.1.1 y 5.0, TLS y WebSockets, además de un portal que incluye un cliente MQTT en el navegador, un explorador de topics en vivo y alertas por umbral. Es la forma más sencilla de ver lo que tu sketch de ArduinoMqttClient envía realmente. Crea un broker Serverless gratuito en app.connectmq.com, sin tarjeta de crédito.
Preguntas frecuentes
¿Es ArduinoMqttClient mejor que PubSubClient?
Ninguna es mejor en todos los casos. ArduinoMqttClient admite publicar con QoS 1 y 2 y envía los payloads en streaming, mientras que PubSubClient es más pequeña y cuenta con una enorme base de ejemplos. Elige ArduinoMqttClient para placas Arduino oficiales y cuando necesites QoS.
¿Admite ArduinoMqttClient MQTT 5?
No, implementa MQTT 3.1.1. Los brokers modernos atienden a clientes 3.1.1 y 5.0 a la vez, así que tu dispositivo puede compartir topics con aplicaciones MQTT 5.
¿Por qué se corta mi conexión de ArduinoMqttClient cada minuto?
Normalmente porque no se llama a poll() con la frecuencia suficiente, porque el keep alive se configuró en segundos en lugar de milisegundos o porque otro cliente usa el mismo client ID.
¿Cuál es el tamaño máximo de mensaje?
La librería envía los payloads en streaming, así que el límite lo pone sobre todo tu broker. El servidor público broker.connectmq.com acepta hasta 64 KB por mensaje; el plan gratuito Serverless permite 256 KB.



