Objetivos
- Construir un panel de control autónomo: el M5Stack Core se suscribe a un broker MQTT y muestra temperatura, humedad y batería en tiempo real en su pantalla de 320×240.
- Utilizar PubSubClient con Wi-Fi de 2,4 GHz, reconexión automática y callback de recepción.
- Publicar por sí mismo el estado de la batería (IP5306) y el RSSI en topics de estado.
- Estructurar la visualización en zonas (barra de progreso, valores, indicador de conexión) redibujadas únicamente al recibir datos.
Material
- 1 M5Stack Core + Wi-Fi de 2,4 GHz.
- 1 broker MQTT accesible (p. ej., Mosquitto en un Raspberry Pi de la red, puerto 1883).
- Bibliotecas: M5Unified, PubSubClient (gestor de librerías de Arduino).
- Un segundo emisor para probar (otro ESP32, o el comando mosquitto_pub).
Código completo
#include <M5Unified.h>
#include <WiFi.h>
#include <PubSubClient.h>
const char* SSID = "VOTRE_WIFI";
const char* PASS = "VOTRE_MDP";
const char* BROKER = "192.168.1.50"; // Mosquitto sur le reseau
WiFiClient esp;
PubSubClient mqtt(esp);
float temperature = 0; float humidite = 0;
bool connecte = false;
void callback(char* topic, byte* payload, unsigned int n) {
char buf[64]; unsigned int l = (n < 63) ? n : 63;
memcpy(buf, payload, l); buf[l] = 0;
if (!strcmp(topic, "salon/temperature")) temperature = atof(buf);
if (!strcmp(topic, "salon/humidite")) humidite = atof(buf);
}
void setup {
Serial.begin(115200);
auto cfg = M5.config;
M5.begin(cfg);
WiFi.begin(SSID, PASS);
while (WiFi.status != WL_CONNECTED) { delay(300); Serial.print("."); }
mqtt.setServer(BROKER, 1883);
mqtt.setCallback(callback);
M5.Display.setTextSize(2);
}
void publierEtat {
char b[16];
snprintf(b, sizeof(b), "%d", M5.Power.getBatteryLevel);
mqtt.publish("m5core/batterie", (const uint8_t*)b, strlen(b));
}
void dessiner {
M5.Display.fillScreen(TFT_BLACK);
M5.Display.fillCircle(305, 15, 8, connecte ? TFT_GREEN : TFT_RED);
M5.Display.setTextColor(TFT_CYAN);
M5.Display.setCursor(10, 10); M5.Display.printf("T : %5.1f C", temperature);
M5.Display.setCursor(10, 45); M5.Display.printf("H : %5.1f %%", humidite);
M5.Display.setTextColor(TFT_WHITE);
M5.Display.setCursor(10, 80); M5.Display.printf("Bat : %d %%", M5.Power.getBatteryLevel);
M5.Display.drawRect(10, 110, 300, 22, TFT_WHITE);
M5.Display.fillRect(12, 112, 296 * constrain(temperature, 0, 40) / 40, 18, TFT_ORANGE);
}
uint32_t tPrec = 0;
void loop {
if (!mqtt.connected) {
connecte = mqtt.connect("m5core-dashboard");
if (connecte) mqtt.subscribe("salon/#");
}
mqtt.loop;
if (millis - tPrec > 2000) { tPrec = millis; publierEtat; dessiner; }
vTaskDelay(10 / portTICK_PERIOD_MS);
}
Verificación esperada
- El indicador en la esquina superior derecha se pone en verde cuando el cliente está conectado al broker (verificar con mosquitto_sub -t '$SYS/broker/clients/connected').
- mosquitto_pub -t salon/temperature -m 23.5 actualiza el valor y la barra de progreso naranja en la pantalla en menos de un segundo.
- El topic m5core/batterie recibe el nivel de batería cada 2 s.
Errores frecuentes
- Broker inaccesible: verificar la IP, que el puerto 1883 esté abierto y que el broker escuche en la red (no solo en localhost).
- mqtt.loop nunca se llama fuera de setup: los mensajes nunca llegan y la conexión se declara perdida por el broker (keepalive).
- Topics mal escritos o QoS/codificación incorrectos: publicar en ASCII simple para probar antes de complicar la configuración.
- Desconectarse del Wi-Fi sin reconexión: mantener la prueba !mqtt.connected en loop con reconexión; de lo contrario, la pantalla se queda con el valor anterior.
- Sobrecargar la visualización con cada mensaje: redibujar como máximo una vez por segundo (temporizador) para mantener la capacidad de respuesta de los botones.
- Olvidar que el ADC2 está inutilizable con el Wi-Fi activo: conectar los sensores analógicos al ADC1 (G32-39).