#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 tank1RestDurationMinuteAfterFull = 1; // how long to wait after tank1 is full in minutes
const int tank2RestDurationMinuteAfterFull = 1; // how long to wait after tank2 is full in minutes
// Pins
const int lowerTankPin = 3; // Pin for lower tank sensor
const int upperTank1Pin = 4; // Pin for upper tank1 sensor for personal use
const int upperTank2Pin = 7; // Pin for upper tank2 sensor for office use
const int valveSwitch1Pin = 8; // Pin for valve for tank1 for personal use
const int valveSwitch2Pin = 9; // Pin for valve for tank2 for office use
const int relayPin = 12; // 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(tank1RestDurationMinuteAfterFull, 'm'); // Tank 1 Pump rest Time Duration to Millis
unsigned long tank2RestDuration = convertToMillis(tank2RestDurationMinuteAfterFull, 'm'); // 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
int preMode = 0;
int mode = 0;
bool motorRunning = false;
bool motorResting = 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;
class Tank {
public:
// Constructor
Tank(int pin, unsigned long restDuration) : pin(pin), restDuration(restDuration) {
pinMode(pin, INPUT_PULLUP);
lastFullTime = 0;
restTime = false;
}
// Member function to check if the tank is full
bool isFull() {
return digitalRead(pin) == LOW;
}
// Member function to record the time when the tank was last full
void recordFull() {
lastFullTime = millis();
restTime = true;
}
// Member function to determine if the tank can be filled again
bool canFill() {
if (restTime && millis() - lastFullTime < restDuration) {
return false;
}
restTime = false;
return true;
}
private:
int pin; // Pin number for the tank
unsigned long restDuration; // Rest duration in milliseconds
unsigned long lastFullTime; // Last time the tank was full
bool restTime; // Rest time status
};
class LowerTank {
public:
// Constructor
LowerTank(int pin) : pin(pin) {
pinMode(pin, INPUT_PULLUP);
}
// Member function to check if the lower tank has water
bool hasWater() {
return digitalRead(pin) == LOW;
}
private:
int pin; // Pin number for the lower tank
};
class Valve {
public:
// Constructor
Valve(int pin) : pin(pin) {
pinMode(pin, INPUT_PULLUP);
}
// Member function to check if the valve is open
bool isOpen() {
return digitalRead(pin) == LOW;
}
private:
int pin; // Pin number for the valve
};
// Initialize tank and valve objects
LowerTank lowerTank(lowerTankPin);
Tank upperTank1(upperTank1Pin, tank1RestDuration);
Tank upperTank2(upperTank2Pin, tank2RestDuration);
Valve valve1(valveSwitch1Pin);
Valve valve2(valveSwitch2Pin);
void setup() {
Serial.begin(9600); // Initialize serial communication for printing
pinMode(relayPin, OUTPUT);
digitalWrite(relayPin, LOW); // Ensure relay is off at the beginning
lcd.init();
lcd.backlight();
}
void loop() {
int mode = determineMode();
if (motorResting || (motorRunning && millis() - pumpStartTime >= pumpRunTimeDuration)) {
mode = 40; // mode Resting
}
operateMotor(mode);
updateDisplay(statusForDisplay, mode);
scrollText(statusForDisplay);
delay(200);
}
int determineMode() {
if (lowerTank.hasWater()) {
if (valve1.isOpen() && valve2.isOpen()) { // Both valves open
return 12;
} else if (!valve1.isOpen() && !valve2.isOpen()) { // Both valves closed - dangerous
return 11;
} else if (valve1.isOpen()) { // Tank 1 Mode
if (upperTank1.canFill()) {
return 1;
} else {
return 1111; // Tank 1 needs more rest
}
} else if (valve2.isOpen()) { // Tank 2 Mode
if (upperTank2.canFill()) {
return 2;
} else {
return 2222; // Tank 2 needs more rest
}
} else {
return 20; // Other errors
}
} else {
return 30; // Ground Tank is Empty
}
return -1;
}
void operateMotor(int mode) {
switch (mode) {
case 1: // Tank 1 Mode
if (lowerTank.hasWater() && !upperTank1.isFull()) {
turnOnMotor();
statusForDisplay = "Pumping For Tank1--";
} else {
turnOffMotor();
statusForDisplay = "Tank1 Full--";
}
break;
case 2: // Tank 2 Mode
if (lowerTank.hasWater() && !upperTank2.isFull()) {
turnOnMotor();
statusForDisplay = "Pumping For Tank2--";
} else {
turnOffMotor();
statusForDisplay = "Tank2 Full--";
}
break;
case 11: // Both valves closed - dangerous
turnOffMotor();
statusForDisplay = "!!! Both Valves Closed--";
break;
case 12: // Both valves open
turnOffMotor();
statusForDisplay = "!!! Both Valves Open--";
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;
default:
turnOffMotor();
statusForDisplay = "Unknown Mode--";
break;
}
}
void turnOnMotor() {
digitalWrite(relayPin, HIGH); // Turn on the motor
motorRunning = true;
motorResting = false;
pumpStartTime = millis();
}
void turnOffMotor() {
digitalWrite(relayPin, LOW); // Turn off the motor
motorRunning = false;
pumpStopTime = millis();
}
void updateDisplay(String status, int mode) {
if (mode != preMode) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(status.substring(0, 16));
lcd.setCursor(0, 1);
lcd.print(status.substring(16));
preMode = mode;
scrollIndex = 0; // Reset scroll index when mode changes
}
}
void scrollText(String status) {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
lcd.scrollDisplayLeft();
scrollIndex++;
if (scrollIndex >= status.length()) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(status.substring(0, 16));
lcd.setCursor(0, 1);
lcd.print(status.substring(16));
scrollIndex = 0;
}
}
}