Hoy montamos el prototipo en el sitio, pero hubo problemas con el sensor DHT11, creo que debe cambiarse más bien por un DHT22, igual, lo que se hizo fue cambiar el sensor por otro que teníamos en el salón, la electrónica es linda pero no es sencilla.
Se actualizó el código con una pequeña modificación, se crea la constante UMBRAL_HUMEDAD_SUELO para poder probar el porcentaje mínimo de humedad para que se active el riego con el 50%, se cambio el umbra de temperatura 36°C y la humedad relativa menor al 30%
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
// Configuración de la pantalla OLED
#define OLED_RESET LED_BUILTIN
// Pin de reset para la pantalla OLED
Adafruit_SSD1306 display(OLED_RESET);
// Pines para las salidas de los relés
#define solenoide D5
// Salida relé para solenoide Nebulizador en D5 (12V DC)
#define bomba D4
// Salida relé para riego en D4 (120V AC)
// Variables para controlar la pantalla OLED
unsigned long lastUpdateTime = 0; // Última vez que se actualizó la pantalla
#define updateInterval 3000
// Intervalo de actualización de la pantalla (3 segundos)
int currentPage = 0; // Página actual que se está mostrando en la OLED
// Configuración del sensor DHT11
#include "DHT.h"
#define DHTpin D6
// Pin del sensor DHT11
#define DHTTYPE DHT11
// Tipo de sensor DHT
DHT dht(DHTpin, DHTTYPE); // Creación del objeto DHT
//la lectura de los sensores la haremos cada minuto, no se requiere cada segundo, vuelve loco el sistema
unsigned long ultimoTiempoLectura = 0; // Guarda el último momento en que se leyó el sensor
const unsigned long intervaloLectura = 10000; // Intervalo de lectura
// LED para indicar la conexión a Internet
#define conectado D0
// Pin D0 para indicar si está conectado a Internet
// Umbrales de humedad para el sensor de suelo
const uint16_t seco = 656; // Valor analógico que indica suelo seco
const uint16_t humedo = 297; // Valor analógico que indica suelo húmedo
// Variables para el temporizador de los modos manuales
bool automaticoRiego = true; // Indica si el riego está en modo automático
bool automaticoNebulizador = true; // Indica si el nebulizador está en modo automático
unsigned long inicioTiempoRiego = 0; // Tiempo en que se activó el modo manual para el riego
unsigned long inicioTiempoNebulizador = 0; // Tiempo en que se activó el modo manual para el nebulizador
bool temporizadorActivoRiego = false; // Indica si el temporizador del riego está activo
bool temporizadorActivoNebulizador = false; // Indica si el temporizador del nebulizador está activo
#define espera 30000
// Tiempo de espera para el modo manual
//este tiempo también sirve para que inicie los actuadores y no se apaguen de imprevisto por cambios esporádicos en las lecturas
//de los sensores
// Definir umbrales para temperatura y humedad relativa
#define TEMP_UMBRAL 36 // Umbral de temperatura en grados Celsius
#define HUMEDAD_UMBRAL 30 // Umbral de humedad relativa en porcentaje
#define HUMEDAD_UMBRAL_SUELO 50
// Pines para los botones físicos que activan el modo manual
#define PULSADOR_NEBULIZADOR D7 // Pin para el pulsador del nebulizador
#define PULSADOR_BOMBA D3 // Pin para el pulsador de la bomba
// Incluir el archivo de propiedades de Arduino IoT Cloud
#include "thingProperties.h"
//aquí va el api para enlazar con Thinkspeak
//basado en https://how2electronics.com/dht11-humidity-temperature-nodemcu-thingspeak/
String apiKey = "C9DE68VGJX1EVI85"; // Enter your Write API key from ThingSpeak
const char* server = "api.thingspeak.com";
#include <ESP8266WiFi.h>
WiFiClient client;
// Configuración NTP
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", -18000, 60000); // -18000 es la corrección para UTC-5 (hora de Colombia), 60000 es el intervalo de actualización (1 minuto)
// Función para configurar el cliente NTP
void setupNTP() {
timeClient.begin();
timeClient.update();
}
void setup() {
Serial.begin(9600); // Iniciar la comunicación serial a 9600 baudios
dht.begin(); // Iniciar el sensor DHT11
delay(1500); // Esperar 1.5 segundos antes de continuar
// Configuración de la pantalla OLED
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Iniciar la pantalla OLED en la dirección 0x3C
display.clearDisplay(); // Limpiar la pantalla
display.display(); // Mostrar el contenido de la pantalla
// Mensaje inicial en la OLED
display.setTextSize(2); // Establecer tamaño de texto
display.setTextColor(WHITE); // Establecer color de texto (blanco)
display.setCursor(0,0); // Posicionar el cursor en la esquina superior izquierda
display.println(" Jose Noe"); // Mostrar el nombre en la OLED
display.display(); // Mostrar el contenido en la pantalla
delay(2500);
// Configuración de NTP
setupNTP();
// Configuración de los pines de salida
pinMode(solenoide, OUTPUT); // Establecer el pin del solenoide como salida
pinMode(bomba, OUTPUT); // Establecer el pin de la bomba como salida
pinMode(conectado, OUTPUT); // Establecer el pin del LED de conexión como salida
// Configuración de los pulsadores con resistencias pull-up internas
pinMode(PULSADOR_NEBULIZADOR, INPUT_PULLUP); // Pulsador para nebulizador
pinMode(PULSADOR_BOMBA, INPUT_PULLUP); // Pulsador para la bomba
// Estado inicial de los relés (apagados)
digitalWrite(solenoide, HIGH); // Apagar el solenoide (lógica inversa)
digitalWrite(bomba, HIGH); // Apagar la bomba (lógica inversa)
nebulizador = false; // Estado inicial del nebulizador (apagado)
riego = false; // Estado inicial del riego (apagado)
// Iniciar las propiedades de Arduino IoT Cloud
initProperties();
ArduinoCloud.begin(ArduinoIoTPreferredConnection); // Iniciar la conexión con Arduino Cloud
// Configurar el nivel de mensajes de depuración
setDebugMessageLevel(2);
ArduinoCloud.printDebugInfo(); // Imprimir información de depuración
}
void loop() {
ArduinoCloud.update(); // Actualizar la conexión con Arduino Cloud
checkWiFiConnection(); // Verificar el estado de la conexión WiFi
//para hacer la medición cada minuto
unsigned long tiempoActual = millis();
// Verifica si ha pasado 1 minuto desde la última lectura
if (tiempoActual - ultimoTiempoLectura >= intervaloLectura)
{
// Actualiza el tiempo de la última lectura
ultimoTiempoLectura = tiempoActual;
// Realiza la lectura de los sensores
LeerDHT11(); // Leer temperatura y humedad relativa
LeerHumedadSuelo(); // Leer la humedad del suelo
enviarThingSpeak();
}
mostrarDatosOLED(); // Mostrar los datos en la pantalla OLED
// Verificar si se presionó algún pulsador
if (digitalRead(PULSADOR_NEBULIZADOR) == LOW) { // Si el pulsador del nebulizador está presionado
nebulizador = !nebulizador; // Cambiar el estado del nebulizador
digitalWrite(solenoide, nebulizador ? LOW : HIGH); // Encender o apagar el nebulizador
onNebulizadorChange(); // Actualizar el estado en la nube
activarManualNebulizador(); // Activar el modo manual para el nebulizador
delay(100); // Pequeño retraso para evitar rebotes
}
if (digitalRead(PULSADOR_BOMBA) == LOW) { // Si el pulsador de la bomba está presionado
riego = !riego; // Cambiar el estado de la bomba
digitalWrite(bomba, riego ? LOW : HIGH); // Encender o apagar la bomba
onRiegoChange(); // Actualizar el estado en la nube
activarManualRiego(); // Activar el modo manual para el riego
delay(100); // Pequeño retraso para evitar rebotes
}
// Control del temporizador para volver al modo automático
if (temporizadorActivoRiego) {
if (millis() - inicioTiempoRiego >= espera) { // Si el temporizador ha alcanzado el tiempo de espera
temporizadorActivoRiego = false; // Desactivar el temporizador del riego
automaticoRiego = true; // Volver al modo automático para el riego
}
}
if (temporizadorActivoNebulizador) {
if (millis() - inicioTiempoNebulizador >= espera) { // Si el temporizador ha alcanzado el tiempo de espera
temporizadorActivoNebulizador = false; // Desactivar el temporizador del nebulizador
automaticoNebulizador = true; // Volver al modo automático para el nebulizador
}
}
delay(100); // Pequeño retraso antes de la siguiente iteración
}
// Función para manejar cambios en el estado del riego
void onRiegoChange() {
if(riego)
{
digitalWrite(bomba, LOW); // Encender la bomba (lógica inversa)
activarManualRiego(); // Activar el modo manual para el riego
}
else
{
riego=false;
digitalWrite(bomba, HIGH); // Apagar la bomba
}
}
// Función para manejar cambios en el estado del nebulizador
void onNebulizadorChange() {
if (nebulizador)
{
digitalWrite(solenoide, LOW); // Encender el nebulizador (lógica inversa)
activarManualNebulizador(); // Activar el modo manual para el nebulizador
} else
{
digitalWrite(solenoide, HIGH); // Apagar el nebulizador
}
}
// Función para leer la humedad del suelo y controlar el riego
void LeerHumedadSuelo() {
int LecturaSensorTierra = analogRead(A0); // Leer el valor analógico del sensor de humedad del suelo
// Serial.println("Lectura analógica: " + String(LecturaSensorTierra)); // Mostrar la lectura en el monitor serial
int HumedadPorcentajeSuelo = map(LecturaSensorTierra, humedo, seco, 100, 0); // Convertir la lectura a porcentaje de humedad
//Serial.println("Porcentaje de humedad del suelo = " + String(HumedadPorcentajeSuelo) + "%"); // Mostrar el porcentaje de humedad
humedadSuelo = HumedadPorcentajeSuelo; // Actualizar la variable global de humedad del suelo
//corrijo los rangos para que no muestre números negativos o mayores a 100%
if(humedadSuelo<0)
humedadSuelo=0;
if(humedadSuelo>100)
humedadSuelo=100;
// Control automático del riego basado en la humedad del suelo
if (automaticoRiego)
{ // Si el riego está en modo automático
if (HumedadPorcentajeSuelo <= HUMEDAD_UMBRAL_SUELO) { // Si la humedad del suelo es menor o igual al 40%
riego = true; // Activar el riego
digitalWrite(bomba, LOW); // Encender la bomba (lógica inversa)
} else {
riego = false; // Desactivar el riego
digitalWrite(bomba, HIGH); // Apagar la bomba
}
}
}
// Función para leer los datos del sensor DHT11 y controlar el nebulizador
void LeerDHT11() {
temperatura = dht.readTemperature(); // Leer la temperatura del DHT11
humedad = dht.readHumidity(); // Leer la humedad relativa del DHT11
Serial.println("Temperatura: " + String(temperatura) + " C"); // Mostrar la temperatura en el monitor serial
Serial.println("Humedad relativa: " + String(humedad) + "%"); // Mostrar la humedad relativa en el monitor serial
// Control automático del nebulizador basado en la temperatura y la humedad relativa
if (automaticoNebulizador) { // Si el nebulizador está en modo automático
if (temperatura >= TEMP_UMBRAL && humedad <= HUMEDAD_UMBRAL) { // Si la temperatura supera el umbral y la humedad es menor al umbral
nebulizador = true; // Activar el nebulizador
digitalWrite(solenoide, LOW); // Encender el solenoide (lógica inversa)
onNebulizadorChange();
} else {
nebulizador = false; // Desactivar el nebulizador
digitalWrite(solenoide, HIGH); // Apagar el solenoide
onNebulizadorChange();
}
}
}
// Función para verificar si el dispositivo está conectado a Internet
void checkWiFiConnection() {
if (WiFi.status() == WL_CONNECTED) { // Si hay conexión a Internet
digitalWrite(conectado, LOW); // Encender el LED de conexión (lógica inversa)
} else {
digitalWrite(conectado, HIGH); // Apagar el LED de conexión
}
}
// Función para mostrar los datos en la pantalla OLED
void mostrarDatosOLED() {
if (millis() - lastUpdateTime > updateInterval) { // Si ha pasado el intervalo de actualización
lastUpdateTime = millis(); // Actualizar el tiempo de la última actualización
// Actualiza la hora
timeClient.update();
String formattedTime = timeClient.getFormattedTime(); // Hora en formato HH:MM:SS
display.clearDisplay(); // Limpiar la pantalla OLED
switch (currentPage) {
case 0: // Página 1
display.setTextSize(1); // Establecer tamaño de texto pequeño
display.setCursor(0, 0);
display.print("Temp: ");
display.print(temperatura);
display.println(" C");
display.setCursor(0, 10);
display.print("Hum.Rel: ");
display.print(humedad);
display.println(" %");
display.setCursor(0, 20);
display.print("Hum.Suelo: ");
display.print(humedadSuelo);
display.println(" %");
/*
display.setCursor(0, 30);
display.print("Neb: ");
display.println(nebulizador ? "ON" : "OFF");
display.setCursor(0, 40);
display.print("Riego: ");
display.println(riego ? "ON" : "OFF");
display.setCursor(0, 50);
display.print("Modo: ");
display.println(automaticoRiego ? "Auto" : "Manual");*/
break;
case 1: // Página 2
display.setTextSize(1); // Establecer tamaño de texto pequeño
display.setCursor(0, 0);
display.print("Nebulizador:");
display.print(nebulizador ? " Activado" : " OFF");
//display.println(automaticoNebulizador ? " Auto" : " Manual");
display.setCursor(0, 10);
display.print("Riego: ");
display.print(riego ? "ON - Activado" : " OFF");
display.setCursor(0, 20);
display.print("Hora: ");
display.println(formattedTime); // Muestra la hora en formato HH:MM:SS
break;
case 2: // Página 3
display.setTextSize(1); // Establecer tamaño de texto pequeño
display.setCursor(0, 0);
display.print("Internet: ");
display.println(WiFi.status() == WL_CONNECTED ? "Conectado" : "Desconectado");
/* display.setCursor(0, 10);
display.print("IP: ");
display.println(WiFi.localIP());*/
display.setCursor(0, 10);
display.println(" IE Naranjal");
display.println(" Huerta Inteligente");
break;
}
display.display(); // Mostrar el contenido en la pantalla OLED
currentPage = (currentPage + 1) % 3; // Cambiar de página
}
}
// Función para activar el modo manual del nebulizador
void activarManualNebulizador() {
automaticoNebulizador = false; // Desactivar el modo automático para el nebulizador
temporizadorActivoNebulizador = true; // Activar el temporizador del modo manual
inicioTiempoNebulizador = millis(); // Guardar el tiempo en que se activó el modo manual
}
// Función para activar el modo manual del riego
void activarManualRiego() {
automaticoRiego = false; // Desactivar el modo automático para el riego
temporizadorActivoRiego = true; // Activar el temporizador del modo manual
inicioTiempoRiego = millis(); // Guardar el tiempo en que se activó el modo manual
}
void enviarThingSpeak()
{
float h = humedad;
float t = temperatura;
float hs= humedadSuelo;
if (client.connect(server,80)) // "184.106.153.149" or api.thingspeak.com
{
String postStr = apiKey;
postStr +="&field1=";
postStr += String(t);
postStr +="&field2=";
postStr += String(h);
postStr +="&field3=";
postStr += String(hs);
postStr += "\r\n\r\n";
client.print("POST /update HTTP/1.1\n");
client.print("Host: api.thingspeak.com\n");
client.print("Connection: close\n");
client.print("X-THINGSPEAKAPIKEY: "+apiKey+"\n");
client.print("Content-Type: application/x-www-form-urlencoded\n");
client.print("Content-Length: ");
client.print(postStr.length());
client.print("\n\n");
client.print(postStr);
}
}