
/************************************************
 * Greenhouse Control System        April 20, 2020
 * Control 8 subsystems through relays, monitor temperature, humidity and soil moisture.
 * Activate irrigation system on low soil moisture while monitoring water level.
 * Activate fan on high temp, activate heter on low temp. 
 * Last modified date: April 20, 2020
 *****************************************/
// Author: Chris Edgar

/**********************************/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <NewPing.h>
#include <dht11.h>                  

LiquidCrystal_I2C lcd(0x27,20,21);

#define TRIGGER_PIN  7  //  trig pin on the ultrasonic sensor attach to pin2 .
#define ECHO_PIN     9  //  echo pin on the ultrasonic sensor attach to pin3.
#define MAX_DISTANCE 400 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

dht11 DHT;                  //Note:DHT on behalf of the temperature and humidity sensor 
const int dht11_data = 18;     
int temp=0;
int hum=0;
int pumpon=0;
int wateron=0;
int heateron=0;
int fanon=0;
int grow1=0;
int grow2=0;
int lighton=0;
int lowlevel=55;
int distance=70;
int lowtemp=5;
int hightemp=25;
int highhum=70;
int soilPin = A0; 
int soilValue = 25;  
int soillimit = 425;
int soiltimer = 500;
int looptimer = 1000;
const int pumprun = 300;   // 5 minutes = 300 seconds
const int buttonPin = 2;  
const int soilLED = 28;
const int relayLED1 = 30;
const int relayLED2 = 32;
const int relayLED3 = 34;
const int relayLED4 = 36;
const int relayLED5 = 38;
const int relayLED6 = 40;
const int relayLED7 = 42;
const int relayLED8 = 44;
const int relay1 = 31;      //Water Pump
const int relay2 = 33;      //Fan
const int relay3 = 35;      //Heater
const int relay4 = 37;      //Grow Light1
const int relay5 = 39;      //Grow Light2
const int relay6 = 41;      //spare1
const int relay7 = 43;      //spare2
const int relay8 = 45;      //Work Light

int relayState = HIGH;         //Relay state
int buttonState = LOW;              //Key state
int lastButtonState = LOW;   //Last time the key data

long lastDebounceTime = 0;    // Last output pin trigger time
long debounceDelay = 50;      //Elimination of jitter, if the output is not stable increase in time

void setup() 
{
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("Test Line 1");
  lcd.setCursor(0,1);
  lcd.print("Test Line 2");
  lcd.setCursor(0,2);
  lcd.print("Test Line 3");
  lcd.setCursor(0,3);
  lcd.print("Test Line 4");
  Serial.begin(9600); //set the baud bit to 9600bps
  pinMode(buttonPin, INPUT);
  pinMode(relay1, OUTPUT);    //Water Pump
  pinMode(relay2, OUTPUT);    //Fan
  pinMode(relay3, OUTPUT);    //Heater
  pinMode(relay4, OUTPUT);    //Grow Light 1
  pinMode(relay5, OUTPUT);    //Grow Light 2
  pinMode(relay6, OUTPUT);    //spare 1
  pinMode(relay7, OUTPUT);    //spare 2
  pinMode(relay8, OUTPUT);    //Work light - button controlled
  pinMode(soilLED, OUTPUT);
  pinMode(relayLED1, OUTPUT);
  pinMode(relayLED2, OUTPUT);
  pinMode(relayLED3, OUTPUT);
  pinMode(relayLED4, OUTPUT);
  pinMode(relayLED5, OUTPUT);
  pinMode(relayLED6, OUTPUT);
  pinMode(relayLED7, OUTPUT);
  pinMode(relayLED8, OUTPUT);
  digitalWrite(relay1, relayState);
  digitalWrite(relay2, relayState);
  digitalWrite(relay3, relayState);
  digitalWrite(relay4, relayState);
  digitalWrite(relay5, relayState);
  digitalWrite(relay6, relayState);
  digitalWrite(relay7, relayState);
  digitalWrite(relay8, relayState);
  lcd.clear();                             //clear display then test all LED lights
  digitalWrite(soilLED, HIGH);
  digitalWrite(relayLED1, HIGH);
  digitalWrite(relayLED2, HIGH);
  digitalWrite(relayLED3, HIGH);
  digitalWrite(relayLED4, HIGH);
  digitalWrite(relayLED5, HIGH);
  digitalWrite(relayLED6, HIGH);
  digitalWrite(relayLED7, HIGH);
  digitalWrite(relayLED8, HIGH);
  delay(3000);
  digitalWrite(soilLED, LOW);
  digitalWrite(relayLED1, LOW);
  digitalWrite(relayLED2, LOW);
  digitalWrite(relayLED3, LOW);
  digitalWrite(relayLED4, LOW);
  digitalWrite(relayLED5, LOW);
  digitalWrite(relayLED6, LOW);
  digitalWrite(relayLED7, LOW);
  digitalWrite(relayLED8, LOW);
  delay(2000);
}

void loop() 
{
  // READ Temperature & Humidity DATA
  DHT.read(dht11_data);
  temp=DHT.temperature;
  hum=DHT.humidity;
  
  // Display Temp & Humidity data
  lcd.setCursor(0,0);
  lcd.print("Loop Hum Temp  Water");       //display line 0
  lcd.setCursor(0,1);
  lcd.print("                    ");       //clear previous values
  lcd.setCursor(0,1);
  lcd.print(looptimer);
  lcd.setCursor(5, 1);                     //Set the cursor at Line 1, Column 3
  lcd.print(hum);
  lcd.print("%");
  lcd.setCursor(9,1) ;
  lcd.print(temp);
  lcd.write(0xDF);              //Display custom characters
  lcd.print("C");

  //Read ultrasound data - Water Level
  if (looptimer >= 1000) {
    distance = 50;
    unsigned int uS = sonar.ping(); // Send ping, get ping time in microseconds (uS).
    distance = uS / US_ROUNDTRIP_CM;
    looptimer = 0;
    if (distance == 0) {
      looptimer = 1000;
    }
  }
  looptimer += 1;
  //Print Ultrasound data
  lcd.setCursor(15, 1);//Set the cursor at Line 1, Column 14.
  lcd.print(distance);// print on the LCD the value of the distance converted from the time between ping sending and receiving. 
  lcd.print("cm");//print the unit "cm"

  //Check water level in barrel
  if (distance < lowlevel) {
    pumpon = 1;
  }
  else {
    pumpon = 0;
  }
  
  //Check temptersture
  if (temp < lowtemp){
    heateron = 1;
  }
  else {
    heateron = 0;
    if (temp > hightemp){
      fanon = 1;
    }
    else {
      fanon = 0;
    }
  }

 
  //Check soil moisture once every 60 minutes
  
  if (soiltimer >= 500){
    soilValue = analogRead(soilPin);
    soiltimer = 0;
  }
//  else {
//    soilValue = soiltimer;
//  }
  lcd.setCursor(0, 2);                        //Set the cursor at Line 2, Column 0
  lcd.print("Soil 1 2 3 4 5 6 7 8");          //Print Line 2 header
  lcd.setCursor(1, 3);                        //Set the cursor at Line 3, Column 3.
  lcd.print("   ");
  lcd.setCursor(1, 3);                        //Set the cursor at Line 3, Column 3.
  lcd.print(soilValue);                       // print the soil moisture value

  if (soilValue > soillimit){  //Check for dry soil
    wateron = 1;
    digitalWrite(soilLED, HIGH);  //Soil needs water
  }
  else {
    wateron = 0;
    digitalWrite(soilLED, LOW);
  }
  
  //Check each relay status
  lcd.setCursor(7,3);
  if (fanon){                         //activate fan if needed
    digitalWrite(relay2, LOW);
    digitalWrite(relayLED2, HIGH);
    lcd.print("o");
  }
  else {
    digitalWrite(relay2, HIGH);
    digitalWrite(relayLED2, LOW);
    lcd.print("x");
  }
  lcd.setCursor(9,3);
  if (heateron){                    //activate heater if needed
    digitalWrite(relay3, LOW);
    digitalWrite(relayLED3, HIGH);    
    lcd.print("o");
  }
  else {
    digitalWrite(relay3, HIGH);
    digitalWrite(relayLED3, LOW);
    lcd.print("x");
  }
  
  lcd.setCursor(5,3);
  if (pumpon && wateron){           //Both water level good and need for water must be true to activiate the irrigation system
    digitalWrite(relay1, LOW);      //activtae water pump
    digitalWrite(relayLED1, HIGH);  //LED1 on
    lcd.print("o P=");
    lcd.print(pumpon);
    lcd.print(" w=");
    lcd.print(wateron);
    for (int x = pumprun; x > 1; x = x-1){   //run water pump for x seconds
      lcd.setCursor(15,3);
      lcd.print("   ");
      lcd.setCursor(15,3);
      lcd.print(x);
      delay(1000);
    }
    lcd.setCursor(5,3);
    lcd.print("- - - - - - -");
    pumpon = 0;
    wateron = 0;
    soiltimer = 5000;
    digitalWrite(relay1, HIGH);
    digitalWrite(relayLED1, LOW);
    digitalWrite(soilLED, LOW);    
    for (int x = 1; x < pumprun; x++){   //wait for x seconds to allow water to soak in
      lcd.setCursor(15,3);
      lcd.print("   ");
      lcd.setCursor(15,3);
      lcd.print(x);
      delay(1000);
    }
    lcd.setCursor(5,3);
    lcd.print("x x x x x x x");
  }
  else {
    digitalWrite(relay1, HIGH);
    digitalWrite(relayLED1, LOW);
    lcd.print("x");
  }
  lcd.setCursor(11,3);
  if (grow1){
    digitalWrite(relay4, LOW);
    digitalWrite(relayLED4, HIGH);    
    lcd.print("o");
  }
  else {
    digitalWrite(relay4, HIGH);
    digitalWrite(relayLED4, LOW);
    lcd.print("x");
  }
  lcd.setCursor(13,3);
  if (grow2){
    digitalWrite(relay5, LOW);
    digitalWrite(relayLED5, HIGH);    
    lcd.print("o");
  }
  else {
    digitalWrite(relay5, HIGH);
    digitalWrite(relayLED5, LOW);
    lcd.print("x");
  }
  lcd.setCursor(15,3);
  lcd.print("x");
  lcd.setCursor(17,3);
  lcd.print("x");

  //Check for button press
  int reading = digitalRead(buttonPin); //Read button data

  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }
  lcd.setCursor(19,3);
  
  if ((millis() - lastDebounceTime) > debounceDelay){
    if (reading != buttonState) {
      buttonState = reading;

      if (buttonState == HIGH) {
        if (lighton) {
          digitalWrite(relay8, HIGH);
          digitalWrite(relayLED8, LOW);
          lcd.print("x");
        }
        else {
          digitalWrite(relay8, LOW);
          digitalWrite(relayLED8, HIGH);        
          lcd.print("o");
        }
       lighton = !lighton;
       relayState = !relayState;
      }
    }
  }
  digitalWrite(relay8, relayState);
  lastButtonState = reading;
  soiltimer += 1;
}
