
ESP32 publicando datos en Mosquitto
Paso a paso para conectar un ESP32 a un broker MQTT Eclipse Mosquitto, gestionando la autenticación y el formato JSON de la telemetría.
Objetivo y arquitectura
Este tutorial construye un flujo pequeño y autenticado para publicar telemetría de un ESP32 en un broker Eclipse Mosquitto alojado en Ubuntu. El flujo es:
| 1 | ESP32 -> Wi-Fi -> Mosquitto -> mosquitto_sub / aplicación supervisora |
El ejemplo usa MQTT 3.1.1, un tópico propio del dispositivo y una carga JSON pequeña. Los usuarios, contraseñas, dirección IP y SSID son marcadores: sustitúyelos localmente y nunca publiques credenciales en el firmware o en el repositorio.
Instalar Mosquitto en Ubuntu
En un host Ubuntu bajo tu control, instala el broker y los clientes de prueba:
| 1 | sudo apt update |
| 2 | sudo apt install mosquitto mosquitto-clients |
| 3 | sudo systemctl enable --now mosquitto |
| 4 | sudo systemctl status mosquitto |
Para una instalación de homologación, confirma que el puerto MQTT está escuchando:
| 1 | sudo ss -ltnp | grep 1883 |
No expongas un broker anónimo directamente a internet. Incluso en una red industrial, trátalo como un servicio autenticado y restringe el firewall a la red necesaria.
Crear un usuario y exigir autenticación
Crea el archivo de contraseñas con el comando oficial mosquitto_passwd. La contraseña se introduce de forma interactiva:
| 1 | sudo mosquitto_passwd -c /etc/mosquitto/passwd esp32-homolog |
| 2 | sudo chown mosquitto:mosquitto /etc/mosquitto/passwd |
| 3 | sudo chmod 640 /etc/mosquitto/passwd |
Crea un archivo de configuración separado, por ejemplo /etc/mosquitto/conf.d/iiot.conf:
| 1 | listener 1883 |
| 2 | allow_anonymous false |
| 3 | password_file /etc/mosquitto/passwd |
Reinicia el servicio y revisa sus registros:
| 1 | sudo systemctl restart mosquitto |
| 2 | sudo journalctl -u mosquitto -n 50 --no-pager |
Para producción o redes no confiables, configura TLS y usa el puerto 8883 con certificados válidos. El puerto 1883 de este tutorial es para una red de homologación protegida.
Probar el broker antes del ESP32
Abre un terminal suscriptor:
| 1 | mosquitto_sub -h 192.168.1.10 -p 1883 \ |
| 2 | -u esp32-homolog -P 'CONTRASENA_LOCAL' \ |
| 3 | -t 'iiot/esp32/esp32-01/telemetria' -v |
En otro terminal, publica un mensaje:
| 1 | mosquitto_pub -h 192.168.1.10 -p 1883 \ |
| 2 | -u esp32-homolog -P 'CONTRASENA_LOCAL' \ |
| 3 | -t 'iiot/esp32/esp32-01/telemetria' \ |
| 4 | -m '{"device":"esp32-01","temperature":24.7,"rssi":-61}' |
Si el mensaje aparece en el primer terminal, la dirección, el puerto, la autenticación y el tópico coinciden. 192.168.1.10 es solo un ejemplo de red local; usa la dirección real del broker.
Configurar el proyecto PlatformIO
En platformio.ini, declara PubSubClient:
| 1 | [env:esp32dev] |
| 2 | platform = espressif32 |
| 3 | board = esp32dev |
| 4 | framework = arduino |
| 5 | monitor_speed = 115200 |
| 6 | lib_deps = |
| 7 | knolleary/PubSubClient |
El ejemplo siguiente usa WiFiClient y PubSubClient. Reconecta sin atrapar el loop en un while infinito y publica una carga JSON compacta:
| 1 | #include <Arduino.h> |
| 2 | #include <WiFi.h> |
| 3 | #include <PubSubClient.h> |
| 4 | |
| 5 | const char* WIFI_SSID = "SSID_LOCAL"; |
| 6 | const char* WIFI_PASSWORD = "CONTRASENA_WIFI"; |
| 7 | const char* MQTT_HOST = "192.168.1.10"; |
| 8 | const uint16_t MQTT_PORT = 1883; |
| 9 | const char* MQTT_USER = "esp32-homolog"; |
| 10 | const char* MQTT_PASSWORD = "CONTRASENA_MQTT"; |
| 11 | const char* MQTT_TOPIC = "iiot/esp32/esp32-01/telemetria"; |
| 12 | |
| 13 | WiFiClient network; |
| 14 | PubSubClient mqtt(network); |
| 15 | unsigned long lastMqttAttempt = 0; |
| 16 | unsigned long lastPublish = 0; |
| 17 | |
| 18 | void connectWifi() { |
| 19 | if (WiFi.status() == WL_CONNECTED) return; |
| 20 | WiFi.begin(WIFI_SSID, WIFI_PASSWORD); |
| 21 | } |
| 22 | |
| 23 | void connectMqtt() { |
| 24 | if (WiFi.status() != WL_CONNECTED || mqtt.connected()) return; |
| 25 | if (millis() - lastMqttAttempt < 5000) return; |
| 26 | |
| 27 | lastMqttAttempt = millis(); |
| 28 | const char* clientId = "esp32-01"; |
| 29 | if (mqtt.connect(clientId, MQTT_USER, MQTT_PASSWORD)) { |
| 30 | Serial.println("MQTT conectado"); |
| 31 | } else { |
| 32 | Serial.printf("MQTT rechazado, rc=%d\n", mqtt.state()); |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | void publishTelemetry() { |
| 37 | if (!mqtt.connected()) return; |
| 38 | |
| 39 | char payload[128]; |
| 40 | const float temperature = 24.7f; // reemplaza por la lectura del sensor |
| 41 | snprintf(payload, sizeof(payload), |
| 42 | "{\"device\":\"esp32-01\",\"temperature\":%.2f,\"rssi\":%d}", |
| 43 | temperature, WiFi.RSSI()); |
| 44 | |
| 45 | if (!mqtt.publish(MQTT_TOPIC, payload)) { |
| 46 | Serial.println("Falló la publicación de telemetría"); |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | void setup() { |
| 51 | Serial.begin(115200); |
| 52 | mqtt.setServer(MQTT_HOST, MQTT_PORT); |
| 53 | connectWifi(); |
| 54 | } |
| 55 | |
| 56 | void loop() { |
| 57 | connectWifi(); |
| 58 | connectMqtt(); |
| 59 | mqtt.loop(); |
| 60 | |
| 61 | if (millis() - lastPublish >= 10000) { |
| 62 | lastPublish = millis(); |
| 63 | publishTelemetry(); |
| 64 | } |
| 65 | } |
Llama a mqtt.loop() con frecuencia. Procesa el protocolo y mantiene vivo el enlace; un delay largo o una operación bloqueante puede hacer que el broker considere desconectado al cliente. El clientId también debe ser único por placa.
Diagnóstico rápido
- rc=4 normalmente indica un usuario o contraseña incorrectos.
- rc=5 significa que el broker rechazó la autorización.
- rc=-2 apunta a un fallo al resolver el host o abrir la conexión.
- rc=-4 suele ser un timeout: revisa IP, puerto, ruta y firewall.
- Si el suscriptor no recibe nada, compara el tópico carácter por carácter.
- PubSubClient tiene un buffer pequeño por defecto; para JSON mayores, ajústalo explícitamente con mqtt.setBufferSize(512) y valida el tamaño antes de publicar.
Seguridad y operación
No pongas contraseñas reales en el código fuente, los commits o los ejemplos públicos. En una red no confiable, cambia a TLS en el puerto 8883, valida el certificado del broker y configura ACLs con el menor privilegio necesario. En producción, monitoriza el espacio en disco, los registros, los reinicios y la cantidad de clientes; la autenticación no sustituye la segmentación de red ni las copias de seguridad de la configuración.
Fuentes oficiales
- Eclipse Mosquitto — métodos de autenticación
- Eclipse Mosquitto — referencia de mosquitto.conf
- Eclipse Mosquitto — mosquitto_passwd
- Eclipse Mosquitto — mosquitto_pub y mosquitto_sub
- PubSubClient — repositorio y limitaciones
