L'ESP8266 reste l'un des moyens les moins chers de connecter un capteur en Wi-Fi, et les projets ESP8266 MQTT s'accordent naturellement à son faible encombrement. Dans ce tutoriel, vous allez connecter un NodeMCU ou un Wemos D1 mini à un broker avec PubSubClient, publier de la télémétrie JSON, commander la LED intégrée depuis votre ordinateur, puis passer au TLS sans manquer de mémoire.
Ce dont vous avez besoin
- Un NodeMCU v2/v3, un Wemos D1 mini ou toute carte ESP8266 avec USB.
- L'Arduino IDE 2.x avec le paquet de cartes « esp8266 by ESP8266 Community » (ajoutez
https://arduino.esp8266.com/stable/package_esp8266com_index.jsondans Fichier → Préférences → URL de gestionnaire de cartes supplémentaires). - La bibliothèque PubSubClient de Nick O'Leary, depuis le gestionnaire de bibliothèques.
- Les outils en ligne de commande Mosquitto sur votre ordinateur pour les tests.
- Un réseau Wi-Fi 2,4 GHz. L'ESP8266 ne prend pas en charge le 5 GHz.
Pour les premières étapes, vous utiliserez broker.connectmq.com, le serveur MQTT public gratuit exploité par ConnectMQ. Il accepte les clients anonymes sur le port 1883 avec n'importe quel client ID non vide et unique. Considérez-le comme un panneau d'affichage public : tout ce que vous y publiez peut être lu par d'autres.
Les réglages de carte qui comptent
Avant d'écrire du code, définissez ces paramètres dans le menu Outils :
| Paramètre | Valeur recommandée | Pourquoi |
|---|---|---|
| Carte | NodeMCU 1.0 (ESP-12E Module) ou LOLIN(WEMOS) D1 mini | Bonne organisation de la flash et bons noms de broches |
| Fréquence CPU | 160 MHz pour le TLS, 80 MHz sinon | Les poignées de main TLS sont bien plus rapides à 160 MHz |
| SSL Support | All SSL ciphers (par défaut) ou Basic SSL ciphers | Basic économise de la flash et fonctionne avec les brokers modernes |
| Variante lwIP | v2 Lower Memory | Laisse plus de heap à votre sketch |
| Vitesse de téléversement | 921600 (descendez à 115200 en cas d'échec) | Itérations plus rapides |
Étape 1 : votre premier sketch ESP8266 MQTT
Le sketch ci-dessous utilise la LED intégrée sur GPIO2 (LED_BUILTIN), active à l'état bas sur la plupart des modules. Il publie le temps de fonctionnement, la force du signal et le heap libre toutes les cinq secondes, et écoute les commandes ON ou OFF.
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;
char deviceId[24];
char topicTelemetry[64];
char topicLedSet[64];
char topicLedState[64];
WiFiClient netClient;
PubSubClient mqtt(netClient);
unsigned long lastPublish = 0;
unsigned long lastAttempt = 0;
void setLed(bool on) {
digitalWrite(LED_BUILTIN, on ? LOW : HIGH); // active à l'état bas
mqtt.publish(topicLedState, on ? "ON" : "OFF", true);
}
void onMessage(char* topic, byte* payload, unsigned int length) {
char msg[16];
unsigned int n = length < sizeof(msg) - 1 ? length : sizeof(msg) - 1;
memcpy(msg, payload, n);
msg[n] = '\0';
Serial.printf("[%s] %s\n", topic, msg);
if (strcmp(msg, "ON") == 0) setLed(true);
if (strcmp(msg, "OFF") == 0) setLed(false);
}
void connectWifi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Wi-Fi");
while (WiFi.status() != WL_CONNECTED) {
delay(300);
Serial.print(".");
}
Serial.printf(" connected, IP %s\n", WiFi.localIP().toString().c_str());
}
bool connectMqtt() {
if (mqtt.connect(deviceId, nullptr, nullptr, topicLedState, 1, true, "offline")) {
Serial.println("MQTT connected");
mqtt.subscribe(topicLedSet, 1);
setLed(false);
return true;
}
Serial.printf("MQTT failed, rc=%d\n", mqtt.state());
return false;
}
void setup() {
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
// ID unique dérivé de l'ID de la puce, p. ex. esp8266-3f2a1b
snprintf(deviceId, sizeof(deviceId), "esp8266-%06x", ESP.getChipId());
snprintf(topicTelemetry, sizeof(topicTelemetry), "connectmq/demo/%s/telemetry", deviceId);
snprintf(topicLedSet, sizeof(topicLedSet), "connectmq/demo/%s/led/set", deviceId);
snprintf(topicLedState, sizeof(topicLedState), "connectmq/demo/%s/led/state", deviceId);
Serial.printf("\nDevice ID: %s\n", deviceId);
connectWifi();
mqtt.setServer(MQTT_HOST, MQTT_PORT);
mqtt.setCallback(onMessage);
mqtt.setKeepAlive(30);
}
void loop() {
if (WiFi.status() != WL_CONNECTED) connectWifi();
if (!mqtt.connected()) {
if (millis() - lastAttempt > 5000) {
lastAttempt = millis();
connectMqtt();
}
return;
}
mqtt.loop();
if (millis() - lastPublish > 5000) {
lastPublish = millis();
char payload[96];
snprintf(payload, sizeof(payload), "{\"uptime\":%lu,\"rssi\":%d,\"heap\":%u}",
millis() / 1000, WiFi.RSSI(), ESP.getFreeHeap());
mqtt.publish(topicTelemetry, payload);
}
}
Ouvrez le moniteur série à 115200 bauds et notez l'identifiant de l'appareil, puis abonnez-vous depuis votre ordinateur (remplacez l'ID par le vôtre) :
mosquitto_sub -h broker.connectmq.com -p 1883 -i laptop-3f2a1b -t "connectmq/demo/esp8266-3f2a1b/#" -v
Commandez la LED :
mosquitto_pub -h broker.connectmq.com -p 1883 -i ctl-3f2a1b -t "connectmq/demo/esp8266-3f2a1b/led/set" -m ON
Le topic led/state est un retained message : tout nouvel abonné sait immédiatement si la LED est allumée, et le Last Will le passe à offline si la carte perd son alimentation.
Étape 2 : comprendre le budget mémoire de l'ESP8266
Une fois le sketch en clair fonctionnel, surveillez la valeur heap qu'il publie. Un sketch simple laisse généralement une marge confortable de heap libre, mais le TLS change la donne. Une session BearSSL avec les buffers par défaut a besoin d'un grand bloc de mémoire contigu pour ses buffers de réception et d'émission, en plus du travail de validation des certificats, et l'ESP8266 ne dispose que d'une fraction de la RAM d'un ESP32.
Conséquences pratiques :
- Gardez le buffer PubSubClient aussi petit que vos messages le permettent. Appeler
setBufferSize(4096)« au cas où » peut faire la différence entre une poignée de main réussie et un échec. - Évitez d'abuser de la classe
Stringdans les sketches qui tournent longtemps ; les allocations répétées fragmentent le heap et la poignée de main TLS peut échouer des jours plus tard alors que le heap libre semble correct.ESP.getMaxFreeBlockSize()indique le plus grand bloc contigu, et c'est ce chiffre qui compte. - Construisez le JSON avec
snprintfou un document ArduinoJson de taille fixe plutôt que par concaténation de chaînes.
Si vous avez régulièrement besoin de gros payloads, lisez la taille du buffer PubSubClient pour découvrir des techniques de streaming qui évitent les gros buffers.
Étape 3 : ESP8266 MQTT sur TLS
En production, votre appareil doit se connecter à un broker privé en TLS sur le port 8883 avec ses propres identifiants. Avec un broker MQTT managé comme ConnectMQ, vous obtenez un nom d'utilisateur, un mot de passe et un client ID depuis le portail. Le certificat du serveur est émis par Let's Encrypt : vous faites donc confiance au certificat racine ISRG Root X1.
Le core ESP8266 utilise BearSSL. Contrairement à l'ESP32, il vérifie les dates de validité des certificats : l'horloge doit donc être correcte avant la poignée de main.
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <time.h>
// ISRG Root X1 (racine Let's Encrypt), collez le PEM complet
static const char ROOT_CA[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
...ISRG Root X1...
-----END CERTIFICATE-----
)EOF";
BearSSL::X509List trustAnchors(ROOT_CA);
BearSSL::WiFiClientSecure tlsClient;
PubSubClient mqtt(tlsClient);
void syncClock() {
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
Serial.print("Waiting for NTP");
time_t now = time(nullptr);
while (now < 1700000000) { // n'importe quel horodatage bien passé
delay(250);
Serial.print(".");
now = time(nullptr);
}
Serial.println(" done");
}
void setupTls() {
syncClock();
tlsClient.setTrustAnchors(&trustAnchors);
// Facultatif : buffers plus petits si le serveur prend en charge max fragment length
if (tlsClient.probeMaxFragmentLength("broker.connectmq.com", 8883, 1024)) {
tlsClient.setBufferSizes(1024, 1024);
}
mqtt.setServer("broker.connectmq.com", 8883);
}
bool connectMqtt() {
return mqtt.connect("YOUR_CLIENT_ID", "YOUR_USERNAME", "YOUR_PASSWORD");
}
Appelez setupTls() dans setup() une fois le Wi-Fi connecté. Réglez la fréquence CPU sur 160 MHz : la première poignée de main peut prendre un moment perceptible à 80 MHz, et votre watchdog n'appréciera pas un connect() lent au milieu d'une boucle chargée.
Étape 4 : ESP8266 MQTT sur batterie avec le deep sleep
De nombreux capteurs ESP8266 fonctionnent sur batterie et n'ont besoin de remonter des données que toutes les quelques minutes. La radio est de loin le plus gros consommateur d'énergie ; le schéma gagnant est donc : se réveiller, se connecter, publier, se déconnecter, dormir. Le deep sleep de l'ESP8266 nécessite une liaison matérielle entre GPIO16 (D0 sur NodeMCU et D1 mini) et la broche RST, car la puce se réveille en se réinitialisant elle-même. Débranchez ce fil pendant le téléversement si votre carte se comporte mal lors du flashage.
void publishAndSleep() {
connectWifi();
mqtt.setServer(MQTT_HOST, MQTT_PORT);
if (mqtt.connect(deviceId)) {
char payload[64];
snprintf(payload, sizeof(payload), "{\"a0\":%d,\"rssi\":%d}", analogRead(A0), WiFi.RSSI());
mqtt.publish(topicTelemetry, payload);
// laisser à la pile le temps d'envoyer le paquet avant de couper la radio
for (int i = 0; i < 10; i++) { mqtt.loop(); delay(10); }
mqtt.disconnect();
}
ESP.deepSleep(5 * 60 * 1000000ULL); // 5 minutes, en microsecondes
}
Appelez publishAndSleep() à la fin de setup() et laissez loop() vide. Quelques remarques pratiques : une poignée de main TLS à chaque réveil coûte nettement plus de temps et d'énergie que du MQTT en clair ; pesez donc l'exigence de sécurité face à l'autonomie et envisagez des intervalles de sommeil plus longs avec le TLS. Utilisez un retained message pour la dernière mesure, afin que les tableaux de bord ouverts entre deux réveils affichent quand même une valeur. Et n'utilisez pas de Last Will pour signaler la présence sur les appareils en sommeil : un disconnect() propre ne le déclenche jamais, et un statut « offline » serait de toute façon trompeur.
Dépanner les problèmes ESP8266 MQTT
- rc=-2 en TLS mais tout va bien sur 1883 : horloge non synchronisée, mauvais certificat racine ou heap contigu insuffisant. Affichez
tlsClient.getLastSSLError()pour obtenir la raison donnée par BearSSL. Notre guide PubSubClient rc=-2 couvre tous les codes. - Redémarrages aléatoires (
wdt reset) : quelque chose bloque trop longtemps. Ne mettez jamais de longs appels àdelay()dans le callback MQTT, et appelezyield()dans les boucles longues. - La carte ne rejoint jamais le Wi-Fi : réseau uniquement en 5 GHz, mot de passe erroné ou portail captif sur un réseau invité.
- La carte se déconnecte dès qu'une seconde carte se connecte : les deux cartes utilisent le même client ID. L'approche par ID de puce ci-dessus l'évite.
- Les messages de plus de quelques centaines d'octets disparaissent : c'est le buffer PubSubClient par défaut de 256 octets. Augmentez-le modérément.
- Les messages cessent d'arriver après quelques heures : fragmentation du heap. Surveillez
getMaxFreeBlockSize()dans le temps.
ESP8266 ou ESP32 ?
L'ESP8266 est tout à fait capable pour des nœuds à capteur unique, des relais et de petits écrans, surtout en MQTT en clair ou avec des connexions TLS occasionnelles. Si vous avez besoin de nombreuses sessions TLS simultanées, du Bluetooth, de davantage de GPIO ou de place pour les mises à jour OTA en plus de gros payloads, passez à l'ESP32. Notre comparatif ESP32 vs ESP8266 passe en revue les compromis, et le tutoriel IoT ESP32 est l'étape suivante lorsque cette carte ne suffit plus.
Faites tourner votre flotte ESP8266 sur ConnectMQ
Une fois le prototype fonctionnel, migrez-le vers un broker MQTT cloud avec des identifiants privés et le TLS. ConnectMQ prend en charge MQTT 3.1.1 et 5.0 en TCP sur 1883 et en TLS sur 8883, et le portail comprend un client MQTT dans le navigateur ainsi qu'un explorateur de topics en direct pour vérifier ce que publient vos cartes. Créez un broker Serverless gratuit sur app.connectmq.com, sans carte bancaire.
Questions fréquentes
L'ESP8266 peut-il utiliser MQTT sur TLS ?
Oui. Le core ESP8266 embarque BearSSL, et PubSubClient fonctionne avec BearSSL::WiFiClientSecure. Synchronisez d'abord l'horloge, faites confiance au certificat racine du broker et limitez les autres usages de la mémoire.
Quelle broche utilise la LED intégrée du NodeMCU ?
Sur la plupart des cartes NodeMCU et Wemos D1 mini, il s'agit de GPIO2 (LED_BUILTIN, aussi marquée D4), et elle est active à l'état bas : écrire LOW l'allume.
Puis-je utiliser l'ESP8266 avec MQTT 5 ?
PubSubClient ne prend en charge que MQTT 3.1.1, ce qui suffit pour la plupart des capteurs. Le broker peut néanmoins servir des clients MQTT 5, comme des tableaux de bord et des backends, sur les mêmes topics.
Pourquoi mon ESP8266 a-t-il besoin de l'heure pour le TLS ?
BearSSL vérifie que le certificat du serveur est dans sa période de validité. Sans horloge correcte, l'appareil se croit en 1970 et rejette le certificat.



