#include <Keypad.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// OLED Display setup
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Keypad setup
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
// KEYPAD PINS: 2,3,4,5,6,7,8,9
byte rowPins[ROWS] = {2, 3, 4, 5}; // Rows: pins 2-5
byte colPins[COLS] = {6, 7, 8, 9}; // Columns: pins 6-9
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// Component pins
const int buzzerPin = A2; // Buzzer
const int greenLED = 12; // Green LED (shows PUMP STATUS: ON when pump running)
const int redLED = 11; // Red LED (shows SYSTEM STATUS)
const int relayPin = 10; // Relay (controls pump)
const int trigPin = A0; // Ultrasonic trigger
const int echoPin = A1; // Ultrasonic echo
// Password setup
const String password = "1234";
String inputPassword = "";
// Water tank dimensions
const float tankHeight = 6.0;
const float tankLength = 16.5;
const float tankWidth = 11.5;
// System variables
bool pumpRunning = false;
unsigned long pumpStartTime = 0;
unsigned long lastDisplayUpdate = 0;
bool showingMessage = false;
unsigned long messageTime = 0;
void setup() {
Serial.begin(9600);
Serial.println("=== WATER DISPENSER ===");
// Initialize pins
pinMode(buzzerPin, OUTPUT);
pinMode(greenLED, OUTPUT);
pinMode(redLED, OUTPUT);
pinMode(relayPin, OUTPUT);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
// Initialize keypad pins (2-9)
for (int i = 2; i <= 9; i++) {
pinMode(i, INPUT_PULLUP);
}
// Initial states
digitalWrite(relayPin, LOW); // Relay OFF initially
digitalWrite(greenLED, LOW); // Green LED OFF (pump not running)
digitalWrite(redLED, HIGH); // Red LED ON (system ready)
digitalWrite(buzzerPin, LOW); // Buzzer OFF
// Initialize OLED
Wire.begin();
delay(100);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) {
Serial.println("OLED not found!");
}
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
// Show startup screen
display.clearDisplay();
display.setCursor(30, 10);
display.println("WATER DISPENSER");
display.setCursor(40, 20);
display.println("SYSTEM");
display.display();
// Startup beep
beep(1);
delay(1000);
// Show main interface
showMessage("ENTER CODE: 1234", 1500);
updateMainDisplay();
Serial.println("System Ready!");
Serial.println("Green LED: Shows PUMP STATUS");
Serial.println("Red LED: Shows SYSTEM STATUS");
Serial.println("Enter 1234# to start pump");
Serial.println("Press ANY button to stop pump");
}
void loop() {
// Check if message should be cleared
if (showingMessage && (millis() - messageTime >= 2000)) {
showingMessage = false;
updateDisplay();
}
// Update display every 2 seconds when not showing message
if (!showingMessage && millis() - lastDisplayUpdate >= 2000) {
lastDisplayUpdate = millis();
updateDisplay();
}
// Check keypad
char key = keypad.getKey();
if (key) {
Serial.print("Key pressed: ");
Serial.println(key);
// If pump is running, ANY button stops it
if (pumpRunning) {
stopPump();
showMessage("PUMP STOPPED", 1500);
return;
}
// If pump not running, handle normal input
handleKeypress(key);
}
}
void updateDisplay() {
if (showingMessage) return;
float waterLevel = getWaterLevel();
float waterVolume = calculateWaterVolume(waterLevel);
if (pumpRunning) {
displayPumpRunningScreen();
} else {
updateWaterDisplay(waterLevel, waterVolume);
}
}
float getWaterLevel() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH, 30000);
if (duration == 0) return 0.0;
float distance = duration * 0.034 / 2;
float waterLevel = tankHeight - distance;
waterLevel = constrain(waterLevel, 0, tankHeight);
return waterLevel;
}
float calculateWaterVolume(float waterLevel) {
return (tankLength * tankWidth * waterLevel) / 1000.0;
}
void handleKeypress(char key) {
// Keypress beep
digitalWrite(buzzerPin, HIGH);
delay(30);
digitalWrite(buzzerPin, LOW);
if (key == '#') {
// Submit password
checkPassword();
}
else if (key == '*') {
// Clear input
inputPassword = "";
Serial.println("Input cleared");
showMessage("INPUT CLEARED", 1000);
}
else if (key >= '0' && key <= '9') {
// Add digit to password
if (inputPassword.length() < 6) {
inputPassword += key;
Serial.print("Current input: ");
Serial.println(inputPassword);
// Show asterisks
showPasswordEntry();
}
}
}
void showPasswordEntry() {
display.clearDisplay();
display.setCursor(20, 5);
display.println("ENTER CODE:");
display.setCursor(40, 15);
for (int i = 0; i < inputPassword.length(); i++) {
display.print("*");
}
display.setCursor(10, 25);
display.println("#=START *=CLEAR");
display.display();
}
void checkPassword() {
Serial.print("Checking password: ");
Serial.println(inputPassword);
if (inputPassword == password) {
Serial.println("✓ PASSWORD CORRECT!");
beep(2);
startPump();
inputPassword = "";
} else {
Serial.println("✗ WRONG PASSWORD!");
beep(3);
showMessage("WRONG CODE", 1500);
inputPassword = "";
}
}
void startPump() {
// MODIFIED: Check water level - changed from 2.0cm to 1.0cm
float waterLevel = getWaterLevel();
if (waterLevel < 1.0) { // Changed from <= 2.0 to < 1.0
showMessage("LOW WATER!", 2000);
beep(3);
return;
}
Serial.println("Starting pump...");
pumpRunning = true;
pumpStartTime = millis();
// Turn ON relay (pump starts)
digitalWrite(relayPin, HIGH);
// Update LEDs
digitalWrite(greenLED, HIGH); // Green ON (pump running)
digitalWrite(redLED, LOW); // Red OFF (system busy)
// Show pump started message
showMessage("PUMP STARTED", 1000);
Serial.println("Pump running. Press ANY button to stop.");
}
void stopPump() {
Serial.println("Stopping pump...");
pumpRunning = false;
// Turn OFF relay
digitalWrite(relayPin, LOW);
// Update LEDs
digitalWrite(greenLED, LOW); // Green OFF (pump stopped)
digitalWrite(redLED, HIGH); // Red ON (system ready)
// Stop beep
beep(1);
Serial.println("Pump stopped.");
}
void displayPumpRunningScreen() {
display.clearDisplay();
// Draw water tank
display.drawRect(5, 5, 40, 22, SSD1306_WHITE);
// Animated water level (shows its working)
int animation = (millis() / 500) % 20;
int waterHeight = animation;
if (waterHeight > 0) {
display.fillRect(6, 26 - waterHeight, 38, waterHeight, SSD1306_WHITE);
}
// Pump status
display.setCursor(50, 5);
display.println("PUMP RUNNING");
// Instructions
display.setCursor(50, 15);
display.println("PRESS ANY");
display.setCursor(50, 25);
display.println("KEY TO STOP");
display.display();
}
void updateMainDisplay() {
display.clearDisplay();
display.setCursor(30, 0);
display.println("WATER DISPENSER");
display.setCursor(10, 10);
display.println("STATUS: READY");
display.setCursor(10, 20);
display.println("CODE: 1234#");
display.display();
}
void updateWaterDisplay(float waterLevel, float waterVolume) {
display.clearDisplay();
// Draw water tank
display.drawRect(5, 5, 40, 22, SSD1306_WHITE);
// Water level visualization
int waterHeight = map(waterLevel, 0, tankHeight, 0, 20);
if (waterHeight > 0) {
display.fillRect(6, 26 - waterHeight, 38, waterHeight, SSD1306_WHITE);
}
// Water info
display.setCursor(50, 5);
display.print("WATER: ");
display.print(waterLevel, 1);
display.println("cm");
display.setCursor(50, 15);
display.print("VOL: ");
display.print(waterVolume, 2);
display.println("L");
// MODIFIED: Status display - changed from < 5.0cm to < 1.0cm
display.setCursor(50, 25);
if (waterLevel < 1.0) { // Changed from < 5.0 to < 1.0
display.print("REFILL!");
} else {
display.print("READY");
}
display.display();
}
void showMessage(String message, int duration) {
showingMessage = true;
messageTime = millis();
display.clearDisplay();
display.setCursor(10, 12);
display.println(message);
display.display();
delay(duration);
showingMessage = false;
}
void beep(int times) {
for (int i = 0; i < times; i++) {
digitalWrite(buzzerPin, HIGH);
delay(100);
digitalWrite(buzzerPin, LOW);
if (i < times - 1) delay(50);
}
}