Automatisation IoT

Capteur d'humidité du sol avec MQTT : montage ESP32 avec étalonnage et alertes d'arrosage

Câblez une sonde capacitive d'humidité du sol sur un ESP32, étalonnez les points sec et humide, publiez le pourcentage d'humidité via MQTT avec deep sleep et déclenchez des alertes d'arrosage anti-rebond.

Nœud capteur d'humidité du sol MQTT avec un ESP32 et une sonde capacitive dans une plate-bande envoyant des mesures vers un broker cloud
Essayez-le sur votre propre broker MQTTObtenez un broker MQTT privé et managé avec l’offre Free et partez d’exemples de code prêts à l’emploi.
Essayer gratuitement Exemples de code Aucune carte bancaire requise

Un capteur d'humidité du sol avec MQTT vous indique quand une plate-bande, un pot ou une zone de parcelle a réellement besoin d'eau, au lieu d'arroser selon un horaire fixe. Dans ce tutoriel, vous allez câbler une sonde capacitive sur un ESP32, l'étalonner dans un sol sec puis saturé, publier le pourcentage d'humidité vers un broker MQTT sur un cycle de deep sleep et déclencher une alerte d'arrosage anti-rebond sur laquelle tableaux de bord et automatisations peuvent agir.

Pourquoi une sonde capacitive

Les sondes résistives bon marché à deux pointes des kits de démarrage font passer du courant dans le sol. En quelques semaines, les électrodes exposées se corrodent, les mesures dérivent et le métal se diffuse dans le sol. Les sondes capacitives mesurent la permittivité diélectrique du sol à travers un circuit imprimé revêtu, si bien que rien de conducteur ne touche la terre. C'est le minimum raisonnable pour tout ce qui doit durer une saison.

Type de sonde Durée de vie dans le sol Précision Remarques
Fourche résistive Quelques semaines Médiocre, dérive Convient seulement pour une démonstration d'un jour
Capacitive (cartes v1.2 / v2.0) Plusieurs saisons, si la tranche est étanchéifiée Relative, nécessite un étalonnage Meilleur rapport qualité-prix pour les amateurs et les petites exploitations
Sondes FDR/TDR professionnelles Plusieurs années Bonne, souvent volumétrique Sortie SDI-12 ou RS485, coût plus élevé

Les cartes capacitives fournissent une mesure relative, et non une teneur volumique en eau. Cela suffit pour décider quand arroser, à condition d'étalonner chaque sonde dans le sol où elle sera installée.

Composants et câblage

Composant Rôle
Carte de développement ESP32 (ou carte à faible courant de repos pour fonctionner sur batterie) Lit la sonde, se connecte au Wi-Fi et à MQTT
Sonde capacitive d'humidité du sol Mesure l'humidité
3 fils de liaison Alimentation, masse, signal
En option : accu 18650, support et petit panneau solaire Alimentation autonome

Câblage :

Broche de la sonde Broche ESP32
VCC GPIO 25 (alimentation commutée)
GND GND
AOUT GPIO 34 (ADC1)

Deux détails comptent. D'abord, utilisez une broche ADC1 (GPIO 32 à 39). Les broches ADC2 ne peuvent pas être lues lorsque le Wi-Fi est actif. Ensuite, alimentez la sonde depuis une GPIO plutôt que depuis le rail 3,3 V, afin qu'elle ne consomme rien pendant que l'ESP32 dort. Les sondes capacitives ne consomment que quelques milliampères, bien en deçà de ce qu'une GPIO peut fournir. Certaines cartes bon marché sont livrées avec un régulateur qui fonctionne mal en 3,3 V ; si les mesures sont erratiques, vérifiez la révision de la carte.

Étanchéifiez le bord supérieur de la sonde et les composants exposés avec du vernis à ongles, un vernis de tropicalisation ou de la gaine thermorétractable. L'eau qui s'infiltre par la tranche découpée du circuit imprimé est la cause la plus fréquente de défaillance des sondes.

Étalonner la sonde

L'ESP32 renvoie une valeur brute de 0 à 4095. Les sondes capacitives affichent une valeur élevée quand le sol est sec et basse quand il est humide. Flashez le sketch ci-dessous avec CALIBRATION_MODE réglé sur true, ouvrez le moniteur série à 115200 bauds et notez deux valeurs :

  1. Sec : la sonde dans un sol totalement sec provenant de la même plate-bande (ou à l'air libre, en solution de repli approximative).
  2. Humide : la sonde dans le même sol saturé d'eau, après quelques minutes de stabilisation.

Enfoncez la sonde toujours à la même profondeur, jusqu'au trait marqué sur la carte, jamais plus profond. Les valeurs typiques se situent autour de 2 600 à 3 000 à sec et de 1 000 à 1 400 en humide, mais chaque sonde est différente : c'est pourquoi il faut mesurer plutôt que recopier.

Le sketch ESP32 du capteur d'humidité du sol MQTT

Le sketch se réveille, alimente la sonde, prend la médiane de plusieurs mesures, la convertit en pourcentage, se connecte au Wi-Fi et au broker, publie un message de télémétrie retained et un état d'alerte, puis retourne en deep sleep. Il utilise la bibliothèque PubSubClient. Remplacez s5d1v8 par votre propre chaîne aléatoire, car le serveur MQTT public gratuit est lisible par tous.

#include <WiFi.h>
#include <PubSubClient.h>

#define CALIBRATION_MODE false

const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";

const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;
const char* CLIENT_ID = "soil-bed1-s5d1v8";
const char* TOPIC_TELE   = "connectmq/demo/s5d1v8/garden/bed1/telemetry";
const char* TOPIC_ALERT  = "connectmq/demo/s5d1v8/garden/bed1/alert";
const char* TOPIC_STATUS = "connectmq/demo/s5d1v8/garden/bed1/status";

const int PIN_PROBE_PWR = 25;
const int PIN_PROBE_ADC = 34;

const int RAW_DRY = 2850;   // issu de l'étalonnage
const int RAW_WET = 1180;   // issu de l'étalonnage

const float ALERT_ON_PCT  = 25.0;  // déclencher l'alerte en dessous
const float ALERT_OFF_PCT = 35.0;  // lever l'alerte au-dessus
const uint64_t SLEEP_MIN = 15;

RTC_DATA_ATTR bool alertActive = false;
RTC_DATA_ATTR uint32_t bootCount = 0;

WiFiClient net;
PubSubClient mqtt(net);

int readRawMedian() {
  digitalWrite(PIN_PROBE_PWR, HIGH);
  delay(300);  // laisser la sortie de la sonde se stabiliser
  int v[9];
  for (int i = 0; i < 9; i++) {
    v[i] = analogRead(PIN_PROBE_ADC);
    delay(20);
  }
  digitalWrite(PIN_PROBE_PWR, LOW);
  for (int i = 1; i < 9; i++) {           // tri par insertion
    int k = v[i], j = i - 1;
    while (j >= 0 && v[j] > k) { v[j + 1] = v[j]; j--; }
    v[j + 1] = k;
  }
  return v[4];
}

float rawToPercent(int raw) {
  float pct = 100.0f * (RAW_DRY - raw) / (float)(RAW_DRY - RAW_WET);
  if (pct < 0) pct = 0;
  if (pct > 100) pct = 100;
  return pct;
}

bool connectWifi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  for (int i = 0; i < 40 && WiFi.status() != WL_CONNECTED; i++) delay(250);
  return WiFi.status() == WL_CONNECTED;
}

bool connectMqtt() {
  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  for (int i = 0; i < 3; i++) {
    if (mqtt.connect(CLIENT_ID, TOPIC_STATUS, 1, true, "offline")) return true;
    delay(1000);
  }
  return false;
}

void goToSleep() {
  esp_sleep_enable_timer_wakeup(SLEEP_MIN * 60ULL * 1000000ULL);
  esp_deep_sleep_start();
}

void setup() {
  Serial.begin(115200);
  pinMode(PIN_PROBE_PWR, OUTPUT);
  analogSetPinAttenuation(PIN_PROBE_ADC, ADC_11db);
  bootCount++;

  int raw = readRawMedian();
  if (CALIBRATION_MODE) {
    while (true) {
      Serial.printf("raw=%d\n", readRawMedian());
      delay(1000);
    }
  }
  float pct = rawToPercent(raw);

  bool changed = false;
  if (!alertActive && pct < ALERT_ON_PCT)  { alertActive = true;  changed = true; }
  if (alertActive && pct > ALERT_OFF_PCT)  { alertActive = false; changed = true; }

  if (connectWifi() && connectMqtt()) {
    char buf[160];
    snprintf(buf, sizeof(buf),
             "{\"moisture_pct\":%.1f,\"raw\":%d,\"rssi\":%d,\"boot\":%lu}",
             pct, raw, WiFi.RSSI(), (unsigned long)bootCount);
    mqtt.publish(TOPIC_STATUS, "online", true);
    mqtt.publish(TOPIC_TELE, buf, true);
    snprintf(buf, sizeof(buf), "{\"active\":%s,\"moisture_pct\":%.1f}",
             alertActive ? "true" : "false", pct);
    mqtt.publish(TOPIC_ALERT, buf, true);
    if (changed) Serial.println(alertActive ? "ALERT raised" : "ALERT cleared");
    mqtt.loop();
    delay(200);       // laisser à la pile TCP le temps de vider ses tampons
    mqtt.publish(TOPIC_STATUS, "sleeping", true);
    mqtt.disconnect();
  }
  goToSleep();
}

void loop() {}

Observer les mesures

mosquitto_sub -h broker.connectmq.com -p 1883 -i watch-s5d1v8 \
  -t 'connectmq/demo/s5d1v8/garden/#' -v

Comme la télémétrie est retained, l'abonné affiche immédiatement la dernière mesure, même si l'appareil passe presque tout son temps à dormir. Le topic de statut vous indique si le nœud est online, sleeping, ou s'il a décroché de manière inattendue (offline, via le last will).

Fonctionnement de l'alerte d'arrosage

Un seuil unique ferait clignoter l'alerte lorsque les mesures oscillent autour de lui, notamment juste après une pluie légère ou quand le soleil réchauffe le sol. Le sketch utilise une hystérésis : l'alerte s'active en dessous de 25 % et ne se lève qu'une fois l'humidité remontée au-dessus de 35 %. Le flag alertActive réside en mémoire RTC (RTC_DATA_ATTR), il survit donc au deep sleep.

Le topic d'alerte est retained et transporte toujours l'état courant, si bien que n'importe quel consommateur de votre maison connectée peut agir dessus. Jeedom et Domoticz savent aussi s'abonner à des topics MQTT. Quelques exemples :

  • une automatisation Home Assistant qui envoie une notification sur votre téléphone, comme le montre le guide automatisation Home Assistant MQTT ;
  • un flow Node-RED ou un contrôleur Python qui ouvre une vanne, traité dans le tutoriel système d'arrosage automatique ;
  • une règle d'alerte à seuil dans le portail ConnectMQ sur moisture_pct, qui consigne les alertes même si votre serveur domestique est hors ligne.

Conseils de précision et de fiabilité

  1. Étalonnez dans le sol réel. Les sols sableux et argileux donnent des mesures très différentes pour une même teneur en eau.
  2. Gardez une profondeur d'insertion constante. Les poches d'air autour de la sonde font chuter fortement les mesures ; tassez le sol autour après l'insertion.
  3. Suivez la tendance, pas les valeurs isolées. Une courbe descendante sur deux jours est plus parlante qu'une mesure unique.
  4. Évitez les extrêmes de l'ADC. L'ADC de l'ESP32 n'est pas linéaire près de 0 et de 4095. Avec une atténuation de 11 dB, la plage utile couvre largement une sonde capacitive.
  5. Surveillez la batterie. Ajoutez un pont diviseur sur une autre broche ADC1 et incluez battery_v dans le payload ; l'article capteur ESP32 sur batterie donne les détails.

Autonomie de la batterie

Avec des réveils toutes les 15 minutes, le nœud n'est éveillé que quelques secondes par cycle, l'essentiel étant passé à attendre l'association Wi-Fi. Utiliser une IP statique ainsi que le BSSID et le canal du routeur peut réduire sensiblement ce temps. Choisissez une carte avec un régulateur à faible courant de repos et sans puce USB ni LED toujours alimentées, car de nombreuses cartes de développement consomment davantage « en veille » que l'ESP32 lui-même. Pour des parcelles éloignées du Wi-Fi, un nœud LoRaWAN avec la même sonde et un pont vers le serveur de réseau est une meilleure conception ; consultez le guide agriculture intelligente IoT pour les compromis.

Configuration de production

Le serveur MQTT public gratuit est idéal pour construire et tester, mais il est partagé et public : n'y envoyez pas de données de production. Pour une installation permanente, créez un broker privé et passez en TLS :

  • incluez WiFiClientSecure.h, utilisez WiFiClientSecure net; et net.setCACert(ISRG_ROOT_X1); avec le certificat ISRG Root X1 ;
  • passez le port à 8883 ;
  • connectez-vous avec mqtt.connect("YOUR_CLIENT_ID", "YOUR_USERNAME", "YOUR_PASSWORD", TOPIC_STATUS, 1, true, "offline") ;
  • déplacez les topics vers votre propre préfixe, par exemple farm1/garden/bed1/telemetry.

TLS ajoute une à deux secondes à chaque cycle de réveil, un faible prix pour garder vos données privées. Un broker MQTT managé vous évite aussi d'exploiter un broker sur le réseau dont dépendent les capteurs. D'autres projets de ce type figurent dans le guide de l'automatisation IoT.

Surveillez votre sol sur ConnectMQ

ConnectMQ offre à vos capteurs un broker privé sécurisé par TLS, avec un explorateur de topics en direct, un tableau de bord et des règles d'alerte à seuil pour les avertissements de sol sec. Créez un broker Serverless gratuit sur app.connectmq.com, sans carte bancaire, et modifiez trois lignes du sketch pour passer en production.

Questions fréquentes

Pourquoi mon capteur capacitif d'humidité du sol affiche-t-il une valeur plus élevée quand le sol est sec ?

C'est le principe des sondes capacitives : la tension de sortie baisse à mesure que la constante diélectrique augmente avec l'eau. Le sketch inverse l'échelle lors de la conversion en pourcentage.

Puis-je utiliser plusieurs sondes sur un seul ESP32 ?

Oui. Utilisez d'autres broches ADC1 (GPIO 32, 33, 35, 36, 39), étalonnez chaque sonde séparément et publiez chacune sur son propre topic ou sous forme de champs dans un seul message JSON.

À quelle profondeur placer le capteur d'humidité du sol ?

Dans la zone racinaire de la culture, généralement entre 5 et 15 cm pour les légumes et les pots. N'enfoncez la sonde que jusqu'au trait marqué, afin que l'électronique reste au-dessus du sol.

À quelle fréquence un capteur d'humidité du sol doit-il publier en MQTT ?

Toutes les 15 à 60 minutes, c'est largement suffisant. L'humidité du sol évolue lentement, et des intervalles plus longs prolongent considérablement l'autonomie de la batterie.

Articles liés

Guide d'installation de Zigbee2MQTT : du coordinateur au tableau de bord

Installez Zigbee2MQTT avec Docker, configurez le coordinateur et la connexion MQTT, appairez et renommez les appareils, pilotez-les via MQTT et affichez leurs états sur un tableau de bord, en testant d'abord sur le serveur MQTT public gratuit.

8 min de lecture

Tous les articles →

Votre broker MQTT privé, à quelques clics

Créez un compte, récupérez les identifiants de votre broker et connectez votre premier appareil — aucun serveur à installer, mettre à jour ou dimensionner.