martes, 20 de agosto de 2024

Actualización sistema 20 de agosto de 2024

 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);

 

                             } 

}


sábado, 17 de agosto de 2024

Control sistema de riego en huerta

Circuito Huerta Inteligente
Hemos desarrollado un sistema de riego que controla una motobomba y una solenoide, la primera para manjerar el riego de acuerdo a los valores del sensor capacitivo de humedad, menor o igual que el 40%, la segunda para activar una solenoide conectada al acueducto que nos lleva el agua al nebulizador, este se acciona de acuerdo a la temperatura y humedad relativa, por el momento se activa con una temperatura superior o igual a 32°C y una humedad relativa menor o igual al 40%, igual las pruebas nos darán los valores adecuados para nuestro contexto.
Manejamos el riego utilizando mangueras de 16mm y microaspesores, tenemos una motobomba de 1/2Hp, y en las pruebas iniciales notamos que sólo se requiere 3 minutos de riego, esperamos que cuando iniciemos las pruebas con el circuito sea algo similar, dado a que sólo vamos a utilizar un sensor, luego veremos si instalamos dos, pero el riego no sólo es de las eras o camas de siembra, sino también del cultivo verticial y un pequeño cultivo escalonado en la parte trasera, son diferentes niveles de humedad pero esperamos que con al menos una medición el promedio de riego sea el adecuado, sólo la experiencia nos lo dira.


El esquemático en fritzing es la traducción de lo que hicimos en protoboard, con Arduino Cloud, fue más sencillo, aunque también la información de las variables la envíamos a nuestro canal de ThingSpeak https://thingspeak.com/channels/1911660 nos ayudamos mucho de Chat GPT para poder aclarar algunas cosas de la programación, peo tener mucho cuidado, se equivoca bastante, por eso al final sólo nos apoyamos para partes puntuales donde el manejo de la oled era un poco incierto.

Aquí les dejo el progama, aunque le falta una parte y está sin formato, también da la hora, esa pantilla Oled es pequeña, pero es bastante satisfactorio ver la información en ella, le da un plus que la LCD no tiene:

#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 32   // Umbral de temperatura en grados Celsius
#define HUMEDAD_UMBRAL 45 // Umbral de humedad relativa en porcentaje

// 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 = "aqui va su api key";     //  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 <= 40) { // 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);
 
                             } 
}






lunes, 6 de noviembre de 2023

Steam Farmer (programa en Arduino)

 


Estamos creando nuestro primer brazo robótico, para ello hemos empleado los siguientes materiales:
  • Palitos de helado pequeños y grandes
  • Pistola de silicona
  • Amarras plásticas de 15cm
  • Servomotores SG90, inicialmente se construyó con tres de ellos, pero en la práctica nos dimos cuenta que es mejor utlizar los MG90, entonces se usaron un SG90 y dos MG90
  • Cables hembra macho, macho macho para las conexiones
  • Un arduino uno
  • Dos joystick, uno para girar y alzar el brazo y otro para abrir y cerrar el gancho.
  • Una mini protoboard
  • Una fuente de 5V, aunque en este caso utilizamos un módulo que nos ayuda regular el voltaje de un adaptador que entrega 12V, pero sirve también un adaptador de 5V/2A (mejor de 2A)
  • El conector hembra que recibe el plug del adaptador
  • Unas tablitas para la base y otras pequeñas para pegar el servo de la base al que nos regula la altura.
Procedimiento

Esto ha sido de paciencia, por ejemplo, es importante inicialmente usar un programa para leer la posición actual de los servomotores, creo que por eso fue que se quemamos dos SG90, debido a que en el gancho hacían mucha fuerza para cerrarse luego de que ya estaba cerrado al iniciar el programa, tener claro en qué ángulo está al iniciar.

Programa


#include <Servo.h>

Servo baseServo;   // Servo para el giro horizontal
Servo alturaServo; // Servo para subir y bajar el brazo
Servo ganchoServo; // Servo para abrir o cerrar el gancho

int baseAngle = 90;    // Ángulo inicial del servo horizontal
int alturaAngle = 90;  // Ángulo inicial del servo de altura
int ganchoAngle = 90;  // Ángulo inicial del servo de gancho


const int joyXPin = A0;   // Pin analógico para la posición X del joystick
const int joyYPin = A1;   // Pin analógico para la posición Y del joystick
const int joyYGPin = A2;   // Pin analógico para la posición X del joystick2 gancho

int baseIncremento = 1; // Incremento de ángulo para el servo de la base
int alturaIncremento = 1; // Incremento de ángulo para el servo de la altura
int ganchoIncremento = 1; // Incremento de ángulo para el servo del gancho

void setup() {
  Serial.begin(9600);  // Inicializa la comunicación serial
  baseServo.attach(8);    // Conecta el servo horizontal al pin 8
  alturaServo.attach(9);  // Conecta el servo de altura al pin 9
  ganchoServo.attach(7);  // Conecta el servo de gancho al pin 10

  baseAngle = baseServo.read();
  alturaAngle = alturaServo.read();
  ganchoAngle = ganchoServo.read();

}

void loop() {
   
  int joyX = analogRead(joyXPin);
  int joyY = analogRead(joyYPin);
  int joyYG = analogRead(joyYGPin);

  // Control de la base (eje X)
  baseAngle += map(joyX, 0, 1023, baseIncremento, -baseIncremento);
  baseAngle = constrain(baseAngle, 0, 180);

  // Control de la altura (eje Y)
  alturaAngle += map(joyY, 0, 1023, -alturaIncremento, alturaIncremento);
  alturaAngle = constrain(alturaAngle, 0, 126);

  // Control de apertura gancho (eje X)
  ganchoAngle += map(joyYG, 0, 1023, ganchoIncremento, -ganchoIncremento);
  ganchoAngle = constrain(ganchoAngle, 86, 180);

 // Envía las señales a los servos
  baseServo.write(baseAngle);
  alturaServo.write(alturaAngle);
  ganchoServo.write(ganchoAngle);

  // Muestra información en el Monitor Serie
  Serial.print("Base: ");
  Serial.print(baseAngle);
  Serial.print(" Altura: ");
  Serial.print(alturaAngle);
  Serial.print(" Gancho: ");
  Serial.println(ganchoAngle);
  delay(50);  // Pequeña pausa para estabilidad
}

miércoles, 4 de octubre de 2023

Proyecto AgroIN primer prototipo

 

Esta es nuestro primer intento este año 2023 de hacer un cultivo interior, para esta ocasión rescatamos unas tiras led que nos habían regalado por si nos servían, al igual que una pequeña estructura en madera con la que se hacen los desayunos sorpresa, así mismo utilizamos una botella pet de 5 litros en forma de maceta con autoriego por capilaridad, aún no tiene nada de control la iluminación, pero ese será nuestro siguiente paso poder controlar el color de acuerdo a la etapa de crecimiento de la lechuga. Hay mucho por experimentar, por aprender.

martes, 3 de octubre de 2023

Caterpilla Laboratorio de Innovación + Control

 


Este proyecto es muy entretenido para los estudiantes, pero al programa original se le debieron hacer algunas modificaciones para que funcionará, aquí el pdf sobre el proyecto,

Proyecto con Micro:Rover Kit

 Los archivos para desarrollar este proyecto se encuentran en https://freenove.com/fnk0037 tener en cuenta que este kit se puede adquirir en Amazon hace un buen tiempo lo adquirí para jugar con mis hijos pero aún son muy pequeños para trabajarlo, por eso lo estoy usando con mis estudiantes.

Utilicé una pila 18650 que conseguí al desarmar la batería de una laptop. La versión que tengo de la microbit es la V1 pero funciona también con la V2, en esta ocasión estamos usando el proyecto 03.3_Obstacle-Avoidance-2 
El archivo lo puede descargar aquí




Microbit Carro a Control Remoto con Microbit y Tarjeta de Expansión

Programa receptor RX https://makecode.microbit.org/_0JyXaq... 

Programa tarjeta transmisora TX https://makecode.microbit.org/_b7j4K4... 









domingo, 1 de octubre de 2023

Comipec Versión 1 de 2023. Dispensador de alimentos granulados para peces o mascotas

 

Este año hemos retomado un proyecto que iniciamos hace una decada y por cuestiones de tiempo y de traslado del coordinador del semillero tecnonarnajal, se había dejado en el olvido.
Esta es la versión 1 de este año 2023, la cual consta de un servomotor SG90 que hace apertura y cierre de la salida de la botella pet de 2.5l que estamos usando, al servo se le ha unido dos tapas, la primera de su misma botella, pero al ver que no alcanzaba a tapar la boca de esta se le montó una tapa de una garrafa de 5 litros, la programación es muy sencilla realizada con la microbit, recuerde instalar primero la extensión SERVO


Las conexiones son tres, PIN0 al amarillo del servomotor, GND al negro o café del servo, y 3V al rojo del servo, cuando lo probamos con el pc no funcionó, sonaba el servo pero no se movía, pensabamos que tenía algún problema el servo, lo cambiamos por otro pero seguía igual, decidimos más bien conectar el cable micro USB a un cargador de teléfono y wuala, funcionó. Luego compartiremos el video, este es el primer prototipo, la idea es que sea programable de acuerdo a la biomasa del estanque y que pueda ayudar a monitorear la temperatura del estanque para saber el momento ideal para proporcionar el alimento.

lunes, 7 de noviembre de 2022

Canal de Youtube del profe Noé

Canal de Youtube del profe Noé donde podrás consultar algunos videos relacionados con el semillero Tecnonaranjal y muchos sobre programación, electrónica, robótica y matemáticas.

 https://www.youtube.com/channel/UCSJo-c_HHXmMT0yzLadJTVA



jueves, 27 de octubre de 2022

Esp8266 y Thingspeak para monitorear la temperatura y la humedad relativa

 En la entrada anterior aprendimos a conectar el NodeMCU Esp8266 al ide de Arduino, ahora veremos como hacer que los datos que nos entrega el sensor DHT11 los podamos ver en una página web que promueve el IoT esta es thingspeak.com

La primera parte del siguiente video nos muestra como usar ThingSpeak





Funcionó!!!