sweet_love (auto-cultivo con Arduino)

alejokaban

Crecimiento
17 Febrero 2013
92
66
23
Hola comunidad,

Primero que todo les presento disculpas (especialmente a @Zion Lion) porque esto lo debí haber hecho hace mucho tiempo. En esa época @Zion Lion estaba trabajando en un Cultivo con Arduino + LED y construyó el EasyGrowWeed. Con las partes que él me suministró más otras que compré y usando su idea original escribí un programa desde cero. Es un sistema embebido automático de control para cultivos, diseñado para ser implementado en Arduino (Mega en este caso). El programa está escrito en full c++ y utiliza librerías MUY actualizadas que incluso no existían hace unos años cuando todo comenzó.

Estas son las partes utilizadas:

- fuente suicheada S-40-12 12v 3.2A 38w
fuente suicheada S-40-12 12v 3.2A 38w 1.jpg

- regulador protoboard mb102
regulador protoboard mb102.jpg

- arduino mega 2560
arduino mega 2560.jpg

- 16x2 LCD keypad shield
LCD keypad shield.png

- reloj de tiempo real DS3232
real time clock DS3232.jpg

- sensor de humedad en suelo FC-28
Soil-Hygrometer-Detection-Module-Moisture-Sensor-FC-28-DC-3-3V-5V.jpg

- sensor de temperatura y humedad en aire DHT22
DHT22 temperature humidity sensor.jpg

- módulo réle de 2 canales opto-aislado 5v 10A
modulo rele 2 canales opto aislado 5v.jpg


- mini bomba de agua 12v 3.6W
mini bomba de agua 12v.jpg


(agradecimientos a @Zion Lion por su aporte)


Este es el diagrama de conexiones (realizado en Fritzing).

sweet_love_bb.png


Este es el código:

Código:
/* nombre clave: sweet_love v0.11
   sistema de control manual y automático para cultivos
   escrito por: alexokaban (alexokaban@gmail.com)
   idea original (EasyGrowWeed) y soporte de partes: Zion Lion
   agradecimiento especial a Zion Lion por el envío de partes
   código libre para el uso de la comunidad.   
   julio de 2019 */

#include <DHT.h>    // https://github.com/alexokaban/DHT-sensor-library
#include <DHT_U.h>
#include <Adafruit_Sensor.h>    // https://github.com/alexokaban/Adafruit_Sensor
#include <DS3232RTC.h>      // https://github.com/alexokaban/DS3232RTC
#include <MD_UISwitch.h>    // https://github.com/alexokaban/MD_UISwitch
#include <SoftTimer.h>    // https://github.com/alexokaban/arduino-softtimer
#include <hd44780.h>    // https://github.com/alexokaban/hd44780
#include <hd44780ioClass/hd44780_pinIO.h>   // Arduino pin i/o class header
#include <Streaming.h>    // http://arduiniana.org/libraries/streaming/

// LCD pin setup
const int rs=8, en=9, db4=4, db5=5, db6=6, db7=7;
hd44780_pinIO lcd(rs, en, db4, db5, db6, db7);

int LCD_select;   // variable que indica una pantalla de 5 posibles
// 1: tiempo/fecha, 2: sensores, 3 y 4: control manual, 5 y 6: control automático, 7: foto-periodo
const int LCD_date_time = 1;
const int LCD_sensors = 2;
const int LCD_ctrl_lamp = 3;
const int LCD_ctrl_plump = 4;
const int LCD_auto_lamp = 5;
const int LCD_auto_plump = 6;
const int LCD_lamp_cycle = 7;

// LCD geometry
const int LCD_COLS = 16;    // columnas
const int LCD_ROWS = 2;     // filas

uint8_t degree_char[8]  = {0x18,0x18,0x00,0x07,0x08,0x08,0x08,0x07};    // caracter de grado
uint8_t arrow_char[8]  = {0x00,0x00,0x04,0x06,0x1F,0x06,0x04,0x00};     // flecha

// variables for the key_pad
const uint8_t ANALOG_SWITCH_PIN = A0;       // switches connected to this pin
MD_UISwitch_Analog::uiAnalogKeys_t kt[] = {
  {  10, 10, 'R' },  // Right
  { 130, 15, 'U' },  // Up
  { 305, 15, 'D' },  // Down
  { 475, 15, 'L' },  // Left
  { 720, 15, 'S' },  // Select
};
MD_UISwitch_Analog keypad(ANALOG_SWITCH_PIN, kt, ARRAY_SIZE(kt));

// variables for controls and sensors
const int ctrl_relay_lamp = 50;   // pin de salida digital al relé que controla la lampára
const int ctrl_relay_plump = 52;    // pin de salida al relé que controla la bomba de agua
volatile bool ctrl_lamp_ON = false;   // bandera de estado para el control manual de la lampára
volatile bool ctrl_plump_ON = false;    // bandera de estado de para el control manual la bomba de agua
volatile bool auto_lamp_ON = false;   // bandera de estado para el control automático de la lámpara
volatile bool auto_plump_ON = false;    // bandera de estado para el control automático de la bomba de agua
volatile bool ctrl_lamp_cycle = false;    // bandera que indica el foto-periodo FALSE = 18/6 y TRUE = 12/12

// for soil moisture sensor HL28
#define HL28_pin A2    // analog pin to connect the soil moisture sensor
volatile bool HL28_get = false;   // flag to get the reading of moisture in the soil
volatile int HL28_maped_value;    // variable para guardar el valor mapeado
volatile int HL28_analog_value;   // variable para guardar el valor leído por el sensor HL-28
const int HL28_dry_soil = 500;    // constante de sustrato seco para activar la bomba de agua
const int HL28_wet_soil = 200;    // constante de sustrato humedo para detener la bomba de agua
int HL28_plump_count;    // contador para realizar lecturas de humedad de acuerdo al estado de la bomba de agua
bool HL28_first_reading = false;    // bandera para realizar la 1ra lectura del sensor HL-28

// for temperature & humidity sensor DHT22
#define DHT_pin A1    // entrada pin análogo al sensor DHT22
#define DHT_type DHT22
DHT dht(DHT_pin, DHT_type);
volatile float DHT_airhumidity;   // variables for saving sensors's values
volatile float DHT_temperature;

// variables para el RTC DS3232
#define SQW_pin 19    // connect this pin to DS3231 INT/SQW pin. entrada que recibe la señal de interrupción para las alarmas del RTC
volatile boolean RTC_alarm_call_ON = false;

const byte alarm1_hour = 16;     // hora de inicio del fotoperiodo (fija)
const byte alarm1_minute = 7;
const byte alarm1_second = 0;
const byte alarm1_day = 0;

volatile byte alarm2_hour = 16;     // hora de finalización del fotoperiodo (variable)
volatile byte alarm2_minute = 8;
volatile byte alarm2_second = 0;
volatile byte alarm2_day = 0;

// -- define method signature
void callBack1(Task* me);
void callBack2(Task* me);
void callBack3(Task* me);
void callBack4(Task* me);
void callBack5(Task* me);

// define las tareas y cada cuantos milisegundos se realizan
Task lcd_show(100, callBack1);   // mostrar una pantalla del estado del sistema en el LCD
Task key_check(10, callBack2);    // revisar si una tecla ha sido presionada
Task DHT_check(3000, callBack3);    // realizar una lectura del sensor DHT22
Task HL28_short_check(1000, callBack4);   // lecturas del sensor HL-28 con intervalo corto
Task HL28_long_check(60000, callBack5);   // ... con intervalo largo

void setup() {

  // inicializa controles
  pinMode(ctrl_relay_lamp, OUTPUT);     // initialize digital pin 50 as an relay output.
  digitalWrite(ctrl_relay_lamp, HIGH);    // inicializa la lámpara apagada (lógica inversa)

  pinMode(ctrl_relay_plump, OUTPUT);     // initialize digital pin 52 as an relay output.
  digitalWrite(ctrl_relay_plump, HIGH);   // inicializa la bomba apagada

  keypad.begin();     // inicializa la clase MD_UISwitch_Analog

  // inicializa sensores
  pinMode(HL28_pin, INPUT);
  dht.begin();      // inicializa el objeto dht

  // inicializa y configura el RTC DS3232 y sus dos alarmas
 
  // esta porción de código debe ser aplicada una sola vez para cargar el tiempo en el RTC
  /*time_t t = compileTime();        // change the tm structure into time_t
  RTC.set(t);*/
 
  RTC.squareWave(SQWAVE_NONE);      // desactiva la onda cuadrada del RTC

  // las alarmas 1 y 2 del RTC se utilizan para controlar el fotoperiodo. ALARM_1 marca el inicio del ciclo y ALARM_2 el final
  // sintaxis: setAlarm(ALARM_TYPES_t alarmType, byte seconds, byte minutes, byte hours, byte daydate)
 
  //RTC.setAlarm(ALM1_MATCH_HOURS, 0, 0, 6, 0);     // inicializa ALARM_1 a las 6am de todos los días (0)
  RTC.setAlarm(ALM1_MATCH_HOURS, alarm1_second, alarm1_minute, alarm1_hour, alarm1_day);
  RTC.alarm(ALARM_1);
  RTC.alarmInterrupt(ALARM_1, true);

  //RTC.setAlarm(ALM2_MATCH_HOURS, 0, 0, 18, 0);      // ALARM_2 a las 6pm
  RTC.setAlarm(ALM2_MATCH_HOURS, alarm2_second, alarm2_minute, alarm2_hour, alarm2_day);
  RTC.alarm(ALARM_2);
  RTC.alarmInterrupt(ALARM_2, true); 

  // setSyncProvider() causes the Time library to synchronize with the
  // external RTC by calling RTC.get() every five minutes by default.
  setSyncProvider(RTC.get);   // the function to get the time from the RTC

  pinMode(SQW_pin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(SQW_pin), RTC_alarm_call, FALLING);

  // inicializa el LCD
  lcd.begin(LCD_COLS, LCD_ROWS);
  lcd.createChar(0, degree_char);   // crea caracter de grado
  lcd.createChar(1, arrow_char);    // .. flecha
 
  LCD_select = LCD_date_time;   // 1ra pantalla de tiempo/fecha
  SoftTimer.add(&lcd_show);   // agrega las tareas definidas a la librería SoftTimer
  SoftTimer.add(&key_check);
  SoftTimer.add(&DHT_check);
  SoftTimer.add(&HL28_short_check);
  SoftTimer.add(&HL28_long_check);

  Serial.begin(115200);    // para pruebas
  printDateTime(RTC.get());
  Serial << " --> Current RTC time\n";
}
// utility function for digital clock display: prints preceding colon and leading 0
void print_Digits(int digits) {
  if (digits < 10)     
    lcd.print('0');
    lcd.print(digits);
    }

void callBack1(Task* me) {    // muestra una de cuatro pantallas posibles en el LCD

/* como este programa no tiene la función de blucle infinito loop(), entonces
   la interrupción generada por el RTC al activarsen las alarmas se procesa
   aquí al principio de la tarea que actualiza la pantalla del LCD*/

  if(RTC_alarm_call_ON == true && auto_lamp_ON == true ) {
    if (RTC.alarm(ALARM_1)) {     // si al ALARM_1 se activa indica el inicio del ciclo
      printDateTime( RTC.get() );
      Serial << " --> Alarm 1\n";     
      digitalWrite(ctrl_relay_lamp, LOW);     // ... entonces prende la lámpara     
      ctrl_lamp_ON = true;
      }
    if (RTC.alarm(ALARM_2)) {     // si al ALARM_2 se activa indica el final del ciclo
      printDateTime( RTC.get() );     
      Serial << " --> Alarm 2\n";
      digitalWrite(ctrl_relay_lamp, HIGH);     // ... entonces apaga la lámpara     
      ctrl_lamp_ON = false;
      }
    RTC_alarm_call_ON = false;      // limpia la bandera de llamado por interrupción de las alarmas del RTC
    }
    
    lcd.clear();      // limpia la pantalla del LCD
  switch(LCD_select) {      // analiza cuál pantalla ha sido seleccionada para mostrar en el LCD   
    case LCD_date_time:     // imprime en pantalla tiempo / fecha
      lcd.setCursor(0,0);
      lcd.print("DATE: ");
      lcd.setCursor(6,0);
      print_Digits(day());
      lcd.print('/');   
      print_Digits(month());
      lcd.print('/');
      lcd.print(year());
  
      lcd.setCursor(0,1);   
      lcd.print("TIME: ");
      lcd.setCursor(6,1);
      print_Digits(hour());
      lcd.print(':');
      print_Digits(minute());
      lcd.print(':');
      print_Digits(second());
      break;   
    
    case LCD_sensors:     // imprime en pantalla las lecturas de los sensores DHT22 y HL-28
      lcd.setCursor(0,0);
      lcd.print("T:");
      lcd.setCursor(2,0);
      lcd.print(DHT_temperature);
      lcd.write(0);

      lcd.setCursor(0,1);     
      lcd.print("A:");
      lcd.setCursor(2,1);
      lcd.print(DHT_airhumidity);
      lcd.print("%");

      lcd.setCursor(9,1);
      lcd.print("S:");
      lcd.setCursor(12,1);
      lcd.print(HL28_maped_value);
      lcd.print("%");           
      break;
      
    case LCD_ctrl_lamp:     //  imprime en pantalla el estado de la lámpara y la bomba de agua y permite prenderlas / apagarlas
      lcd.setCursor(0,0);
      lcd.write(1);
      lcd.setCursor(1,0);
      lcd.print(" ");
      LCD_ctrl_show(); 
      break;
      
    case LCD_ctrl_plump:
      lcd.setCursor(0,1);
      lcd.write(1);
      lcd.setCursor(1,1);
      lcd.print(" ");
      LCD_ctrl_show();
      break;

    case LCD_auto_lamp:     // imprime en pantalla el estado de los controles automáticos y permite activarlos / desactivarlos
      lcd.setCursor(0,0);
      lcd.write(1);
      lcd.setCursor(1,0);
      lcd.print(" ");
      LCD_ctrl_show();
      break;

    case LCD_auto_plump:
      lcd.setCursor(0,1);
      lcd.write(1);
      lcd.setCursor(1,1);
      lcd.print(" ");
      LCD_ctrl_show();
      break;

    case LCD_lamp_cycle:
      lcd.setCursor(0,0);
      lcd.print("FOTO-PERIODO: ");
      lcd.setCursor(0,1);
      lcd.write(1);
      lcd.setCursor(1,1);
      lcd.print(" ");     
      LCD_ctrl_show();
    }
  }

void LCD_ctrl_show(void) {    // función para mostrar el estado de los controles
  switch(LCD_select) {
    case LCD_ctrl_lamp:
      LCD_ctrl_manual();
    break;

    case LCD_ctrl_plump:
      LCD_ctrl_manual();
    break;

    case LCD_auto_lamp:
      LCD_ctrl_auto();
    break;

    case LCD_auto_plump:
    LCD_ctrl_auto();
    break;

    case LCD_lamp_cycle:
      lcd.setCursor(2,1);
      if (ctrl_lamp_cycle == false) {
        lcd.print("VEGETAV. 18/6");}
      else {
        lcd.print("MADURAC. 12/12");}   
    break;
    }
  }

void LCD_ctrl_manual(void) {
  lcd.setCursor(2,0);
  lcd.print("LAMP: ");
  lcd.setCursor(8,0);
  if (ctrl_lamp_ON == false) {     
    lcd.print("OFF");}
   if (ctrl_lamp_ON == true) {     
     lcd.print("ON");}   
 
     lcd.setCursor(2,1);
     lcd.print("BOMB: ");
     lcd.setCursor(8,1);
     if (ctrl_plump_ON == false) {     
       lcd.print("OFF");}
     if (ctrl_plump_ON == true) {     
       lcd.print("ON");}     
  }

void LCD_ctrl_auto(void) {
  lcd.setCursor(2,0);
  lcd.print("LAMP.AUTO: ");
  lcd.setCursor(13,0);
  if (auto_lamp_ON == false) {     
    lcd.print("OFF");}
  if (auto_lamp_ON == true) {     
    lcd.print("ON");}   
 
  lcd.setCursor(2,1);
  lcd.print("BOMB.AUTO: ");
  lcd.setCursor(13,1);
  if (auto_plump_ON == false) {     
    lcd.print("OFF");}
  if (auto_plump_ON == true) {     
    lcd.print("ON");}     
  }

void callBack2(Task* me) {    // revisa si ha sido presionada una tecla para navegar en el LCD
    MD_UISwitch::keyResult_t k = keypad.read();     // lee el estado del teclado
    
    if (k == MD_UISwitch::KEY_DOWN) {     // si hay un evento de presionar tecla
      
      switch(keypad.getKey()) {       // analiza cuál tecla ha sido presionada       
        
        // utiliza las teclas arriba y abajo para cambiar las posibles pantallas en el LCD
        case 'U':     // arriba
          if (LCD_select == LCD_date_time) {      // si es la 1ra pantalla
            LCD_select = LCD_lamp_cycle;}      // entonces cambia a la última pantalla
          else {
            LCD_select--;}      // sino entonces retrocede una pantalla
        break;
        
        case 'D':     // abajo
          if (LCD_select == LCD_lamp_cycle) {      // si es la última pantalla
            LCD_select = LCD_date_time;}      // entonces nuestra la primera pantalla
          else {
            LCD_select++;}      // sino entonces avanza una pantalla
        break;       
        
        // utiliza la tecla select para prender / apagar la lámpara y la bomba de agua
        case 'S':     // select
          switch (LCD_select) {
            case LCD_ctrl_lamp:
              if (ctrl_lamp_ON == true ){     // si la lámpara está encendida: la apaga
                digitalWrite(ctrl_relay_lamp, HIGH);
                ctrl_lamp_ON = false;
                }
              else {
                digitalWrite(ctrl_relay_lamp, LOW);   // sino entonces la prende
                ctrl_lamp_ON = true;
                }
            break;           
            case LCD_ctrl_plump:
              if (ctrl_plump_ON == true ) {     // si la bomba de agua está encendida: la apaga
                digitalWrite(ctrl_relay_plump, HIGH);
                ctrl_plump_ON = false;
                }
              else {
                digitalWrite(ctrl_relay_plump, LOW);   // sino entonces la prende
                ctrl_plump_ON = true;
                }
            break;
            case LCD_auto_lamp:
              if (auto_lamp_ON == true) {     // si el control automtico de la lámpara está activado: lo activa
                auto_lamp_ON = false;
                }
              else {
                auto_lamp_ON = true;      // sino entonces lo activa
              }
            break;           
            case LCD_auto_plump:
              if (auto_plump_ON == true) {     // si el control automtico de la bomba de agua está activado: lo activa
                auto_plump_ON = false;
                }
              else {
                auto_plump_ON = true;      // sino entonces lo activa
              }     
            break;         
            }
          break;

        // utiliza las tecla derecha e izquierda para cambiar el foto-periodo
        case 'R':     // derecha
          if (LCD_select == LCD_lamp_cycle) {
            
            // ctrl_lamp_cycle es una bandera que indica el foto-periodo FALSE = 18/6 y TRUE = 12/12
            if (ctrl_lamp_cycle == false){      // si el foto-periodo era 18/6
              ctrl_lamp_cycle = true;     // ... entonces lo cambia a 12/12
              //alarm2_hour = 18;     // configura la ALARM_2 para finalizar el ciclo a las 6pm
              alarm2_hour = 16;
              alarm2_minute = 9;             
              }           
            else {      // si el foto-periodo era 12/12
              ctrl_lamp_cycle = false;      // ... entonces los cambia a 18/6
              //alarm2_hour = 0;      // configura la ALARM_2 para finalizar el ciclo a las 12am
              alarm2_hour = 16;
              alarm2_minute = 8;
              }
            RTC_alarm2_set();
            }
        break;

        case 'L':     // izquierda
          if (LCD_select == LCD_lamp_cycle) {
            
            // ctrl_lamp_cycle es una bandera que indica el foto-periodo FALSE = 18/6 y TRUE = 12/12
            if (ctrl_lamp_cycle == false){      // si el foto-periodo era 18/6
              ctrl_lamp_cycle = true;     // ... entonces lo cambia a 12/12
              //alarm2_hour = 18;     // configura la ALARM_2 para finalizar el ciclo a las 6pm
              alarm2_hour = 16;
              alarm2_minute = 9;
              }           
            else {      // si el foto-periodo era 12/12
              ctrl_lamp_cycle = false;      // ... entonces los cambia a 18/6
              //alarm2_hour = 0;      // configura la ALARM_2 para finalizar el ciclo a las 12am
              alarm2_hour = 16;
              alarm2_hour = 8;
              }
            RTC_alarm2_set();
            }
        break;
      }
    }
  }

void callBack3(Task* me) {    // realiza lecturas en el sensor DHT22
  DHT_airhumidity = dht.readHumidity();     //  lee y almacena el valor de la humedad en el aire
  DHT_temperature = dht.readTemperature();      // ... de la temperatura
  }

void callBack4(Task* me) {    // realiza una lectura de intervalo corto en el sensor HL-28
  if (ctrl_plump_ON == true){       // sólo realiza lectura de intervalo corto mientras la bomba de agua está prendida
    HL28_reading();     //
    HL28_compare();
    }     
  }

void callBack5(Task* me) {    // realiza una lectura de intervalo largo en el sensor HL-28
  if (ctrl_plump_ON == false){       // sólo realiza lectura de intervalo largo mientras la bomba de agua está apagada
    HL28_reading();
    HL28_compare();
    }
  }

void HL28_reading(void){      // función para realizar una lectura de humedad en el sustrato y mapear el valor
  HL28_analog_value = analogRead(HL28_pin);     // realiza una lectura análoga del pin conectado al sensor HL-28 
  HL28_maped_value = map(HL28_analog_value, 550, 179, 0, 100);     // ubica este valor leído entre un mínimo y un máximo
  /*
     1016 sonda en sustrato completamente seco (sin planta)   
     179 sonda en sustrato completamente húmedo (sin planta) -> 100% (la bomba se desactiva al llegar a 200))

     550 sonda en sustrato seco con planta  -> 0% (la bomba se activa al llegar a 500)     
     58 -> 100% (la bomba se desactiva al llegar a 200))

     1023 sonda al aire
     450 sonda en paño humedo
     0 sonda en agua*/

  // para pruebas 
  /*Serial.println(HL28_analog_value); //lectura analógica   
  //Serial.print(HL28_maped_value); //lectura mapeada
  Serial.println("%");
  Serial.print("\n");*/       
  }

void HL28_compare(void){      // función para comparar el valor analogo obtenido con las constantes de sustrato definidas al inicio

  if (auto_plump_ON == true) {    // sólo realiza la comparación si el control automático de la bomba de agua está activado
    if (HL28_analog_value > HL28_dry_soil){     // si el valor es mayor que sustrato seco, entonces prender bomba de agua
      digitalWrite(ctrl_relay_plump, LOW);
      ctrl_plump_ON = true;
      }
    if (HL28_analog_value < HL28_wet_soil){     // si el valor es menor que sustrato humedo, entonces apagar bomba de agua
      digitalWrite(ctrl_relay_plump, HIGH);
      ctrl_plump_ON = false;
      }
    }
  }

void RTC_alarm_call(void) {
  RTC_alarm_call_ON = true;
  }

void RTC_alarm2_set(void) {
  RTC.setAlarm(ALM2_MATCH_HOURS, alarm2_second, alarm2_minute, alarm2_hour, alarm2_day);
  RTC.alarm(ALARM_2);
  RTC.alarmInterrupt(ALARM_2, true);
  }

void printDateTime(time_t t) {
    Serial << ((day(t)<10) ? "0" : "") << _DEC(day(t));
    Serial << monthShortStr(month(t)) << _DEC(year(t)) << ' ';
    Serial << ((hour(t)<10) ? "0" : "") << _DEC(hour(t)) << ':';
    Serial << ((minute(t)<10) ? "0" : "") << _DEC(minute(t)) << ':';
    Serial << ((second(t)<10) ? "0" : "") << _DEC(second(t));
}
 time_t compileTime() {       // function to return the compile date and time as a time_t value
    const time_t FUDGE(10);    //fudge factor to allow for upload time, etc. (seconds, YMMV)
    const char *compDate = __DATE__, *compTime = __TIME__, *months = "JanFebMarAprMayJunJulAugSepOctNovDec";
    char compMon[3], *m;

    strncpy(compMon, compDate, 3);
    compMon[3] = '\0';
    m = strstr(months, compMon);

    tmElements_t tm;
    tm.Month = ((m - months) / 3 + 1);
    tm.Day = atoi(compDate + 4);
    tm.Year = atoi(compDate + 7) - 1970;
    tm.Hour = atoi(compTime);
    tm.Minute = atoi(compTime + 3);
    tm.Second = atoi(compTime + 6);

    time_t t = makeTime(tm);
    return t + FUDGE;        //add fudge factor to allow for compile time
    }

Resumen de funcionamiento

El sistema controla el riego y la iluminación del cultivo. Muestra en la pantalla del LCD la siguiente información: tiempo, fecha, temperatura, humedad en aire y en sustrato, estado de los controles manuales y automáticos, así como el fotoperiodo. Puede ser configurado para realizar control manual y automático. Para el control automático del riego, utiliza la medida del sensor de humedad en el sustrato y activa el riego mediante una bomba de agua. Para el control automático de la luz, configura las alarmas del reloj de tiempo real con el foto-periodo especificado sea de crecimiento 18/6 (por defecto) o 12/12 de maduración. Los controles automáticos vienen desactivados por defecto.

Las ideas para la siguiente versión son:
- Comunicarse con el sistema por internet utilizando el ethernet shield,
- Personalizar en tiempo real el foto-periodo y los valores de referencia de sustrato húmedo y seco.

Reemplacé la sonda del sensor de humedad que viene de fabrica por una artesanal hecha con tornillos gruesos y piezas de ferretearía, de modo que si se daña por corrosión podría ser reemplazada fácilmente. De todas maneras en esta parte tuve en cuenta las dificultades presentadas anteriormente (a Zion y otros usuarios) debido a la corrosión en la sonda, entonces para este código implementé un algoritmo que usa dicha sonda y realiza una lectura de humedad sólo una vez cada minuto pero con una mayor frecuencia al momento de usar la bomba de agua para lograr detener su uso a tiempo. La corrosión la causa la lectura como tal así que reducir la frecuencia con que se hace debería extender la vida de la sonda..

Agradecimientos a todos por la comprensión. La verdad tuve un bloqueo que me impidió hacer esto antes, así que lo siento mucho.

Espero estarle cumpliendo a la comunidad y a @Zion Lion.

Saludos. Buenos humos.

Links de utilidad:
Arduino
fritzing
GitHub alexokaban
 

alejokaban

Crecimiento
17 Febrero 2013
92
66
23
IMG_20190803_101218.jpg

IMG_20190803_101238.jpg


continuación del vídeo anterior, donde la humedad quedó en 85%. activo la bomba y sube a 91%:


La moral es editar luego este post y subir fotos y vídeos de mejor calidad, y que muestren los controles automáticos.
 
Última edición:

alejokaban

Crecimiento
17 Febrero 2013
92
66
23
Que bien ponte eso.

Una idea loca, si el sensor de os humedad tiende a oxidarse, se podría hacer con algún tipo de presostato que detecte el peso de una o varias macetas en seco y húmedo.
Es una idea excelente. Ya estaba pensando en un posible inconveniente con la sonda echa de tornillos: si la maceta es muy grande en dónde ubico los tornillos? si están muy juntos puede detectar humedad aún estando seca otra parte de la maceta, si están muy separados habría que regar un montón con la bomba para que llegue el agua de un lado a otro de la maceta o habría que regar no en un sólo punto sino en varios, y si los tornillos son superficiales en relación a la profundidad de la maceta el sistema podría errar y pensar que el riego está listo cuando en la parte de abajo está aún seco.... su idea soluciona todo eso una maceta con sustrato seco tiene un peso muy distinto a una con sustrato húmedo.
 

Zintxo

Oldtimer
19 Febrero 2019
5.333
15.589
228
Es una idea excelente. Ya estaba pensando en un posible inconveniente con la sonda echa de tornillos: si la maceta es muy grande en dónde ubico los tornillos? si están muy juntos puede detectar humedad aún estando seca otra parte de la maceta, si están muy separados habría que regar un montón con la bomba para que llegue el agua de un lado a otro de la maceta o habría que regar no en un sólo punto sino en varios, y si los tornillos son superficiales en relación a la profundidad de la maceta el sistema podría errar y pensar que el riego está listo cuando en la parte de abajo está aún seco.... su idea soluciona todo eso una maceta con sustrato seco tiene un peso muy distinto a una con sustrato húmedo.
La verdad es ke me parece muy interesante, lo unico, con el presostato podrias diferenciar entre un tiesto humedo con eskeje y una planta de buen tamaño terminando de florar ya con el sustrato muy seco?
 

juanchoronga

Semilla
25 Agosto 2019
2
0
1
51
Buenas tardes a todos, es mi primera vez en esto del cultivo, arme un indoor controlado con arduino, agregando un humidificador, calefactor 8las noches son demasiado frias por estos lados -2 grados), extractor y un inyector de aire, con esto controlo humedad relativa y temperatura sin problemas por ahora que hace frio, tengo para el indoor 3 led cob de 50 w (chinos) estoy en fase vegetativa por ahora me gustaria saber los parametros de temperatura y humedad que estan usando, por el mometnto los seteos que manejo es de acuerdo a la temperatura la humedad relativa, nunca supera los 24 grados a una humedad maxima de 65-70 % esto es casi constante.

Gracias por los comentarios.
 

Adjuntos

-