#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Function to convert time to milliseconds
unsigned long convertToMillis(float time, char unit) {
unsigned long millisValue = 0;
if (unit == 'h') { // time is in hours
millisValue = time * 60 * 60 * 1000UL;
} else if (unit == 'm') { // time is in minutes
millisValue = time * 60 * 1000UL;
}
return millisValue;
}
//========= Changeable ===============
const float pumpRunTimeHour = 1; // Maximum Pump Run Time in hours
const float pumpRestTimeHour = 0.5; // Maximum Pump Rest Time in hours
const int tank1RestDurationAfterFull = 1; // how long to wait after tank1 is full in Hours
const int tank2RestDurationAfterFull = 12; // how long to wait after tank2 is full in Hours
// Floating Switch
const int lowerTank = 2; // Pin for lower tank sensor
const int upperTank1 = 3; // Pin for upper tank1 sensor for personal use
const int upperTank2 = 4; // Pin for upper tank2 sensor for office use
// Limit Switch
const int valveSwitch1 = 6; // Pin for valve for tank1 for personal use
const int valveSwitch2 = 7; // Pin for valve for tank2 for office use
// Relay For Motor
const int relayPin = 8; // Pin for relay
//=====================================================================================
unsigned long pumpRunTimeDuration = convertToMillis(pumpRunTimeHour, 'h'); // Pump Run Time Duration to Millis
unsigned long pumpRestTimeDuration = convertToMillis(pumpRestTimeHour, 'h'); // Pump Rest Time Duration to Millis
unsigned long tank1RestDuration = convertToMillis(tank1RestDurationAfterFull, 'h'); // Tank 1 Pump rest Time Duration to Millis
unsigned long tank2RestDuration = convertToMillis(tank2RestDurationAfterFull, 'h'); // Tank 2 Pump rest Time Duration to Millis
unsigned long currentMillis = 0;
unsigned long pumpStartTime = 0; // Stores the time when the motor started
unsigned long pumpStopTime = 0; // Stores the time when the motor stopped
unsigned long lastTank1FullTime = 0; // Stores when tank 1 was full last time
unsigned long lastTank2FullTime = 0; // Stores when tank 2 was full last time
unsigned long tank1FulledDuration = 0 ; //if mode 1111 then calculation for filled duration
unsigned long tank2FulledDuration = 0 ; //if mode 2222 then calculation for filled duration
int preMode = 0;
int mode = 0;
bool preLowerTankStatus = false;
bool preUpperTank1Status = false;
bool preUpperTank2Status = false;
bool preValveSwitch1Status = false;
bool preValveSwitch2Status = false;
bool preMotorStatus = false;
bool lowerTankStatus = false;
bool upperTank1Status = false; // Upper tank1 is full if it reads LOW
bool upperTank2Status = false; // Upper tank2 is full if it reads LOW
bool valveSwitch1Status = false;
bool valveSwitch2Status = false;
bool motorStatus = false;
bool motorRunning = false;
bool motorResting = false;
bool tank1RestTime = false;
bool tank2RestTime = false;
String statusForDisplay = "";
LiquidCrystal_I2C lcd(0x27, 16, 2); // Set the LCD address to 0x27 for a 16 chars and 2 line display
unsigned long previousMillis = 0; // Stores the last time the display was updated
const long interval = 350; // Interval at which to scroll text (0.35 seconds)
int scrollIndex = 0;
//===================================== Setup =================================
void setup() {
Serial.begin(9600); // Initialize serial communication for printing
pinMode(lowerTank, INPUT_PULLUP);
pinMode(upperTank1, INPUT_PULLUP);
pinMode(upperTank2, INPUT_PULLUP);
pinMode(valveSwitch1, INPUT_PULLUP);
pinMode(valveSwitch2, INPUT_PULLUP);
pinMode(relayPin, OUTPUT);
// Start with the relay off
digitalWrite(relayPin, LOW); // Ensure relay is off at the beginning
lcd.init(); // Initialize the LCD
lcd.backlight(); // Turn on the backlight
}
//===================================== LOOP =================================
void loop() {
lowerTankStatus = checkTank(lowerTank);
upperTank1Status = checkTank(upperTank1);
upperTank2Status = checkTank(upperTank2);
valveSwitch1Status = checkValve(valveSwitch1);
valveSwitch2Status = checkValve(valveSwitch2);
motorStatus = digitalRead(relayPin);
// Record the time tank was full
if (motorRunning && upperTank1Status) {
lastTank1FullTime = millis();
tank1RestTime = true;
}
if (motorRunning && upperTank2Status) {
lastTank2FullTime = millis();
tank2RestTime = true;
}
// if Motor resting check if rest time is over or not and motor ran more than run time, only for over runned motor
if (motorResting) {
if (millis() - pumpStopTime >= pumpRestTimeDuration) {
motorResting = false;
mode = determineMode();
} else {
mode = preMode; // mode Resting
}
} else if (motorRunning && millis() - pumpStartTime >= pumpRunTimeDuration) {
mode = 40; // mode Resting
} else {
mode = determineMode(); //check determineMode here.
}
// =======calculation time for filled water=======================
if (mode == 1111) {
// Calculate the duration since Tank1 was last full
tank1FulledDuration = lastFilledDuration(lastTank1FullTime);
String message = "Tank 1 Filled "+ String(tank1FulledDuration) + " Min ago....";
statusForDisplay = message;
}
if (mode == 2222) {
// Calculate the duration since Tank1 was last full
tank2FulledDuration = lastFilledDuration(lastTank2FullTime);
String message = "Tank 2 Filled "+ String(tank2FulledDuration) + " Min ago....";
statusForDisplay = message;
}
//=======================================================
// Check if any status has changed; if so, proceed with execution, else carry on as before.
if (preLowerTankStatus != lowerTankStatus ||
preUpperTank1Status != upperTank1Status ||
preUpperTank2Status != upperTank2Status ||
preMotorStatus != motorStatus ||
preMode != mode ||
preValveSwitch1Status != valveSwitch1Status ||
preValveSwitch2Status != valveSwitch2Status) {
operateMotor(mode);
clearDisplay();
updateDisplay();
// Update previous status
preLowerTankStatus = lowerTankStatus;
preUpperTank1Status = upperTank1Status;
preUpperTank2Status = upperTank2Status;
preMotorStatus = motorStatus;
preValveSwitch1Status = valveSwitch1Status;
preValveSwitch2Status = valveSwitch2Status;
preMode = mode;
}
scrollText(statusForDisplay);
delay(200);
}
//function to check tank pin high or not
bool checkTank(int pin) {
return (digitalRead(pin) == LOW); // Active-low logic
}
bool checkValve(int pin) {
return (digitalRead(pin) == LOW); // Active-low logic
}
//Turn on motor with essential other varaible update
void turnOnMotor() {
digitalWrite(relayPin, HIGH);
pumpStartTime = millis(); // Update when motor starts
motorRunning = true;
motorResting = false;
motorStatus = digitalRead(relayPin);
}
//Turn off motor with essential other varaible update
void turnOffMotor() {
digitalWrite(relayPin, LOW);
pumpStopTime = millis(); // Update when motor stops
motorRunning = false;
motorStatus = digitalRead(relayPin);
}
// ==========================================determine latest mode=======================
int determineMode() {
if (!lowerTankStatus) {
return 30; // Ground Tank is Empty
}
if (valveSwitch1Status && valveSwitch2Status) {
return 11; // Both valves closed - dangerous
}
if (!valveSwitch1Status && !valveSwitch2Status) {
return 12; // Both valves open
}
if (valveSwitch1Status && upperTank1Status) {
return 1111;
}
if (valveSwitch2Status && upperTank2Status) {
return 2222;
}
if (valveSwitch1Status) { // Tank 1 Mode
if (!tank1RestTime) {
return 1;
} else {
if (millis() - lastTank1FullTime >= tank1RestDuration) {
tank1RestTime = false;
return 1;
} else {
return 1111; // Tank 1 is resting
}
}
}
if (valveSwitch2Status) { // Tank 2 Mode
if (!tank2RestTime) {
return 2;
} else {
if (millis() - lastTank2FullTime >= tank2RestDuration) {
tank2RestTime = false;
return 2;
} else {
return 2222; // Tank 2 is resting
}
}
}
return 20; // Error Mode
}
//================================================Motor Operation=============================
void operateMotor(int mode) {
switch (mode) {
case 1: // Tank 1 Mode
if (lowerTankStatus && !upperTank1Status) {
turnOnMotor();
statusForDisplay = "Pumping For Tank1--";
} else {
turnOffMotor();
statusForDisplay = "Tank1 Full--";
}
break;
case 2: // Tank 2 Mode
if (lowerTankStatus && !upperTank2Status) {
turnOnMotor();
statusForDisplay = "Pumping For Tank2--";
} else {
turnOffMotor();
statusForDisplay = "Tank2 Full--";
}
break;
case 11: // Both valves closed - dangerous
turnOffMotor();
statusForDisplay = "!!! Both Valves Open--";
break;
case 12: // Both valves open
turnOffMotor();
statusForDisplay = "!!! Both Valves Closed--";
break;
case 20: // Other errors
turnOffMotor();
statusForDisplay = "Other Errors--";
break;
case 30: // Ground Tank is Empty
turnOffMotor();
statusForDisplay = "Ground Tank Is Empty ==";
break;
case 40: // Resting Time
turnOffMotor();
statusForDisplay = "Resting Time---";
motorResting = true;
break;
case 1111: // Additional Resting Time (if needed)
turnOffMotor();
statusForDisplay = "Tank-1 Recently Filled--";
break;
case 2222: // Additional Resting Time (if needed)
turnOffMotor();
statusForDisplay = "Tank-2 Recently Filled---";
break;
}
}
//=================== Time Calculation for recently filled
int lastFilledDuration(unsigned long lastTimeFilled) {
return (millis() - lastTimeFilled) / 60000;
}
// =================================Update display===================
void updateDisplay() {
Serial.print("Lower Tank is ");
Serial.println(lowerTankStatus ? "Full" : "Low");
Serial.println("..............................");
Serial.print("Upper Tank1 is ");
Serial.println(upperTank1Status ? "Full" : "Low");
Serial.print("Upper Tank2 is ");
Serial.println(upperTank2Status ? "Full" : "Low");
Serial.println("..............................");
Serial.print("Valve1 is ");
Serial.println(valveSwitch1Status ? "On" : "Off");
Serial.print("Valve2 is ");
Serial.println(valveSwitch2Status ? "On" : "Off");
Serial.println("..............................");
Serial.print("Current Mode Is: ");
Serial.println(mode);
Serial.println("..............................");
Serial.print("Last Pump Started: ");
Serial.println(pumpStartTime);
Serial.print("Last Pump Stopped: ");
Serial.println(pumpStopTime);
Serial.println(motorStatus);
Serial.println(millis());
// Print to LCD
lcd.setCursor(0, 0);
lcd.print("GT:");
lcd.print(lowerTankStatus ? "OK" : "Low");
lcd.print(" M:");
lcd.print(mode);
// Print the statusForDisplay in the second line
lcd.setCursor(0, 1);
lcd.print(statusForDisplay.substring(0, 16));
}
void scrollText(String message) {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
lcd.setCursor(0, 1);
String displayMessage = message + " ";
String scrollMessage = displayMessage.substring(scrollIndex) + displayMessage.substring(0, scrollIndex);
lcd.print(scrollMessage.substring(0, 16));
scrollIndex = (scrollIndex + 1) % displayMessage.length();
}
}
void clearDisplay() {
for (int i = 0; i < 10; i++) {
Serial.println();
}
lcd.clear();
}