#include <Wire.h> // This library is used for communication between devices using the I2C protocol
#include <LiquidCrystal_I2C.h> // This library helps control an LCD that communicates using I2C
// Define the LCD address and its size (16 columns and 2 rows)
#define LCD_ADDRESS 0x27
#define LCD_COLUMNS 16
#define LCD_ROWS 2
// Define pins for the ultrasonic sensors (used to measure distance)
#define TRIG_PIN 2
#define ECHO_PIN 3
#define TRIG_PIN2 4
#define ECHO_PIN2 5
#define TRIG_PIN3 6
#define ECHO_PIN3 7
// Define the relay pin (used to control the pump) and switches for manual/auto modes
#define RELAY_PIN 13
#define AUTO_MANUAL_SWITCH_PIN 11
#define MANUAL_SWITCH_PIN 10
// Define pins for LEDs that indicate Auto and Manual modes
#define AUTO_LED_PIN 8
#define MANUAL_LED_PIN 9
// Define pins for the solenoid valves and their indicator LEDs
#define SOLENOID_VALVE1_PIN 12
#define SOLENOID_VALVE2_PIN 14
#define SOLENOID_VALVE1_LED_PIN 15
#define SOLENOID_VALVE2_LED_PIN 16
// Define a pin for the Pump's status LED
#define PUMP_LED_PIN 17
// Define constants for the tank's physical properties and control percentages
#define TANK_HEIGHT 200 // The height of the tank in centimeters
#define START_PUMP_PERCENTAGE 45 // Pump starts when the water is 45% full
#define STOP_PUMP_PERCENTAGE 88 // Pump stops when the water is 88% full
// Define a debounce delay (helps prevent switch bouncing issues)
#define DEBOUNCE_DELAY 200
// Define how frequently (in milliseconds) the sensors should check the water level
#define SENSOR_INTERVAL 500
// Create an LCD object (to control the LCD)
LiquidCrystal_I2C lcd(LCD_ADDRESS, LCD_COLUMNS, LCD_ROWS);
// Variables for keeping track of time and switch states
unsigned long previousSensorMillis = 0;
unsigned long previousDebounceMillis = 0;
bool lastManualSwitchState = LOW; // Tracks the last state of the manual switch
bool pumpManualState = LOW; // Keeps track of whether the pump is on in manual mode
void setup() {
// Set up pin modes for the ultrasonic sensors (output for trigger, input for echo)
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(TRIG_PIN2, OUTPUT);
pinMode(ECHO_PIN2, INPUT);
pinMode(TRIG_PIN3, OUTPUT);
pinMode(ECHO_PIN3, INPUT);
// Set up pin modes for relay and switches
pinMode(RELAY_PIN, OUTPUT);
pinMode(AUTO_MANUAL_SWITCH_PIN, INPUT_PULLUP); // Pull-up means the switch is normally high
pinMode(MANUAL_SWITCH_PIN, INPUT_PULLUP);
// Set up pin modes for the mode LEDs (Auto/Manual)
pinMode(AUTO_LED_PIN, OUTPUT);
pinMode(MANUAL_LED_PIN, OUTPUT);
// Set up pin modes for the solenoid valves and their LEDs
pinMode(SOLENOID_VALVE1_PIN, OUTPUT);
pinMode(SOLENOID_VALVE2_PIN, OUTPUT);
pinMode(SOLENOID_VALVE1_LED_PIN, OUTPUT);
pinMode(SOLENOID_VALVE2_LED_PIN, OUTPUT);
// Set up pin mode for the Pump LED
pinMode(PUMP_LED_PIN, OUTPUT);
// Initialize everything to OFF at the start
digitalWrite(RELAY_PIN, LOW);
digitalWrite(SOLENOID_VALVE1_PIN, LOW);
digitalWrite(SOLENOID_VALVE2_PIN, LOW);
digitalWrite(PUMP_LED_PIN, LOW);
// Initialize the LCD and turn on its backlight
lcd.begin(LCD_COLUMNS, LCD_ROWS);
lcd.backlight();
// Display a welcome message on the LCD
lcd.setCursor(0, 0);
lcd.print("GOD IS MY LIGHT");
lcd.setCursor(0, 1);
lcd.print("SmartPumpCrtSys");
// Wait for 1 second to show the welcome message
delay(1000);
// Clear the LCD to prepare it for further use
lcd.clear();
}
void loop() {
unsigned long currentMillis = millis(); // Get the current time
// Check if it's time to read the sensors again
if (currentMillis - previousSensorMillis >= SENSOR_INTERVAL) {
previousSensorMillis = currentMillis;
// Measure the distance from each ultrasonic sensor (in cm)
int distance1 = getDistance(TRIG_PIN, ECHO_PIN);
int distance2 = getDistance(TRIG_PIN2, ECHO_PIN2);
int distance3 = getDistance(TRIG_PIN3, ECHO_PIN3);
// If any sensor fails, display an error message
if (distance1 < 0 || distance2 < 0 || distance3 < 0) {
lcd.setCursor(0, 0);
lcd.print("Sensor Error ");
return;
}
// Convert distance to water level as a percentage (0-100%)
int waterLevel1 = map(distance1, 0, TANK_HEIGHT, 100, 0);
int waterLevel2 = map(distance2, 0, TANK_HEIGHT, 100, 0);
int waterLevel3 = map(distance3, 0, TANK_HEIGHT, 100, 0);
// Display water levels of tank 1 and tank 2 on the LCD
lcd.setCursor(0, 0);
lcd.print("L1:");
lcd.print(waterLevel1);
lcd.print("% L2:");
lcd.print(waterLevel2);
lcd.print("%");
// Display water level of tank 3 and the mode on the LCD
lcd.setCursor(0, 1);
lcd.print("L3:");
lcd.print(waterLevel3);
lcd.print("%");
// Check if the system is in Auto mode (switch is HIGH)
if (digitalRead(AUTO_MANUAL_SWITCH_PIN) == HIGH) {
// Turn on the Auto LED and turn off the Manual LED
digitalWrite(AUTO_LED_PIN, HIGH);
digitalWrite(MANUAL_LED_PIN, LOW);
// Indicate Auto mode on the LCD
lcd.setCursor(6, 1);
lcd.print("Auto "); // Add spaces to clear leftover characters
// In Auto mode, control the solenoid valves and pump automatically
controlSolenoidValve(waterLevel2, SOLENOID_VALVE1_PIN, SOLENOID_VALVE1_LED_PIN);
controlSolenoidValve(waterLevel3, SOLENOID_VALVE2_PIN, SOLENOID_VALVE2_LED_PIN);
controlPump(waterLevel1);
} else { // System is in Manual mode
// Turn on the Manual LED and turn off the Auto LED
digitalWrite(AUTO_LED_PIN, LOW);
digitalWrite(MANUAL_LED_PIN, HIGH);
// Indicate Manual mode on the LCD
lcd.setCursor(6, 1);
lcd.print("Manual "); // Add spaces to clear leftover characters
// Turn off the solenoid valves in Manual mode
digitalWrite(SOLENOID_VALVE1_PIN, LOW);
digitalWrite(SOLENOID_VALVE1_LED_PIN, LOW);
digitalWrite(SOLENOID_VALVE2_PIN, LOW);
digitalWrite(SOLENOID_VALVE2_LED_PIN, LOW);
// Handle manual pump control
if (currentMillis - previousDebounceMillis >= DEBOUNCE_DELAY) {
bool manualSwitchState = digitalRead(MANUAL_SWITCH_PIN);
if (manualSwitchState != lastManualSwitchState) {
previousDebounceMillis = currentMillis;
lastManualSwitchState = manualSwitchState;
if (manualSwitchState == HIGH) {
pumpManualState = !pumpManualState; // Toggle pump state
}
}
}
// Display pump status based on manual switch
if (pumpManualState) {
lcd.setCursor(13, 1);
lcd.print("ON ");
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(PUMP_LED_PIN, HIGH);
} else {
lcd.setCursor(13, 1);
lcd.print("OFF");
digitalWrite(RELAY_PIN, LOW);
digitalWrite(PUMP_LED_PIN, LOW);
}
}
}
}
// Function to get the distance measured by an ultrasonic sensor
int getDistance(int trigPin, int echoPin) {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Measure the time it takes for the ultrasonic signal to return
long duration = pulseIn(echoPin, HIGH, 25000); // Timeout after 25ms
if (duration == 0) {
return -1; // Return error if no signal is received
}
// Convert the time to distance (in cm)
int distance = (duration * 0.0343) / 2;
if (distance < 0 || distance > TANK_HEIGHT) {
return -1; // Return error if the distance is out of range
}
return distance;
}
// Function to control the pump based on water level
void controlPump(int waterLevel) {
if (waterLevel < START_PUMP_PERCENTAGE) {
lcd.setCursor(13, 1); // Show pump status at the end of the second row
lcd.print("ON ");
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(PUMP_LED_PIN, HIGH); // Turn on the pump and its LED
} else if (waterLevel > STOP_PUMP_PERCENTAGE) {
lcd.setCursor(13, 1);
lcd.print("OFF");
digitalWrite(RELAY_PIN, LOW);
digitalWrite(PUMP_LED_PIN, LOW); // Turn off the pump and its LED
}
}
// Function to control a solenoid valve based on water level
void controlSolenoidValve(int waterLevel, int valvePin, int ledPin) {
if (waterLevel < START_PUMP_PERCENTAGE) {
digitalWrite(valvePin, HIGH);
digitalWrite(ledPin, HIGH); // Open the valve and turn on its LED
} else if (waterLevel > STOP_PUMP_PERCENTAGE) {
digitalWrite(valvePin, LOW);
digitalWrite(ledPin, LOW); // Close the valve and turn off its LED
}
}