Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 3 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
|
The Smart Irrigation System controls the irrigation schedule according to 4 parameters:
- Soil Moisture Level: When Soil Moisture drop below a certain threshold the irrigation process will begin which will water the soil until the Soil Moisture Level Rise above a certain threshold
- Relative Humidity: Use to find the Soil Moisture Level value to stop the irrigation process. Humidity plays an important role in determining how fast/slow the water evaporates from the soil and plant. Based on that statement when humidity is high (air is humid) less water is needed hence the Soil Moisture Level value to stop the irrigation process can be lower, conversely when humidity is low (air is dry) more water is needed hence the Soil Moisture Level value to stop the irrigation process can be higher.
- Rain Status: When there is rain present during the irrigation, the irrigation process should stop since the plant is already going to be watered naturally, hence reducing water wastage and prevent for overwatering the plant.
- Soil Moisture Level Range of Plant: This value is set by the user in the GUI different plants have different Soil Moisture Level Requirements, and these values can affect the Soil Moisture Level value to stop the irrigation process as this value must be within the range, additionally the Soil Moisture Level value to start the irrigation process also affected by this value as when the Soil Moisture Level Value drop below this range the irrigation process will start.
The Rain sensor circuit contains 4 electrical components which is the rain sensor which detects if any rain is present, the Arduino board processes the rain sensor analog input to determine whether there is rain and controls the pump according to the rain weather status, the LCD display to display the rain weather status and pump status, and an active low relay that controls the pump activation/deactivation.
Humidity SensorThe objective of this circuit is to determine the Soil Moisture Level which the pump will be deactivated after the irrigation start, which this value will be affected by the Relative humidity level of the air. When the air is “Humid” the speed of water to evaporate into the air is much slower compared to when the air is “Dry”, hence if the air is “Humid” the need for water for the plant will reduce hence the Pump Stop Soil Moisture level will also be lower, conversely if the air is “Dry” the need of water for the plant will increase hence the Pump Stop Soil Moisture level will also be higher.
Soil Moisture SensoThe Soil Moisture sensor circuit contains 4 electrical components which is the Soil Moisture sensor which detects the Moisture level of the soil, the Arduino board processes the soil moisture sensor analog input and converts it to percentage form, and controls when to start the irrigation process according to the Soil Moisture Level, LCD display to display the Soil Moisture Level in percentage, irrigation status, and pump status, and an active low relay that controls the pump activation/deactivation.
GUI & HC06The objective of this circuit is to transmit the data (Soil Moisture Level, Rain Weather Status, Relative Humidity, Irrigation Status, Pump Status) of the system and display it on the GUI which allows the user to observe various information about the system far from the circuit.
Furthermore, the GUI also allows the user to adjust the Soil Moisture Level Threshold (Soil Moisture Level Range where the agriculture plant requires) of the system according to the agriculture plant requirement as different plants have different requirements, and transmit this data to the Arduino Board.
Smart Irrigation SystemThe objective of the smart irrigation system is to control the activation of the irrigation process according to the various input parameter stated above, which the system contains 5 input parameters.
Firstly, Soil Moisture Level (Sensor Value) is the input parameter that determines when to start/stop the irrigation process.
Secondly, Rain Weather Status (Sensor Value) is the parameter that forcefully ends the irrigation process when rain is present.
Thirdly, Relative Humidity (Sensor Value) is the parameter that determines the Soil Moisture Level value for when the irrigation process should stop.
Lastly, the User Define Upper & Lower Threshold Soil Moisture Level Value, which the Upper & Lower Threshold value can affect the Soil Moisture Level value for when the irrigation process should stop as this value must be within the range, Additionally Lower Threshold value also determines when the irrigation started.
Furthermore, the irrigation process of the SMART IRRIGATION system is programmed to water the soil for 700ms every 1.5min until the system stops the irrigation process according to the soil moisture level, the reason for a 1.5min buffer between the activation of the water pump during the irrigation process is to allow the water to fully sink into the soil and spread through the soil, hence increase the accuracy of the system and obtain a more precise timing when to stop the irrigation process.
- Smart Irrigation System [Intergrated Code]
- GUI Code [Python]
- Bluetooth Section of Smart Irrigation system [Arduino]
- Soil Moisture Sensor Section of Smart Irrigation System
- Humidity Sensor Section of Smart Irrigation System [Python Fuzzy Logic]
- Humidity Sensor Section of Smart Irrigation System [Arduino]
- Rain Sensor Section of Smart Irrigation System
Smart Irrigation System [Intergrated Code]
Arduino#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]
Pythonimport 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#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#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]
Pythonimport 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#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#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);
}
Comments