Objectives
- Build a standalone dashboard: the M5Stack Core subscribes to an MQTT broker and displays temperature, humidity, and battery level in real time on its 320×240 screen.
- Use PubSubClient with 2.4 GHz Wi-Fi, automatic reconnection, and a receive callback.
- Publish the battery state (IP5306) and RSSI to status topics yourself.
- Structure the display into zones (gauge, values, connection indicator) that are redrawn only upon reception.
Hardware
- 1 M5Stack Core + 2.4 GHz Wi-Fi.
- 1 accessible MQTT broker (e.g., Mosquitto on a Raspberry Pi on the network, port 1883).
- Libraries: M5Unified, PubSubClient (Arduino manager).
- A second transmitter for testing (another ESP32, or the mosquitto_pub command).
Complete Code
#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);
}
Expected Verification
- The indicator in the top right turns green when the client is connected to the broker (verify with mosquitto_sub -t '$SYS/broker/clients/connected').
- mosquitto_pub -t salon/temperature -m 23.5 updates the value and the orange gauge on the screen in less than one second.
- The topic m5core/batterie receives the battery level every 2 s.
Common Errors
- Broker unreachable: check the IP, ensure port 1883 is open, and verify that the broker is listening on the network (not just localhost).
- mqtt.loop never called outside setup: messages never arrive and the connection is declared lost by the broker (keepalive).
- Misspelled topics or QoS/encoding issues: publish in simple ASCII for testing before adding complexity.
- Disconnecting from Wi-Fi without reconnecting: keep the !mqtt.connected test in loop with reconnection logic, otherwise the screen freezes on the old value.
- Overloading the display on every message: redraw at most once per second (using a timer) to maintain button responsiveness.
- Forgetting that ADC2 is unavailable when Wi-Fi is active: connect analog sensors to ADC1 (G32-39).