Automatización IoT

Sensor de humedad del suelo con MQTT: montaje con ESP32, calibración y alertas de riego

Conecta una sonda capacitiva de humedad del suelo a un ESP32, calibra los puntos seco y húmedo, publica el porcentaje de humedad por MQTT con deep sleep y genera alertas de riego sin rebotes.

Nodo sensor de humedad del suelo MQTT con un ESP32 y una sonda capacitiva en un bancal que envía lecturas a un broker en la nube
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

Un sensor de humedad del suelo con MQTT te dice cuándo un bancal, una maceta o un sector de una parcela, desde un huerto urbano hasta una finca agrícola en el Bajío o en Valencia, necesita agua de verdad, en lugar de regar con un horario fijo. En este tutorial conectarás una sonda capacitiva a un ESP32, la calibrarás con suelo seco y saturado, publicarás el porcentaje de humedad en un broker MQTT con un ciclo de deep sleep y generarás una alerta de riego sin rebotes sobre la que pueden actuar dashboards y automatizaciones.

Por qué una sonda capacitiva

Las sondas resistivas baratas de dos puntas que traen los kits de iniciación hacen pasar corriente por el suelo. En pocas semanas los electrodos expuestos se corroen, las lecturas derivan y el metal se disuelve en la tierra. Las sondas capacitivas miden la permitividad dieléctrica del suelo a través de una placa de circuito recubierta, de modo que nada conductor toca la tierra. Son el mínimo razonable para cualquier cosa que deba durar una campaña.

Tipo de sonda Vida útil en el suelo Precisión Notas
Horquilla resistiva Semanas Mala, deriva Solo vale para una demo de un día
Capacitiva (placas v1.2 / v2.0) Campañas, si se sella el borde Relativa, requiere calibración La mejor relación calidad-precio para aficionados y pequeñas explotaciones
Sondas FDR/TDR profesionales Años Buena, a menudo volumétrica Salida SDI-12 o RS485, coste más alto

Las placas capacitivas dan una lectura relativa, no el contenido volumétrico de agua. Para decidir cuándo regar es suficiente, siempre que calibres cada sonda en el suelo en el que va a estar.

Componentes y conexiones

Componente Función
Placa de desarrollo ESP32 (o una de bajo consumo en reposo para baterías) Lee la sonda, se conecta a Wi-Fi y MQTT
Sonda capacitiva de humedad del suelo Mide la humedad
3 cables dupont Alimentación, masa, señal
Opcional: celda 18650, portapilas y pequeño panel solar Alimentación autónoma

Conexiones:

Pin de la sonda Pin del ESP32
VCC GPIO 25 (alimentación conmutada)
GND GND
AOUT GPIO 34 (ADC1)

Hay dos detalles importantes. Primero, usa un pin del ADC1 (GPIO 32 a 39). Los pines del ADC2 no se pueden leer mientras el Wi-Fi está activo. Segundo, alimenta la sonda desde un GPIO en lugar de la línea de 3,3 V para que no consuma nada mientras el ESP32 duerme. Las sondas capacitivas consumen solo unos pocos miliamperios, muy por debajo de lo que puede suministrar un GPIO. Algunas placas baratas llevan un regulador que funciona mal a 3,3 V; si las lecturas son erráticas, comprueba la revisión de la placa.

Sella el borde superior de la sonda y los componentes expuestos con esmalte de uñas, barniz de protección (conformal coating) o tubo termorretráctil. El agua que se cuela por el borde cortado del PCB es la causa más habitual de fallo de la sonda.

Calibrar la sonda

El ESP32 devuelve un valor en bruto de 0 a 4095. Las sondas capacitivas dan valores altos en seco y bajos en húmedo. Carga el sketch de abajo con CALIBRATION_MODE en true, abre el monitor serie a 115200 baudios y anota dos valores:

  1. Seco: la sonda en suelo completamente seco del mismo bancal (o al aire, como alternativa aproximada).
  2. Húmedo: la sonda en el mismo suelo saturado de agua, tras unos minutos para que se estabilice.

Introduce la sonda siempre a la misma profundidad, hasta la línea marcada en la placa y nunca más. Los valores típicos rondan 2.600 a 3.000 en seco y 1.000 a 1.400 en húmedo, pero cada sonda es distinta; por eso hay que medir en lugar de copiar.

El sketch de sensor de humedad del suelo MQTT para ESP32

El sketch se despierta, alimenta la sonda, calcula la mediana de varias lecturas, la convierte a porcentaje, se conecta al Wi-Fi y al broker, publica un mensaje de telemetría retenido y el estado de la alerta, y vuelve al deep sleep. Usa la librería PubSubClient. Sustituye s5d1v8 por tu propia cadena aleatoria, ya que el área pública del servidor MQTT público gratuito la puede leer cualquiera.

#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;   // de la calibración
const int RAW_WET = 1180;   // de la calibración

const float ALERT_ON_PCT  = 25.0;  // activar la alerta por debajo de este valor
const float ALERT_OFF_PCT = 35.0;  // desactivar la alerta por encima de este valor
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);  // dejar que se estabilice la salida de la sonda
  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++) {           // ordenación por inserción
    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);       // dar tiempo a la pila TCP para vaciar el buffer
    mqtt.publish(TOPIC_STATUS, "sleeping", true);
    mqtt.disconnect();
  }
  goToSleep();
}

void loop() {}

Ver las lecturas

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

Como la telemetría es retenida, el suscriptor muestra la última lectura de inmediato, aunque el dispositivo pase casi todo el tiempo dormido. El topic de estado te indica si el nodo está online, sleeping o se ha desconectado inesperadamente (offline, por el last will).

Cómo funciona la alerta de riego

Con un único umbral, la alerta se activaría y desactivaría continuamente cuando las lecturas oscilan a su alrededor, sobre todo justo después de una lluvia ligera o cuando el sol calienta el suelo. El sketch usa histéresis: la alerta se activa por debajo del 25 % y solo se desactiva cuando la humedad sube por encima del 35 %. El flag alertActive vive en la memoria RTC (RTC_DATA_ATTR), así que sobrevive al deep sleep.

El topic de alerta es retenido y siempre lleva el estado actual, de modo que cualquier consumidor puede actuar sobre él:

  • una automatización de Home Assistant que envía una notificación a tu teléfono, como se muestra en la guía de automatizaciones MQTT en Home Assistant;
  • un flujo de Node-RED o un controlador en Python que abre una válvula, tratado en el tutorial del sistema de riego automático;
  • una regla de alerta por umbral en el portal de ConnectMQ sobre moisture_pct, que registra las alertas aunque tu servidor doméstico esté desconectado.

Consejos de precisión y fiabilidad

  1. Calibra en el suelo real. Los suelos arenosos y arcillosos dan lecturas muy distintas para el mismo contenido de agua.
  2. Mantén constante la profundidad de inserción. Las bolsas de aire alrededor de la sonda hacen caer bruscamente las lecturas; compacta la tierra a su alrededor tras insertarla.
  3. Observa la tendencia, no los valores sueltos. Una curva descendente durante dos días significa más que una sola lectura.
  4. Evita los extremos del ADC. El ADC del ESP32 no es lineal cerca de 0 y de 4095. Con una atenuación de 11 dB, el rango útil cubre holgadamente una sonda capacitiva.
  5. Controla la batería. Añade un divisor de tensión en otro pin del ADC1 e incluye battery_v en el payload; el artículo sobre el sensor ESP32 alimentado por batería tiene los detalles.

Autonomía de la batería

Con despertares cada 15 minutos, el nodo solo está despierto unos segundos por ciclo, la mayor parte esperando a asociarse al Wi-Fi. Usar una IP estática y el BSSID y el canal del router puede acortarlo notablemente. Elige una placa con un regulador de bajo consumo en reposo y sin chip USB ni LED siempre encendidos, porque muchas placas de desarrollo consumen más "dormidas" que el propio ESP32. Para parcelas alejadas del Wi-Fi, un nodo LoRaWAN con la misma sonda y un bridge desde el servidor de red es un diseño mejor; consulta la guía de agricultura inteligente IoT para ver los pros y contras.

Configuración de producción

El área del servidor público es ideal para construir y probar, pero es compartida y pública, así que no sirve para datos de producción. Para una instalación permanente, crea un broker privado y pasa a TLS:

  • incluye WiFiClientSecure.h, usa WiFiClientSecure net; y net.setCACert(ISRG_ROOT_X1); con el certificado ISRG Root X1;
  • cambia el puerto a 8883;
  • conéctate con mqtt.connect("YOUR_CLIENT_ID", "YOUR_USERNAME", "YOUR_PASSWORD", TOPIC_STATUS, 1, true, "offline");
  • pasa los topics a tu propio prefijo, por ejemplo farm1/garden/bed1/telemetry.

TLS añade uno o dos segundos a cada ciclo de despertar, un coste pequeño por mantener tus datos privados. Un broker MQTT gestionado también te ahorra mantener un broker en la red de la que dependen los sensores. Encontrarás más proyectos como este en la guía de automatización IoT.

Monitoriza tu suelo con ConnectMQ

ConnectMQ da a tus sensores un broker privado protegido con TLS, con explorador de topics en vivo, dashboard y reglas de alerta por umbral para avisos de suelo seco. Crea un broker Serverless gratuito en app.connectmq.com, sin tarjeta de crédito, y cambia tres líneas del sketch para ponerlo en marcha.

Preguntas frecuentes

¿Por qué mi sensor capacitivo de humedad del suelo da valores más altos cuando el suelo está seco?

Así funcionan las sondas capacitivas: la tensión de salida baja a medida que la constante dieléctrica sube con el agua. El sketch invierte la escala al convertir a porcentaje.

¿Puedo usar varias sondas en un mismo ESP32?

Sí. Usa otros pines del ADC1 (GPIO 32, 33, 35, 36, 39), calibra cada sonda por separado y publica cada una en su propio topic o como campos de un único mensaje JSON.

¿A qué profundidad debe ir el sensor de humedad del suelo?

En la zona radicular del cultivo, normalmente de 5 a 15 cm para hortalizas y macetas. Insértalo solo hasta la línea marcada para que la electrónica quede por encima del suelo.

¿Con qué frecuencia debe publicar por MQTT un sensor de humedad del suelo?

Cada 15 a 60 minutos es más que suficiente. La humedad del suelo cambia despacio, y los intervalos largos alargan enormemente la autonomía de la batería.

Artículos relacionados

Guía para configurar Zigbee2MQTT: del coordinador al panel

Instala Zigbee2MQTT con Docker, configura el coordinador y la conexión MQTT, empareja y renombra dispositivos, contrólalos por MQTT y consulta sus estados en un panel, probando primero en un servidor MQTT público gratuito.

8 min de lectura

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.