Medidor autónomo de humedad del suelo con D1 Mini

Esta vez traigo un pequeño aunque muy versátil cacharrito para medir la humedad de cualquier terreno (maceta, jardinera, jardín) sin necesidad de cables de alimentación ni de datos; simplemente pinchar y obtener la medida. De nuevo, como en el proyecto anterior, todo realizado con materiales reciclados o de los que ya disponía en mi pequeño taller.

Diseño

El «cerebro» del aparato es el D1 Mini, un montaje muy económico del microcontrolador ESP8266 que incorpora pines de salida para puerto de entrada analógico, pin de reset, alimentación a 5 y 3.3V, pines de entrada/salida con capacidad PWM… Un pequeño monstruo capaz de cualquier tarea.

En primer lugar, para el montaje que nos ocupa, hay que puentear el pin D0 con el pin RST (reset), de manera que el microcontrolador pueda «despertar» de sus periodos de hibernación, ya que al estar alimentado por una batería, es preferible que hiberne durante los periodos en los que no tiene que hacer nada, ahorrando así energía.

Por desgracia, este puente entre los pines D0 y RST inhibe la posibilidad de que el microcontrolador pueda ser programado, por lo que hay que poder desconectarlo para cargar el programa. Las opciones eran instalar un puente que pudiera levantar, o montar este switch que casualmente tenía olvidado en un cajón, y que facilita mucho la tarea, la verdad. De este modo, en la posición ON la máquina podrá despertar de la hibernación, y en la contraria podrá ser programada cuando queramos.

Pero para que este dispositivo sea realmente autónomo necesitamos una fuente de energía (que en este caso será el sol) y una forma de almacenarla de manera que el microcontrolador pueda utilizarla. Bien, pues para ello utilizaremos una batería de un móvil Xiaomi, que aunque el móvil hace mucho que pasó a mejor vida, la batería aún se encuentra en muy buen estado. En su día, hace ya algunos meses, realicé los primeros pinitos añadiendo placas solares a baterías de móviles, y de aquello me sobró esta batería ya preparada para la carga por energía solar y para conectarle dispositivos a 3.7V. El circuito necesario para conseguirlo se puede adquirir online a bajísimo precio, y en su día compré unos cuantos, como el de la foto. Las entradas que tiene a los lados del conector usb son para conectar una placa solar de 5V, mientras las salidas traseras permiten tanto la carga de la batería, como la conexión de los dispositivos que vayamos a utilizar. Además, la batería se puede cargar enchufando al usb una toma de 5V, por lo que es muy cómodo cargar la batería mediante un cable.

Una vez realizada una primera carga de la batería, se comprueba que sea capaz de alimentar correctamente al microcontrolador, en este caso con un programa de prueba que enciende el diodo al despertar (que como es lógico, se apaga durante la hibernación). Ya veremos más adelante cómo se hace esto en el código.

También es importante comprobar si la placa solar cargará la batería, cosa que hacemos simplemente enchufándola a la batería y exponiéndola a la luz. Como se aprecia en la fotografía, la luz roja en el circuito cargador indica que la batería de está cargando, así que, de momento, todo bien.

En este caso, ya he montado la placa solar sobre la caja hermética que usaré para proteger la electrónica de este dispositivo; una caja que en su día me costó algo cara para su tamaño y a la que hasta ahora no había sabido darle una utilidad.

Es una caja bastante pequeña, pero cuyo tamaño es ideal para el proyecto, ya que los componentes entran bastante ajustados y ni siquiera necesitan ser sujetados con tornillería. No se puede decir que sea un montaje muy ortodoxo, pero cosas peores he visto en artículos comprados en tienda.

El sensor de humedad es de tipo capacitivo, algo más caro que el resistivo, pero que da mejor calidad en las medidas y tiene más durabilidad, al no sufrir corrosión por contacto con el terreno. Su consumo es de 5mA, y está conectado directamente a la batería. En un futuro me plantearé montar un circuito interruptor con un transistor para impedir que el sensor esté consumiendo la batería en los periodos de hibernación.

Y para finalizar, aquí está el invento en su emplazamiento provisional para las primeras pruebas de resistencia a la humedad y de duración de la batería. Instalado el sábado 12 de noviembre, a día 16 sigue funcionando, transmitiendo datos cada 10 minutos.

Está claro que tomar la humedad cada 10 minutos es un poco excesivo, ya que con tomarla cada hora seguramente sería suficiente. El programa definitivo, del que hablaré en otro post, incluirá la posibilidad de cambiar remotamente los tiempos de hibernación enviándole órdenes a través del servidor MQTT.

Como se puede ver, la alimentación del sensor de humedad está controlada por un transistor, que cierra el circuito a través del pin D8 cuando el controlador se enciende o se «despierta» después de un periodo de hibernación. De esta forma se evita que esté constantemente consumiendo energía de la batería.

El otro componente interesante de este montaje es el circuito cargador de la batería, al que le puede llegar alimentación desde una placa solar o desde un conector USB. Ahora, pasemos al código:

Código

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <PubSubClient.h>
#include <EEPROM.h>
 
int hibernacion       = 3600;
int circuito_sensor   = D8;
 
const char* ssid = "SSID de tu WiFi";
const char* passwd = "Contraseña de tu wifi";
const char* mqtt_server = "Dirección de tu servidor MQTT";
int mqtt_port = 1883;
const char* mqtt_username = "Usuario de tu servidor MQTT";
const char* mqtt_password = "Contraseña de usuario del servidor MQTT";
const char* clientID = "s01";
const char* topic_ordenes = "casa/ordenes/#";
char* topic_respuesta = "casa/s01/respuesta";
char* topic_hora = "casa/s01/hora";
char* topic_humedad = "casa/s01/humedad";
WiFiClient wifiClient;
PubSubClient client(mqtt_server, mqtt_port, wifiClient);
bool conectado_wifi = false;
bool conectado_mqtt = false;
 
// Intenta conectar los servicios de WiFi, NTP y MQTT
void conectar() {
  // Iniciamos el proceso de intento de conexión
  int contador = 0;
  while (WiFi.status() != WL_CONNECTED && contador < 50) {      
    conectado_wifi = false;
    conectado_mqtt = false;          
    Serial.print("Conectando a WiFi... ");
    Serial.println(contador);
    contador++;
    delay(500);
  }
  // Finalizado el proceso, comprobamos el estado de la conexión   
  if (WiFi.status() == WL_CONNECTED) {
    // Si venimos de estado desconectado, avisar de la nueva conexión
    if (!conectado_wifi) {
      Serial.println("Conectado con éxito a WiFi");
    }
    conectado_wifi = true;    
    // Iniciamos el proceso de intento de conexión a MQTT
    if (!client.connected() || !conectado_mqtt) {
      contador = 0;
      conectado_mqtt = false;     
      while (!client.connect(clientID, mqtt_username, mqtt_password) && contador < 50) {
        Serial.print("Conectando a MQTT... ");
        Serial.println(contador);
        contador++;
        delay(500);
      }
    }
    if (client.connected()) {
      // Si venimos de estado desconectado, avisar de la nueva conexión
      if (!conectado_mqtt) {
        Serial.println("Conectado con éxito a MQTT");
      }
      conectado_mqtt = true;
      client.subscribe(topic_ordenes);
      client.loop();
    }
    else {
      Serial.println("***Error de conexión MQTT");      
    }
  }
  else {
    Serial.println("***Error de conexión WiFi");
  }
}
 
void emitirDato(char* dato_topic, String payload, bool retain) {
  if (conectado_mqtt) {
    int contador = 0;
    conectar();
    while(!client.publish(dato_topic, payload.c_str(), retain) && contador<10) {
      delay(100);
      contador++;
    }    
  }
  else {
    Serial.println("***Imposible transmitir datos: MQTT desconectado");
  }
}
 
void emitirHumedad() {
  String medida = String(analogRead(A0));
  Serial.println("Emitiendo humedad... " + medida);
  emitirDato(topic_humedad, medida,true);
}
 
void setup() {
  pinMode(circuito_sensor, OUTPUT);
  digitalWrite(circuito_sensor, HIGH);
  Serial.begin(9600);
  Serial.setTimeout(2000);
  Serial.println("Despertando...");
  WiFi.begin(ssid, passwd);
  client.setServer(mqtt_server, mqtt_port);
}
 
void loop() {
  conectar();
  delay(5000);
  emitirHumedad();
  delay(5000);
  Serial.println("Hibernando...");  
  ESP.deepSleep(hibernacion*1e6);
}

Con este código, el microcontrolador D1 Mini cerrará el circuito del sensor, esperará cinco segundos, transmitirá los datos al servidor MQTT y luego hibernará durante un periodo de 3600 segundos, para volver entonces a repetir todo el proceso.

Una vez en el servidor MQTT, este dato de humedad puede almacenarse en una base de datos para dibujar gráficas de la evolución de la humedad, como en el caso de mi HispaBot_Meteo: