Smart Irrigation System

A Smart Irrigation system that monitors various parameters and decides when to start/stop the irrigation processs.

IntermediateFull instructions providedOver 1 day757
Smart Irrigation System

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
Bread Board
×1
HC06 Bluetooth Module
×1
Soil Moisture Sensor
×1
DHT11 Sensor
×1
Rain Sensor Module
×1
Micro Submersible Water Pump
×1
5V relay
×1
I2C 1602 Serial LCD
×1
AA Batteries
AA Batteries
×3
9V battery (generic)
9V battery (generic)
×1
3xAA Battery Holder
×1
9V battery clip
×1

Software apps and online services

Arduino IDE
Arduino IDE
Pycharm

Story

Read more

Code

Smart Irrigation System [Intergrated Code]

Arduino
This code is the full Arduino code for the Smart Irrigation system which controls the irrigation schedule according to the input parameters (Soil Moisture Level, Relative Humidity, Rain Status, Soil Moisture Level Range).
#include <Adafruit_Sensor.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <SoftwareSerial.h>

// Define DHT Type
#define DHTTYPE DHT11

// Define Sensor/Relay Pin
#define DHT11_PIN 13
#define Moisture_Sensor_Pin 0
#define Rain_Sensor_Pin 1
#define Relay_pin 2

// Initialize DHT11, LCD, HC06
DHT dht(DHT11_PIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27,16,2);
SoftwareSerial HC06(11, 10); // (TX,RX)

// Define and Initialize Variable
float ML = 0; // Soil Moisture Level
float RH = 0; // Relative Humidity
int Rain = 0; // Boolean for Rain/NoRain
int Pump = 0; // Boolean for Pump Activated/Deactivated
float UML = 75; // Upper Soil Moistuer Level Threshold
float LML = 50; // Lower Soil Moisture Level Threshold
float SPML; // Stop Pump Soil Moisture Level
int irrigation_start = 0;//boolean of whether the irrigation process have started
unsigned long lastIriigatingTime = 0;

void setup() 
{
  Serial.begin(9600);
  
  // Initialize LCD & Turn on LCD Backlight
  lcd.init();
  lcd.backlight();
  
  // Set Pin Mode of Moisture_Sensor_Pin to Input to read value from Sensor
  pinMode(Moisture_Sensor_Pin, INPUT);
  
  //Initialize DHT11 Sensor
  dht.begin();
  
  // Set Pin Mode of Rain_Sensor_Pin to Input to read value from Sensor
  pinMode(Rain_Sensor_Pin, INPUT);

  // Set Pin Mode of Relay_pin to Output to Control Relay
  pinMode(Relay_pin, OUTPUT);

  //Initialize HC06 with 9600 baud
  HC06.begin(9600);

  // Initialize Pump to be off
  PumpOff();

  // delay 5 minutes to allow sensor to stablelize the reading
  delay(120000);
}

void loop() 
{
  // Call Functions to Read from sensors
  Soil_Moisture_Level();
  Humidity();
  Rain_Present();

  // Transmit sensors data & Pump Status to laptop GUI through Bluetooth 
  Transmit_Data();

  // Call display() Functions to display sensor data and PumpStatus on LCD 
  display();

  // Call Read_Recieve_Data to read data recieved from laptop GUI by HC06 if there is any
  Read_Recieve_Data();
  
  // Call ML_STOP() Function to calculate Stop Pump Moisture Level
  ML_STOP();

  // if NoRain Present 
  // Check ML to determine the action of the system
  if (Rain == 0)
  {
    // if Soil Moisture Level is lower than Threshold CALL the irrigating function to start the irrigation process
    if (ML < LML)
    {
      // irrigation_start = 1 indicating the irrigation is in process
      irrigation_start = 1;
      // Call irrigating() function to start the irrigation process
      irrigating();
    }
    // stop the irrigation process
    else if(ML >= SPML) // Deactivate Pump When ML alrd reach SPML
    {
      // irrigation_start = 1 indicating the irrigation is in process
      irrigation_start = 0;
    }
    else if (ML > LML && ML < SPML && irrigation_start == 1)
    {
      // irrigation_start = 1 indicating the irrigation process have started
      irrigation_start = 1;
      // Call irrigating() function to start the irrigation process
      irrigating();
    }
  }
  // if Rain Present END the irrigation process 
  else if(Rain == 1)
  {
    // irrigation_start = 0 indicating the irrigation process have ended
    irrigation_start = 0;
  }
}

void irrigating()
{  
 //find current time
 unsigned long CurrentTime = millis();

 //irrigate the soil every 1.5min
 if (CurrentTime - lastIriigatingTime > 63000)
 { 
   //Activate Pump
   PumpOn();

   //update LCD & GUI display 
   Pump = 1;
   display ();
   Transmit_Data();

   //irrigate for 0.7s 
   delay(700);

   //stop irrigating
   PumpOff();

   //update LCD & GUI display 
   Pump = 0;
   display ();
   Transmit_Data();

   //update last Irrigation Time
   lastIriigatingTime = CurrentTime + 700;
 }
}

void display()
{
  lcd.setCursor(0,0);

  // Dispaly Rain/NoRain Represented by boolean 0(NoRain), 1(Rain)
  lcd.print("Rain:");
  lcd.print(Rain);
  
  // Dispaly Soil Moisture Level
  lcd.print(" ML=");
  lcd.print(ML);
  lcd.print("% ");
  
  lcd.setCursor(0,1);
  
  // Dispaly Pump Status Represented by boolean 0(OFF), 1(ON)
  lcd.print("Pump:");
  lcd.print(Pump);
  
  if (irrigation_start == 0)
  {
    // Dispaly Relative Humidity while not irrigating
    lcd.print(" RH=");
    lcd.print(RH); 
    lcd.print("% ");
  }
  else if (irrigation_start == 1)
  {
    // Dispaly Stop Pump Moisture Level while irrigating
    lcd.print(" SP=");
    lcd.print(SPML);
    lcd.print("% ");
  }
}

void Soil_Moisture_Level()
{
  // TAKE Sensor Reading from Soil Moisture Sensor
  float Moisture_Sensor_Reading = analogRead(Moisture_Sensor_Pin);

  // Convert Analog Soil Moisture Sensor Reading into Soil Moisture in % 
  ML = ( 100 - ( (Moisture_Sensor_Reading/1023.00) * 100 ) );
}

void Humidity()
{
  if (!isnan(dht.readHumidity()))
  {
    // Read Relative Humidity Level in % using dht.readHumidity() fucntion
    RH = dht.readHumidity(); 
  }
}

void Rain_Present()
{
  int Rain_Sensor_Reading = analogRead(Rain_Sensor_Pin);
  if (Rain_Sensor_Reading < 400) // Rain
  {
    Rain = 1;
  }
  else // No Rain
  {
    Rain = 0;
  }
}

void ML_STOP()
{
  // Define Array of Fuzzy Logic Compute Value to Determine the Stop_Soil Moisture Level
  // 0 to 1 correspons to UML to LML
  // index 0 to 100 correspond to the RH
  float fv[101] = {0.868, 0.868, 0.868, 0.868, 0.868, 0.868, 0.868, 0.868, 0.868, 0.868, 0.868, 0.858, 
                   0.849, 0.841, 0.834, 0.827, 0.822, 0.817, 0.813, 0.809, 0.806, 0.798, 0.789, 0.78, 
                   0.77, 0.759, 0.748, 0.736, 0.723, 0.711, 0.7, 0.686, 0.673, 0.662, 0.652, 0.642, 
                   0.633, 0.624, 0.616, 0.608, 0.6, 0.592, 0.584, 0.576, 0.567, 0.558, 0.548, 0.538, 
                   0.527, 0.514, 0.5, 0.486, 0.473, 0.462, 0.452, 0.442, 0.433, 0.424, 0.416, 0.408, 
                   0.4, 0.392, 0.384, 0.376, 0.367, 0.358, 0.348, 0.338, 0.327, 0.314, 0.3, 0.287, 
                   0.274, 0.261, 0.248, 0.237, 0.225, 0.215, 0.206, 0.197, 0.188, 0.185, 0.181, 
                   0.177, 0.172, 0.167, 0.161, 0.154, 0.146, 0.137, 0.127, 0.127, 0.127, 0.127, 
                   0.127, 0.127, 0.127, 0.127, 0.127, 0.127, 0.127};

  // Find Differnce between UML and LML
  float diff = UML - LML;
  
  // Convert Fuzzy Logic Compute Value to Pump Stop Soil Moisture Level Value 
  SPML = LML + (diff * fv[int(RH)]);
}

void Read_Recieve_Data()
{
  // Check if there is data available
  // Only Run when there is data available for read from HC06
  if (HC06.available() > 0)
  {
    // read data Recieve from HC06 until encounter newline
    // store the recive data into a string variable "recieve_data"
    String recieve_data = HC06.readStringUntil('\n');
    
    // delay 20ms to ensure that the data is received completely and processed correctly
    delay(20);
    
    // Print Recieve Data in Monitor for testing program purpose
    Serial.println(recieve_data);
    
    // find index of first ';' and ','
    int index = recieve_data.indexOf(';');
    int commaIndex = recieve_data.indexOf(','); // 2, 4, 5
    
    // only allow certain format of recive data to be assign to UML & LML
    // To avoid unwanted data/giberish data to be assign to UML & LML
    if ((commaIndex == 3 && (index == 7 || index == 8 || index == 9)) || 
        (commaIndex == 4 && (index == 8 || index == 9 || index == 10)) || 
        (commaIndex == 5 && (index == 9 || index == 10 || index == 11)))
    {
      // Assign Data in recieve_data from index 0 to first comma index into data1_str
      String data1_str = recieve_data.substring(0, commaIndex);
      
      // Assign Data in recieve_data from index after first comma index to index before first ';' index into data2_str
      String data2_str = recieve_data.substring(commaIndex + 1, index);
  
      // only assign data that is lower than 100 into UML as UML cannot exceed 100
      if (data1_str.toFloat() < 100)
      {
        UML = data1_str.toFloat();
      }
  
      // only assign data that is lower than 100 into LML as LML cannot exceed 100
      if (data2_str.toFloat() < 100)
      {
        LML = data2_str.toFloat();
      }
  
      // Print UML & LML in Monitor for testing program purpose
      Serial.print("Data1: ");
      Serial.println(UML);
      Serial.print("Data2: ");
      Serial.println(LML);
    }
  }
}

void Transmit_Data()
{
  // Put all Needed Transmit Data in one line seperated by comma
  String Transmit_data = String(ML) + "," + String(RH) + "," + String(Rain) + "," + String(Pump) + "," + String(irrigation_start) + "\n";
  
  // Transmit Data Through HC06
  HC06.println(Transmit_data);
}

void PumpOn()
{ 
  // Active Pump
  // Active Low Relay
  digitalWrite(Relay_pin, LOW);
  Pump = 1;
}


void PumpOff()
{
  // Deactive Pump
  // Active Low Relay
  digitalWrite(Relay_pin, HIGH);
  Pump = 0;
}

GUI Code [Python]

Python
This code create a GUI using custom tkinter library of python which display the receive data from the Arduino board, and transmit the User define Soil Moisture Range to the Arduino Board
import customtkinter
import serial
from customtkinter import *
from serial import SerialException

# Initialize Variable
SML = '???'
RH = '???'
R = '???'
Activation = '???'
IRG_P = '???'

# define filename that store ML thresh value
filename = "ML_Thresh.txt"
# if it not exists create one and set UML as 75, LML as 50
if not os.path.exists(filename):
    with open(filename, "w") as f:
        f.write("75.0,50.0")
        print("File created.")

# Open File to read data and get UML,LML value from previous setting
# Initialize UML & LML from previous setting
with open(filename, "r") as f:
    data = f.read()
    # Split the data into two separate values
    values = data.split(',')
    # Convert the values from strings to integers
    UML = float(values[0])
    LML = float(values[1])

# Initialize Temporary UML & LML for slider
UML_tem = 75.00
LML_tem = 50.00

# Main Menu Window
IS = customtkinter.CTk()
IS.geometry("250x190")
IS.title("IRRIGATION SYSTEM")
IS.resizable(False, False)

# Label Frame
IS_frame_1 = customtkinter.CTkFrame(master=IS)
IS_frame_1.grid(row=0, column=0, padx=15, pady=8)

# Main Menu Label
label_main = customtkinter.CTkLabel(master=IS_frame_1,
                                    text='IRRIGATION SYSTEM',
                                    font=('Times New Roman', 18),
                                    width=200,
                                    height=10,
                                    corner_radius=8)
label_main.grid(row=0, column=0, padx=10, pady=15)

# Button & Entry Frame
IS_frame_2 = customtkinter.CTkFrame(master=IS)
IS_frame_2.grid(row=1, column=0, padx=15, pady=0)

# Start Button
button_start = customtkinter.CTkButton(master=IS_frame_2,
                                       width=200,
                                       height=40,
                                       corner_radius=8,
                                       text="Start",
                                       state='disabled',
                                       font=('Times New Roman', 18),
                                       command=lambda: gui())
button_start.grid(row=1, column=0, padx=10, pady=8)


def validate(port_entry):
    if port_entry.get() == '':
        port = 'COM'
    else:
        try:
            port = f'COM{int(port_entry.get())}'
        except ValueError:
            port = 'COM'
    print(port)

    try:
        serial.Serial(port, 9600, timeout=1)
        bc = True
    except SerialException:
        bc = False

    print(bc)
    if not bc:
        button_start.configure(state='disabled')
    elif bc:
        button_start.configure(state='normal')


# Entry for HC06 Port
Port = customtkinter.CTkEntry(master=IS_frame_2,
                              placeholder_text="HC06 PORT NUMBER",
                              width=200,
                              height=40,
                              justify='center',
                              border_width=2,
                              corner_radius=8)
Port.bind("<KeyRelease>", lambda event: validate(Port))
Port.grid(row=0, column=0, padx=10, pady=8)


def gui():
    global SML, RH, UML, UML_tem, LML, LML_tem, R, Activation, IRG_P

    def segmented_button_callback(value):
        if value == 'SoilMoistureLevel':
            label_value.configure(text=f'SOIL MOISTURE LEVEL: {SML}%')
        elif value == "RainPresent":
            label_value.configure(text=f'RAIN PRESENT: {R}')
        elif value == "RelativeHumidity":
            if type(RH) == str:
                label_value.configure(text=f'RELATIVE HUMIDITY: {RH}%')
            elif RH > 60:
                label_value.configure(text=f'RELATIVE HUMIDITY: {RH}% (Too Humid)')
            elif RH < 40:
                label_value.configure(text=f'RELATIVE HUMIDITY: {RH}% (Too Dry)')
            else:
                label_value.configure(text=f'RELATIVE HUMIDITY: {RH}%')

    def ut_slider_event(value):
        global UML_tem
        UML_tem = round(value, 2)
        lt_slider.configure(to=UML_tem - 1)
        label_ut.configure(text=f'UPPER MoistureLevel Value: {UML_tem}%')

    def lt_slider_event(value):
        global LML_tem
        LML_tem = round(value, 2)
        ut_slider.configure(from_=LML_tem + 1)
        label_lt.configure(text=f'LOWER MoistureLevel Value: {LML_tem}%')

    def set_ml():
        global UML, UML_tem, LML, LML_tem
        UML = UML_tem
        LML = LML_tem

        # save the set threshold value
        with open(filename, "w") as file:
            file.write(f"{UML},{LML}")

        label_thresh.configure(text=f'Upper ML Value: {UML}%\nLower ML Value: {LML}%')

    def disable_event():
        pass

    # Hide Startup Window
    IS.withdraw()

    # Create Main GUI Window
    gui_win = CTkToplevel(IS)
    gui_win.geometry("365x660")
    gui_win.title("IRRIGATION SYSTEM")
    gui_win.resizable(False, False)

    # Disable the Close Window Control Icon
    gui_win.protocol("WM_DELETE_WINDOW", disable_event)

    # GUI Frame 1
    gui_frame_1 = customtkinter.CTkFrame(master=gui_win)
    gui_frame_1.grid(row=0, column=0, padx=15, pady=15)

    # Title Label
    label_title = customtkinter.CTkLabel(master=gui_frame_1,
                                         text='IRRIGATION SYSTEM',
                                         font=('Times New Roman', 18),
                                         width=315,
                                         height=10,
                                         corner_radius=8)
    label_title.grid(row=0, column=0, padx=10, pady=10)

    # Segmented Button
    segmented_button = customtkinter.CTkSegmentedButton(master=gui_win,
                                                        values=["SoilMoistureLevel", "RainPresent", "RelativeHumidity"],
                                                        border_width=10,
                                                        command=segmented_button_callback)
    segmented_button.grid(row=1, column=0, padx=15, pady=0)
    segmented_button.set("SoilMoistureLevel")

    # Value Frame
    value_frame = customtkinter.CTkFrame(master=gui_win)
    value_frame.grid(row=2, column=0, padx=15, pady=8)

    # SML Label
    label_value = customtkinter.CTkLabel(master=value_frame,
                                         text=f'SOIL MOISTURE LEVEL: {SML}%',
                                         font=('Times New Roman', 16),
                                         width=315,
                                         height=10,
                                         corner_radius=8)
    label_value.grid(row=0, column=0, padx=10, pady=15)

    # Irrigation Activation Frame
    value_frame = customtkinter.CTkFrame(master=gui_win)
    value_frame.grid(row=3, column=0, padx=15, pady=8)

    # Pump Label
    label_pump = customtkinter.CTkLabel(master=value_frame,
                                        text=f'IrrigationProcess:{IRG_P}\nWater Pump: {Activation}',
                                        font=('Times New Roman', 16),
                                        width=315,
                                        height=10,
                                        corner_radius=8)
    label_pump.grid(row=0, column=0, padx=10, pady=15)

    # Thresh Frame
    thresh_frame = customtkinter.CTkFrame(master=gui_win)
    thresh_frame.grid(row=4, column=0, padx=15, pady=8)

    # Upper ML Thresh
    label_ut = customtkinter.CTkLabel(master=thresh_frame,
                                      text=f'UPPER MoistureLevel Value: {UML_tem}%',
                                      font=('Times New Roman', 16),
                                      width=315,
                                      height=10,
                                      corner_radius=8)
    label_ut.grid(row=0, column=0, padx=10, pady=15)

    ut_slider = customtkinter.CTkSlider(master=thresh_frame,
                                        from_=LML_tem + 1,
                                        to=99,
                                        command=ut_slider_event)
    ut_slider.grid(row=1, column=0, padx=10, pady=15)

    # Lower ML Thresh
    label_lt = customtkinter.CTkLabel(master=thresh_frame,
                                      text=f'Lower MoistureLevel Value: {LML_tem}%',
                                      font=('Times New Roman', 16),
                                      width=315,
                                      height=10,
                                      corner_radius=8)
    label_lt.grid(row=2, column=0, padx=10, pady=15)

    lt_slider = customtkinter.CTkSlider(master=thresh_frame,
                                        from_=0,
                                        to=UML_tem - 1,
                                        command=lt_slider_event)
    lt_slider.grid(row=3, column=0, padx=10, pady=15)

    # Set Button for setting the threshold
    button_return = customtkinter.CTkButton(master=thresh_frame,
                                            width=300,
                                            height=40,
                                            corner_radius=8,
                                            text="Set",
                                            font=('Times New Roman', 18),
                                            command=lambda: set_ml())
    button_return.grid(row=4, column=0, padx=10, pady=15)

    # Label ML Thresh Value
    label_thresh = customtkinter.CTkLabel(master=thresh_frame,
                                          text=f'Upper ML Value: {UML}%\nLower ML Value: {LML}%',
                                          font=('Times New Roman', 18),
                                          width=315,
                                          height=10,
                                          corner_radius=8)
    label_thresh.grid(row=5, column=0, padx=10, pady=15)

    # Return Button
    button_return = customtkinter.CTkButton(master=gui_win,
                                            width=330,
                                            height=40,
                                            corner_radius=8,
                                            text="Return",
                                            font=('Times New Roman', 18),
                                            command=lambda: (gui_win.destroy(), IS.deiconify()))
    button_return.grid(row=5, column=0, padx=10, pady=5)

    port = f'COM{Port.get()}'
    ser = serial.Serial(port, 9600, timeout=1)
    while True:
        transmit_data = str(UML) + ',' + str(LML) + ';' + '\n'
        print(transmit_data)
        ser.write(transmit_data.encode())

        try:
            receive_data = ser.readline().decode()
        except UnicodeDecodeError:
            continue
        if len(receive_data) > 0:
            try:
                SML, RH, rain, pump, irp = receive_data.split(',')

                pump = int(pump)
                rain = int(rain)
                SML = float(SML)
                RH = float(RH)
                irp = int(irp)

                if pump == 1:
                    Activation = 'ON'
                    print('ON')
                elif pump == 0:
                    Activation = 'OFF'
                    print('Off')

                if rain == 1:
                    R = True
                elif rain == 0:
                    R = False

                if irp == 1:
                    IRG_P = 'Irrigating'
                elif irp == 0:
                    IRG_P = 'Not Irrigating'

            except ValueError:
                continue

        segmented_button_callback(segmented_button.get())
        label_pump.configure(text=f'IrrigationProcess:{IRG_P}\nWater Pump: {Activation}')
        gui_win.update()


IS.mainloop()

Bluetooth Section of Smart Irrigation system [Arduino]

Arduino
This code allows the Arduino board to transmit/receive data to/from the GUI through HC06.
#include <SoftwareSerial.h>
#include <LiquidCrystal_I2C.h>

// Initialize LCD, HC06
LiquidCrystal_I2C lcd(0x27,16,2);
SoftwareSerial HC06(11, 10); // TX,RX

// Define and Initialize Variable
float ML = 50; // Soil Moisture Level
float RH = 50; // Relative Humidity
int Rain = 1; // Rain Status
int Pump = 1; // Pump Status
int irrigation_start = 0; // Irrigation Status
float UML;
float LML;

void setup() 
{
  Serial.begin(9600);
  
  //Initialize HC06 with 9600 baud
  HC06.begin(9600);

  // Initialize LCD & Turn on LCD Backlight
  lcd.init();
  lcd.backlight();
}

void loop() 
{
  // Read Recive Data
  Read_Recieve_Data();

  // Put all Needed Transmit Data in one line seperated by comma
  String Transmit_data = String(ML) + "," + String(RH) + "," + String(Rain) + "," + String(Pump) + "," +String(irrigation_start) + "\n";
  
  // Transmit Data Through HC06
  HC06.println(Transmit_data);

  // Call display() Functions to display UML & LML
  display();

  // Increment ML & RH every loop to see if the value on GUI Update
  ML += 1;
  RH += 1;

  // Reset ML to 0 when it reach 100
  if (ML == 100)
  {
    ML = 0;
  }

  // Reset  RH to 0 when it reach 100
  if (RH == 100)
  {
    RH = 0;
  }
}

void Read_Recieve_Data()
{
  // Check if there is data available
  // Only Run when there is data available for read from HC06
  if (HC06.available() > 0)
  {
    // read data Recieve from HC06 until encounter newline
    // store the recive data into a string variable "recieve_data"
    String recieve_data = HC06.readStringUntil('\n');

    // delay 20ms to ensure that the data is received completely and processed correctly    
    delay(20);

    // Print Recieve Data in Monitor for testing program purpose
    Serial.println(recieve_data);

    // find index of first ';' and ','    
    int index = recieve_data.indexOf(';');
    int commaIndex = recieve_data.indexOf(','); // 2, 4, 5

    // only allow certain format of recive data to be assign to UML & LML
    // To avoid unwanted data/giberish data to be assign to UML & LML
    if ((commaIndex == 3 && (index == 7 || index == 8 || index == 9)) || 
        (commaIndex == 4 && (index == 8 || index == 9 || index == 10)) || 
        (commaIndex == 5 && (index == 9 || index == 10 || index == 11)))
    {
      // Assign Data in recieve_data from index 0 to first comma index into data1_str
      String data1_str = recieve_data.substring(0, commaIndex);

      // Assign Data in recieve_data from index after first comma index to index before first ';' index into data2_str
      String data2_str = recieve_data.substring(commaIndex + 1, index);
      
      // only assign data that is lower than 100 into UML as UML cannot exceed 100
      if (data1_str.toFloat() < 100)
      {
        UML = data1_str.toFloat();
      }

      // only assign data that is lower than 100 into LML as LML cannot exceed 100
      if (data2_str.toFloat() < 100)
      {
        LML = data2_str.toFloat();
      }
            
      // Print UML & LML in Monitor for testing program purpose
      Serial.print("Data1: ");
      Serial.println(UML);
      Serial.print("Data2: ");
      Serial.println(LML);
    }
  }
}

void display()
{ 
  // Display Receieve UML & LML Value on LCD
  lcd.setCursor(0,0);
  lcd.print("UML=");
  lcd.print(UML);
  lcd.print("%");
  lcd.print(" ");
  
  lcd.setCursor(0,1);
  lcd.print("LML=");
  lcd.print(LML);
  lcd.print("%");
  lcd.print(" ");
}

Soil Moisture Sensor Section of Smart Irrigation System

Arduino
This code is a code that tested the soil moisture sensor section of the Smart Irrigation system. In this code, the Soil Moisture Reading is read from the Soil Moisture sensor and converted to % form, next the code takes the Soil Moisture Level is compared to a lower threshold value when the Soil Moisture Level is lower than this value the irrigation process will start and end when the Soil Moisture Level reach another threshold set.
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);

#define Moisture_Sensor_Pin 0
#define Relay_pin 2

float LML = 50; // Lower Soil Moisture Level Threshold
float SPML = 65; // Soil Moisture Level Value to Stop Irrigation
int Pump = 0;
float ML = 0;
unsigned long lastIriigatingTime = 0;// last time the pump activated
int irrigation_start = 0;// Irrigation Status, 1:irrigating, 0:not irrigating

void setup() 
{
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  pinMode(Relay_pin, OUTPUT);
  pinMode(Moisture_Sensor_Pin, INPUT);

  //Pump Initialse to be OFF
  digitalWrite(Relay_pin, HIGH);

  //DELAY 1min to stable sensor reading 
  delay(60000);
}

void loop() 
{
  // Read Soil Moisture Sensor reading and convert it to % form
  float Moisture_Sensor_Reading = analogRead(Moisture_Sensor_Pin);
  ML = ( 100 - ( (Moisture_Sensor_Reading/1023.00) * 100 ) );

  display();
  
  // Process Variable
  if (ML < LML)
  {
    irrigation_start = 1;
    irrigating();
  }
  else if(ML >= SPML)
  {
    irrigation_start = 0;
  }
  else if (ML > LML && ML < SPML && irrigation_start == 1)
  {
    irrigation_start = 1;
    irrigating();
  }
}

void irrigating()
{  
 //find current time
 unsigned long CurrentTime = millis();

 //irrigate the soil every 1.5min
 if (CurrentTime - lastIriigatingTime > 63000)
 { 
   //Activate Pump
   digitalWrite(Relay_pin, LOW);

   //update display
   Pump = 1;
   display ();

   //irrigate for 0.5s 
   delay(700);

   //stop irrigating
   digitalWrite(Relay_pin, HIGH);

   //update display
   Pump = 0;
   display ();

   //update last Irrigation Time
   lastIriigatingTime = CurrentTime + 700;
 }
}

void display()
{
  lcd.setCursor(0,0);
  lcd.print("ML=");
  lcd.print(ML);
  
  lcd.setCursor(0,1);
  lcd.print("Pump:");
  lcd.print(Pump);
  lcd.print(" IRG:");
  lcd.print(irrigation_start);
}

Humidity Sensor Section of Smart Irrigation System [Python Fuzzy Logic]

Python
In this code, a fuzzy logic system is created to obtain the Soil Moisture Level Value to Stop the irrigation process at different Humidity. The program will output an array of fuzzy logic outputs of the value from 0 to 1 with the input of Humidity (0 - 100) which then this array will be integrated to the Arduino program and will be converted to the Soil Moisture Level Range set by the user and obtain the specific Soil Moisture Level Value to Stop the irrigation process according to the humidity
import numpy as np
import skfuzzy as fuzz
import matplotlib.pyplot as plt
from skfuzzy import control as ctrl

# Define the antecedents and consequent
humid = ctrl.Antecedent(np.arange(0, 100, 1), 'humidity')
sml = ctrl.Consequent(np.arange(0, 1, 0.01), 'moist_lvl')

# Define the membership functions for the input variable
humid['Extra Dry'] = fuzz.trapmf(humid.universe, [0, 0, 20, 30])
humid['Dry'] = fuzz.trimf(humid.universe, [10, 30, 50])
humid['Moderate'] = fuzz.trimf(humid.universe, [30, 50, 70])
humid['Humid'] = fuzz.trimf(humid.universe, [50, 70, 90])
humid['Extra Humid'] = fuzz.trapmf(humid.universe, [70, 80, 100, 100])

# Define the membership functions for the output variable
sml['Extra Low'] = fuzz.trapmf(sml.universe, [0, 0, 0.2, 0.3])
sml['Low'] = fuzz.trimf(sml.universe, [0.1, 0.3, 0.5])
sml['Moderate'] = fuzz.trimf(sml.universe, [0.3, 0.5, 0.7])
sml['High'] = fuzz.trimf(sml.universe, [0.5, 0.7, 0.9])
sml['Extra High'] = fuzz.trapmf(sml.universe, [0.7, 0.8, 1, 1])

# Define the fuzzy rules
rule1 = ctrl.Rule(humid['Extra Dry'], sml['Extra High'])
rule2 = ctrl.Rule(humid['Dry'], sml['High'])
rule3 = ctrl.Rule(humid['Moderate'], sml['Moderate'])
rule4 = ctrl.Rule(humid['Humid'], sml['Low'])
rule5 = ctrl.Rule(humid['Extra Humid'], sml['Extra Low'])

# Create the control system and the simulation
soil_ctrl = ctrl.ControlSystem([rule1, rule2, rule3, rule4, rule5])
soil_simulation = ctrl.ControlSystemSimulation(soil_ctrl)

SML = []
for i in range(101):
    # Set the input values for the simulation
    soil_simulation.input['humidity'] = i

    # Compute the output
    soil_simulation.compute()

    SML.append(round(soil_simulation.output['moist_lvl'], 2))

# Print the output
print(SML)

Humidity Sensor Section of Smart Irrigation System [Arduino]

Arduino
In this code, the Arduino board will obtain the Relative Humidity value from DHT11 Sensor and find the corresponding fuzzy logic output of 0 to 1 and convert it into a value that fits in the Soil Moisture Level Range
#include <DHT.h>
#include <LiquidCrystal_I2C.h>

#define DHT11_PIN 13
#define DHTTYPE DHT11

LiquidCrystal_I2C lcd(0x27,16,2);
DHT dht(DHT11_PIN, DHTTYPE);

float Pump_Stop_ML value; // Soil Moisture Level to stop irrigation process
float RH = 0; // Relative Humidity
float lower_ML = 50; // Soil Moisture Level Lower Range
float upper_ML = 75; // Soil Moisture Level Upper Range
float FValue = 0; // fuzzy logic value

void setup() 
{
  Serial.begin(9600);
  dht.begin();
  lcd.init();
  lcd.backlight();
}

void loop() 
{
  //Read DHT11 Sensor
  RH = dht.readHumidity();
  
  // Call function to get Pump_Stop_ML value
  ML_STOP();

  // Display result on lcd
  display();
}


void ML_STOP()
{
  // Array of fuzzy logic output obtain from the python program
  float fv[101] = {0.868, 0.868, 0.868, 0.868, 0.868, 0.868, 0.868, 0.868, 0.868, 0.868, 0.868, 0.858, 
                   0.849, 0.841, 0.834, 0.827, 0.822, 0.817, 0.813, 0.809, 0.806, 0.798, 0.789, 0.78, 
                   0.77, 0.759, 0.748, 0.736, 0.723, 0.711, 0.7, 0.686, 0.673, 0.662, 0.652, 0.642, 
                   0.633, 0.624, 0.616, 0.608, 0.6, 0.592, 0.584, 0.576, 0.567, 0.558, 0.548, 0.538, 
                   0.527, 0.514, 0.5, 0.486, 0.473, 0.462, 0.452, 0.442, 0.433, 0.424, 0.416, 0.408, 
                   0.4, 0.392, 0.384, 0.376, 0.367, 0.358, 0.348, 0.338, 0.327, 0.314, 0.3, 0.287, 
                   0.274, 0.261, 0.248, 0.237, 0.225, 0.215, 0.206, 0.197, 0.188, 0.185, 0.181, 
                   0.177, 0.172, 0.167, 0.161, 0.154, 0.146, 0.137, 0.127, 0.127, 0.127, 0.127, 
                   0.127, 0.127, 0.127, 0.127, 0.127, 0.127, 0.127};

  
  // find soil moisture range "width" 
  float diff = upper_ML - lower_ML;
  
  // convert fuzzy logic outpt of 0-1 
  // into a value that is in the Soil Moisture Level Range
  Pump_Stop_ML = lower_ML + (diff * fv[int(RH)]);

}


void display()
{
  lcd.setCursor(0,0);
  lcd.print("RH=");
  lcd.print(RH);
  
  lcd.setCursor(0,1);
  lcd.print("Stop_ML=");
  lcd.print(Pump_Stop_ML);

}

Rain Sensor Section of Smart Irrigation System

Arduino
This code is a code that tested the rain sensor section of the Smart Irrigation system, the code constantly activates the pump only when the rain sensor detects rain present the pump will stop
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);

# define Rain_Sensor_Pin 1
# define Relay_pin 2

int Rain = 0;
int Pump = 0;

void setup() 
{
  lcd.init();
  lcd.backlight();
  Serial.begin(9600);
  pinMode(Rain_Sensor_Pin, INPUT);
  pinMode(Relay_pin, OUTPUT);
}

void loop() 
{ 
  //Define Varialble
  int Rain_Sensor_Reading = analogRead(Rain_Sensor_Pin);
  int condition = 1;
  
  // Process Variable
  // if other condtion met, Activate Pump according to rain sensor
  if (condition == 1)
  {
    if (Rain_Sensor_Reading < 400) // Rain
    {
      // Deactivate Pump (Relay Active Low)
      Rain = 1;
      Pump = 0;
      digitalWrite(Relay_pin, HIGH);
      display();
    }
    else // No Rain
    {
      // Activate Pump (Relay Active Low)
      Rain = 0;
      Pump = 1;
      digitalWrite(Relay_pin, LOW);
      display();
    }
  }
}

void display()
{
  lcd.setCursor(0,0);
  lcd.print("Rain:");
  lcd.print(Rain);
  
  lcd.setCursor(0,1);
  lcd.print("Pump:");
  lcd.print(Pump);
}

Credits

LIM JING XIANG [TP062071]

LIM JING XIANG [TP062071]

1 project • 3 followers
L-j Kit

L-j Kit

1 project • 1 follower
SUN YIGE

SUN YIGE

1 project • 1 follower
Muhammad Rafi Dwiyani

Muhammad Rafi Dwiyani

1 project • 1 follower
NARENDRAN

NARENDRAN

20 projects • 22 followers

Comments