Victor VidjeabascaraneDavid LamootNoé B.
Published

Smart greenhouse

An irrigation system intended for a greenhouse.

IntermediateShowcase (no instructions)740
Smart greenhouse

Things used in this project

Hardware components

DHT22 Temperature Sensor
DHT22 Temperature Sensor
×1
Adafruit Waterproof DS18B20 Digital temperature sensor
Adafruit Waterproof DS18B20 Digital temperature sensor
×1
DFRobot soil moisture sensor SEN0308
×1
DFRobot luminosity sensor SEN0390
×1
Pololu 3.3V Step-Up/Step-Down Voltage Regulator S7V8F3
×2
H bridge DRV8838
×1
Arduino MKR WAN 1310
Arduino MKR WAN 1310
×1
Espressif ESP32 camera
×1
Seeed Studio Grove wire
×1
Solenoid valve
×1
Plastic Enclosure, Project Box
Plastic Enclosure, Project Box
×2
Watering kit
×1
Li-Ion Battery 1000mAh
Li-Ion Battery 1000mAh
×1
wire
×1
Adafruit TLV6569 3.3 V regulator
×1
watering connection
×2
faucet nose
×2
pipe
×1
Lipo rider
×1
Solar panel 3W
×1
Big wire
×1
thermal sheath
×1
Rocker Switch, SPST
Rocker Switch, SPST
×1
Jumper wires (generic)
Jumper wires (generic)
×1

Software apps and online services

Arduino IDE
Arduino IDE
Agriflow (Ubidot could be an alternative)
KiCad
KiCad
The thing Network
Ubidots
Ubidots

Hand tools and fabrication machines

Bantam Tools Desktop PCB Milling Machine
Bantam Tools Desktop PCB Milling Machine
Drill / Driver, Cordless
Drill / Driver, Cordless
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
3D Printer (generic)
3D Printer (generic)
Multitool, Screwdriver
Multitool, Screwdriver
conn drill bit
Hot glue gun (generic)
Hot glue gun (generic)

Story

Read more

Schematics

PCB schematic

PCB track

PCB in 3D

Complete PCB

Code

MKRWAN_test1812.ino

Arduino
#include <MKRWAN.h>
#include "ArduinoLowPower.h"
#include "Air_Hum_temp.hpp"
#include "Hum_sol.hpp"
#include "Luminosite.hpp"
#include "Temp_sol.hpp"
#include "Electrovanne.hpp"
#include "Batterie.hpp"
#include "Allumer_ESP.hpp"
#include "Conversion.hpp"

//int Done = 11;
#define enableCapteur 12
#define SHDN  8
#define Sleep  2
#define enableESP 10

//Duree
int frequenceCapteur = 600000; // 10 minutes en ms
int frequenceEsp = 43200000; //12 heures en ms
int dureeOuvertureElectrovanne = 5; //5 secondes
unsigned long currentMillis = 43200000; //Pour prendre une photo au dmarage du systme
unsigned long previousMillis = 0;

LoRaModem modem;

//Find this on your TTN account 
String appEui = "";
String appKey = "";

bool connected;
int err_count;
short con; 
void setup() {
  //Serial.begin(115200);
  setup_electrovanne();
  setup_dht();
  setup_lum();
  //pinMode(Done,OUTPUT);
  //pinMode(enableCapteur,OUTPUT);
  pinMode(SHDN,OUTPUT);
  pinMode(Sleep,OUTPUT);
  pinMode(enableESP,OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  //while (!Serrial);
  modem.begin(EU868);
  delay(1000);
  connected=false;
  err_count=0;
  con =0;
}

void loop() {
  //Dmarrage systme
  digitalWrite(LED_BUILTIN, HIGH);

  digitalWrite(enableCapteur,HIGH); //Alimentation des capteurs active
  //digitalWrite(Delay,HIGH);
  delay(1000);
  digitalWrite(SHDN,LOW); //Alimentation pont en H dsactive
  digitalWrite(Sleep,LOW); //Pont en H en mode sleep
  digitalWrite(enableESP,LOW); //ESP non aliment
  delay(1000);

  //Rcupration donne capteur
  short hum_air_short = (short)(humidity_dht());
  short temp_air_short = (short)(temp_dht());
  short temp_sol_short = (short)(temp_sol());
  delay(500);
  temp_sol_short = (short)(temp_sol());
  short hum_sol_short = (short) (hum_sol());
  short lum_short = (short) (lum());
  short battery_short = (short) (battery());
  short electrovanne = (short) 0; //lectrovanne ferme

  //Arrosage
  if (hum_sol()/10 < 25){ //Arrosage si humidit infrieur  25%
    digitalWrite(SHDN,HIGH); //Alimentation pont en H
    digitalWrite(Sleep,HIGH); //Pont en H quitte le mode sleep
    ouverture_fermeture(dureeOuvertureElectrovanne);
    digitalWrite(SHDN,LOW); //Coupe alimentation pont en H
    delay(500);
    digitalWrite(Sleep,LOW); //Pont en H en mode sleep
    electrovanne = (short) 1; // lectrovanne ouverte
  }

  //ESP
  if (currentMillis - previousMillis >= frequenceEsp){ //Prend une photo  chaque fois que l'intervalle coul est pass
    currentMillis = millis();
    previousMillis = currentMillis;
    allumer_ESP();
  }

  //Envoi donnes
  char msg[2] = {3,4};
  short test = 27; 
  if ( !connected ) {
    //Serial.print("Join test : ");
    //Serial.println(++con);
    int ret=modem.joinOTAA(appEui, appKey);
    if ( ret ) {
      connected=true;
      modem.minPollInterval(60);
      //Serial.println("Connected");
      modem.dataRate(5);   // switch to SF7
      delay(100);          // because ... more stable
      err_count=0;
    }
  }
  if ( connected ) {
    int err=0;
    modem.beginPacket();
    modem.write(temp_air_short);
    modem.write(hum_air_short);
    modem.write(temp_sol_short);
    modem.write(hum_sol_short);
    modem.write(lum_short);
    modem.write(battery_short);
    modem.write(electrovanne);

    err = modem.endPacket();
    if ( err <= 0 ) {
      //Serial.print("Error : ");
      //Serial.println(err);
      // Confirmation not received - jam or coverage fault
      err_count++;
      if ( err_count > 50 ) {
        connected = false;
      }
      // wait for 2min for duty cycle with SF12 - 1.5s frame
      for ( int i = 0 ; i < 120 ; i++ ) {
        delay(1000);
      }
    } else {
      err_count = 0;
      // wait for 20s for duty cycle with SF7 - 55ms frame
      delay(20000);
      //Serial.println("Message envoy");  
    } 
  }

  //Downlinks
  char rcv[64];
  int i = 0;
  while (modem.available()){
    rcv[i++] = (char) modem.read();
  }
  if ((int)rcv[0] == 1){
    frequenceCapteur = minutesToMilliseconds((int)rcv[1]);
  }
  else if (rcv[0] == 2){
    frequenceEsp = hoursToMilliseconds((int)rcv[1]);
  }
  else if (rcv[0] == 3){
    dureeOuvertureElectrovanne = (int)rcv[1];
  }

  //Coupure alimentation capteur
  digitalWrite(enableCapteur,LOW); 
  
  //Duree de fonctionnement du systeme
  currentMillis = millis();

  //Consommation
  if (battery()/100 < 20){
      digitalWrite(LED_BUILTIN, LOW);
      LowPower.deepSleep(frequenceCapteur);
  }
  else{
      digitalWrite(LED_BUILTIN, LOW);
      LowPower.sleep(frequenceCapteur);
  }
  //digitalWrite(Delay,LOW);
  //digitalWrite(enableCapteur,LOW); 
  //delay(60000);
}

ESP32CAM_Drive.ino

Arduino
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "Base64.h"
#include "esp_camera.h"
//======================================== 

//======================================== CAMERA_MODEL_AI_THINKER GPIO.
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27

#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22
//======================================== 

// LED Flash PIN (GPIO 4)
#define FLASH_LED_PIN 4

//======================================== Enter your WiFi ssid and password.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
//======================================== 

//======================================== Replace with your "Deployment ID" and Folder Name.
String myDeploymentID = "REPLACE_WITH_YOUR_DEPLOYMENT_ID";
String myMainFolderName = "ESP32-CAM";
//======================================== 

//======================================== Variables for Timer/Millis.
unsigned long previousMillis = 0; 
const int Interval = 30000; //--> Capture and Send a photo every 30 seconds.
//======================================== 

// Variable to set capture photo with LED Flash.
// Set to "false", then the Flash LED will not light up when capturing a photo.
// Set to "true", then the Flash LED lights up when capturing a photo.
bool LED_Flash_ON = true;

// Initialize WiFiClientSecure.
WiFiClientSecure client;

//________________________________________________________________________________ Test_Con()
// This subroutine is to test the connection to "script.google.com".
void Test_Con() {
  const char* host = "script.google.com";
  while(1) {
    Serial.println("-----------");
    Serial.println("Connection Test...");
    Serial.println("Connect to " + String(host));
  
    client.setInsecure();
  
    if (client.connect(host, 443)) {
      Serial.println("Connection successful.");
      Serial.println("-----------");
      client.stop();
      break;
    } else {
      Serial.println("Connected to " + String(host) + " failed.");
      Serial.println("Wait a moment for reconnecting.");
      Serial.println("-----------");
      client.stop();
    }
  
    delay(1000);
  }
}
//________________________________________________________________________________ 

//________________________________________________________________________________ SendCapturedPhotos()
// Subroutine for capturing and sending photos to Google Drive.
void SendCapturedPhotos() {
  const char* host = "script.google.com";
  Serial.println();
  Serial.println("-----------");
  Serial.println("Connect to " + String(host));
  
  client.setInsecure();

  //---------------------------------------- The Flash LED blinks once to indicate connection start.
  digitalWrite(FLASH_LED_PIN, HIGH);
  delay(100);
  digitalWrite(FLASH_LED_PIN, LOW);
  delay(100);
  //---------------------------------------- 

  //---------------------------------------- The process of connecting, capturing and sending photos to Google Drive.
  if (client.connect(host, 443)) {
    Serial.println("Connection successful.");
    
    if (LED_Flash_ON == true) {
      digitalWrite(FLASH_LED_PIN, HIGH);
      delay(100);
    }

    //.............................. Taking a photo.
    Serial.println();
    Serial.println("Taking a photo...");
    
    for (int i = 0; i <= 3; i++) {
      camera_fb_t * fb = NULL;
      fb = esp_camera_fb_get();
       if(!fb) {
          Serial.println("Camera capture failed");
          Serial.println("Restarting the ESP32 CAM.");
          delay(1000);
          ESP.restart();
          return;
        } 
      esp_camera_fb_return(fb);
      delay(200);
    }
  
    camera_fb_t * fb = NULL;
    fb = esp_camera_fb_get();
    if(!fb) {
      Serial.println("Camera capture failed");
      Serial.println("Restarting the ESP32 CAM.");
      delay(1000);
      ESP.restart();
      return;
    } 
  
    if (LED_Flash_ON == true) digitalWrite(FLASH_LED_PIN, LOW);
    
    Serial.println("Taking a photo was successful.");
    //.............................. 

    //.............................. Sending image to Google Drive.
    Serial.println();
    Serial.println("Sending image to Google Drive.");
    Serial.println("Size: " + String(fb->len) + "byte");
    
    String url = "/macros/s/" + myDeploymentID + "/exec?folder=" + myMainFolderName;

    client.println("POST " + url + " HTTP/1.1");
    client.println("Host: " + String(host));
    client.println("Transfer-Encoding: chunked");
    client.println();

    int fbLen = fb->len;
    char *input = (char *)fb->buf;
    int chunkSize = 3 * 1000; //--> must be multiple of 3.
    int chunkBase64Size = base64_enc_len(chunkSize);
    char output[chunkBase64Size + 1];

    Serial.println();
    int chunk = 0;
    for (int i = 0; i < fbLen; i += chunkSize) {
      int l = base64_encode(output, input, min(fbLen - i, chunkSize));
      client.print(l, HEX);
      client.print("\r\n");
      client.print(output);
      client.print("\r\n");
      delay(100);
      input += chunkSize;
      Serial.print(".");
      chunk++;
      if (chunk % 50 == 0) {
        Serial.println();
      }
    }
    client.print("0\r\n");
    client.print("\r\n");

    esp_camera_fb_return(fb);
    //.............................. 

    //.............................. Waiting for response.
    Serial.println("Waiting for response.");
    long int StartTime = millis();
    while (!client.available()) {
      Serial.print(".");
      delay(100);
      if ((StartTime + 10 * 1000) < millis()) {
        Serial.println();
        Serial.println("No response.");
        break;
      }
    }
    Serial.println();
    while (client.available()) {
      Serial.print(char(client.read()));
    }
    //.............................. 

    //.............................. Flash LED blinks once as an indicator of successfully sending photos to Google Drive.
    digitalWrite(FLASH_LED_PIN, HIGH);
    delay(500);
    digitalWrite(FLASH_LED_PIN, LOW);
    delay(500);
    //.............................. 
  }
  else {
    Serial.println("Connected to " + String(host) + " failed.");
    
    //.............................. Flash LED blinks twice as a failed connection indicator.
    digitalWrite(FLASH_LED_PIN, HIGH);
    delay(500);
    digitalWrite(FLASH_LED_PIN, LOW);
    delay(500);
    digitalWrite(FLASH_LED_PIN, HIGH);
    delay(500);
    digitalWrite(FLASH_LED_PIN, LOW);
    delay(500);
    //.............................. 
  }
  //---------------------------------------- 

  Serial.println("-----------");

  client.stop();
}
//________________________________________________________________________________ 

//________________________________________________________________________________ VOID SETUP()
void setup() {
  // put your setup code here, to run once:
  
  // Disable brownout detector.
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
  
  Serial.begin(115200);
  Serial.println();
  delay(1000);

  pinMode(FLASH_LED_PIN, OUTPUT);
  
  // Setting the ESP32 WiFi to station mode.
  Serial.println();
  Serial.println("Setting the ESP32 WiFi to station mode.");
  WiFi.mode(WIFI_STA);

  //---------------------------------------- The process of connecting ESP32 CAM with WiFi Hotspot / WiFi Router.
  Serial.println();
  Serial.print("Connecting to : ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  
  // The process timeout of connecting ESP32 CAM with WiFi Hotspot / WiFi Router is 20 seconds.
  // If within 20 seconds the ESP32 CAM has not been successfully connected to WiFi, the ESP32 CAM will restart.
  // I made this condition because on my ESP32-CAM, there are times when it seems like it can't connect to WiFi, so it needs to be restarted to be able to connect to WiFi.
  int connecting_process_timed_out = 20; //--> 20 = 20 seconds.
  connecting_process_timed_out = connecting_process_timed_out * 2;
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    digitalWrite(FLASH_LED_PIN, HIGH);
    delay(250);
    digitalWrite(FLASH_LED_PIN, LOW);
    delay(250);
    if(connecting_process_timed_out > 0) connecting_process_timed_out--;
    if(connecting_process_timed_out == 0) {
      Serial.println();
      Serial.print("Failed to connect to ");
      Serial.println(ssid);
      Serial.println("Restarting the ESP32 CAM.");
      delay(1000);
      ESP.restart();
    }
  }

  digitalWrite(FLASH_LED_PIN, LOW);
  
  Serial.println();
  Serial.print("Successfully connected to ");
  Serial.println(ssid);
  //Serial.print("ESP32-CAM IP Address: ");
  //Serial.println(WiFi.localIP());
  //---------------------------------------- 

  //---------------------------------------- Set the camera ESP32 CAM.
  Serial.println();
  Serial.println("Set the camera ESP32 CAM...");
  
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  
  // init with high specs to pre-allocate larger buffers
  if(psramFound()){
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 5;  //0-63 lower number means higher quality
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 2;  //0-63 lower number means higher quality
    config.fb_count = 1;
  }
  
  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    Serial.println();
    Serial.println("Restarting the ESP32 CAM.");
    delay(1000);
    ESP.restart();
  }

  sensor_t * s = esp_camera_sensor_get();

  // Selectable camera resolution details :
  // -UXGA   = 1600 x 1200 pixels
  // -SXGA   = 1280 x 1024 pixels
  // -XGA    = 1024 x 768  pixels
  // -SVGA   = 800 x 600   pixels
  // -VGA    = 640 x 480   pixels
  // -CIF    = 352 x 288   pixels
  // -QVGA   = 320 x 240   pixels
  // -HQVGA  = 240 x 160   pixels
  // -QQVGA  = 160 x 120   pixels
  s->set_framesize(s, FRAMESIZE_SXGA);  //--> UXGA|SXGA|XGA|SVGA|VGA|CIF|QVGA|HQVGA|QQVGA

  Serial.println("Setting the camera successfully.");
  Serial.println();

  delay(1000);

  Test_Con();

  Serial.println();
  Serial.println("ESP32-CAM captures and sends photos to the server every 60 seconds.");
  Serial.println();
  delay(2000);
}
//________________________________________________________________________________ 

//________________________________________________________________________________ VOID LOOP()
void loop() {
  // put your main code here, to run repeatedly:

  //---------------------------------------- Timer/Millis to capture and send photos to Google Drive every 20 seconds (see Interval variable).
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= Interval) {
    previousMillis = currentMillis;

    SendCapturedPhotos();
  }
  //---------------------------------------- 
}
//________________________________________________________________________________ 
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

Code

Credits

Victor Vidjeabascarane
1 project • 1 follower
David Lamoot
1 project • 1 follower
Noé B.
1 project • 1 follower

Comments