#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <math.h>
// Define the LCD address and dimensions
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Define pins for the ultrasonic sensor
const int trigPin = 9;
const int echoPin = 10;
// Define pin for the relay module
const int relayPin = 8;
// Define pin for the pushbutton
const int buttonPin = 7;
// Define pin for the buzzer
const int buzzerPin = 6;
// Variables for duration and distance
long duration;
int distance;
const float minDistance = 2; // Minimum distance for 100% water level in cm
const float maxDistance = 400; // Maximum distance for 0% water level in cm
// Configurable pump control thresholds
const int turnOnPercentage = 15; // Turn on the pump when water level is at or below this percentage
const int cutOffPercentage = 99; // Turn off the pump when water level is at or above this percentage
// Variables for dry run detection
unsigned long pumpStartTime = 0;
bool pumpRunning = false;
bool dryRunDetected = false;
int previousWaterLevelPercent = 0;
int lastWaterLevelPercent = 0;
unsigned long lastCheckTime = 0;
void setup() {
// Initialize the Serial Monitor
Serial.begin(9600);
// Initialize the LCD
lcd.begin(16, 2);
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Water Level:");
// Set the ultrasonic sensor pins as output and input
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
// Set the relay pin as output
pinMode(relayPin, OUTPUT);
// Set the button pin as input with internal pull-up resistor
pinMode(buttonPin, INPUT_PULLUP);
// Set the buzzer pin as output
pinMode(buzzerPin, OUTPUT);
// Initially turn off the pump and buzzer
digitalWrite(relayPin, LOW);
digitalWrite(buzzerPin, LOW);
}
void loop() {
// Clear the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Set the trigPin on HIGH state for 10 microseconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Read the echoPin and calculate the distance
duration = pulseIn(echoPin, HIGH);
distance = duration * 0.034 / 2;
// Calculate water level percentage
int waterLevelPercent = map(distance, maxDistance, minDistance, 0, 100);
waterLevelPercent = constrain(waterLevelPercent, 0, 100);
// Print the water level percentage to the Serial Monitor
Serial.print("Water Level: ");
Serial.print(waterLevelPercent);
Serial.println("%");
// Display the water level percentage on the LCD if no dry run is detected
if (!dryRunDetected) {
lcd.setCursor(0, 1);
lcd.print("Lvl:");
lcd.print(waterLevelPercent);
lcd.print("% "); // Add spaces to ensure old values are overwritten
}
// Control the pump based on water level percentage and dry run state
if (waterLevelPercent <= turnOnPercentage && !pumpRunning && !dryRunDetected) {
// Turn on the pump
digitalWrite(relayPin, HIGH);
pumpStartTime = millis();
pumpRunning = true;
lastWaterLevelPercent = waterLevelPercent;
lastCheckTime = millis();
} else if (waterLevelPercent >= cutOffPercentage && pumpRunning) {
// Turn off the pump
digitalWrite(relayPin, LOW);
pumpRunning = false;
}
// Check for dry run condition
if (pumpRunning && (millis() - lastCheckTime > 10000)) { // 10 seconds
if (waterLevelPercent <= lastWaterLevelPercent) {
// Turn off the pump
digitalWrite(relayPin, LOW);
pumpRunning = false;
dryRunDetected = true;
// Turn on the buzzer
digitalWrite(buzzerPin, HIGH);
// Display dry run warning message
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Dry Run");
} else {
// Update last water level percent if the water level has increased
lastWaterLevelPercent = waterLevelPercent;
}
lastCheckTime = millis(); // Reset the check timer
}
// Check if the button is pressed to reset dry run state
if (digitalRead(buttonPin) == LOW) {
dryRunDetected = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Dry Run Reset "); // Clear the message after reset
// Turn off the buzzer
digitalWrite(buzzerPin, LOW);
delay(1000); // Display the reset message for 1 second
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Water Level:");
}
// Add a delay before the next reading
delay(1000);
}