#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <TimeLib.h>
#include <EEPROM.h>
const int washRelayPin = 2;
const int spinRelayPin = 5;
const int fillRelayPin = 18;
const int drainRelayPin = 23;
// Initialize the LCD display using Wire library
LiquidCrystal_I2C lcd(0x27, 16, 2);
const int normalWashButtonPin = 14;
const int quickWashButtonPin = 12;
const int resetButtonPin = 13;
enum MachineState {
IDLE,
BALANCING,
WASH,
RINSE,
SPINLOW,
SPIN,
FINISHED
};
MachineState currentState = IDLE;
unsigned long balancingDuration, washDuration, rinseDuration, spinLowDuration, spinDuration;
unsigned long cycleStartTime = 0;
unsigned long timeLeft = 0;
unsigned long lastUpdateTime = 0;
const unsigned long updateTimeInterval = 1000;
unsigned long fillDuration = 5000;
unsigned long drainDuration = 3000;
const unsigned long normalBalancingDuration = 10000;
const unsigned long normalWashDuration = 30000;
const unsigned long normalRinseDuration = 15000;
const unsigned long normalSpinLowDuration = 7000;
const unsigned long normalSpinDuration = 10000;
const unsigned long quickBalancingDuration = 10000;
const unsigned long quickWashDuration = 15000;
const unsigned long quickRinseDuration = 7000;
const unsigned long quickSpinLowDuration = 2000;
const unsigned long quickSpinDuration = 5000;
bool isNormalMode = false;
bool secondCycleRinse = false;
bool secondCycleBalancing = false;
bool idleMessagePrinted = false;
bool fillingWaterMessagePrinted = false;
bool fillingWaterMessagePrinted1 = false;
bool washingMessagePrinted = false;
bool washingMessagePrintedSerial = false;
bool drainingWaterMessagePrinted = false;
bool drainingWaterMessagePrinted1 = false;
bool rinsingMessagePrinted = false;
bool balancingMessagePrinted = false;
bool spinningMessagePrinted = false;
bool spinningLowMessagePrinted = false;
bool finishedMessagePrinted = false;
bool infoMode = false;
String normalModeInfo = "Normal Mode";
String quickModeInfo = "Quick Mode";
void setup() {
Serial.begin(115200);
pinMode(washRelayPin, OUTPUT);
pinMode(spinRelayPin, OUTPUT);
pinMode(fillRelayPin, OUTPUT);
pinMode(drainRelayPin, OUTPUT);
pinMode(normalWashButtonPin, INPUT_PULLUP);
pinMode(quickWashButtonPin, INPUT_PULLUP);
pinMode(resetButtonPin, INPUT_PULLUP);
Wire.begin();
Wire.beginTransmission(0x3F);
if (Wire.endTransmission()) {
// lcd = LiquidCrystal_I2C(0x27, 20, 4);
LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display
EEPROM.begin(512);
}
//lcd.begin();
lcd.init();
lcd.backlight();
}
void loop() {
handleSerialCommands();
handleButtonInput();
switch (currentState) {
case IDLE:
if (!idleMessagePrinted) {
idleMessagePrinted = true;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Machine is Idle");
lcd.setCursor(0, 1);
lcd.print("Press Start");
}
break;
case BALANCING:
displayAdditionalInfo("BALANCING");
updateTimer();
runBalancingCycle();
break;
case WASH:
displayAdditionalInfo("WASH");
updateTimer();
runWashCycle();
break;
case RINSE:
displayAdditionalInfo("RINSE");
updateTimer();
runRinseCycle();
break;
case SPINLOW:
displayAdditionalInfo("SPINLOW");
updateTimer();
runSpinLowCycle();
break;
case SPIN:
displayAdditionalInfo("SPIN");
updateTimer();
runSpinCycle();
break;
case FINISHED:
currentState = IDLE;
Serial.println("Washing machine cycle finished. Returning to idle state.");
resetFlags();
break;
}
}
void handleSerialCommands() {
if (Serial.available() <= 0) return;
char command = Serial.read();
switch (command) {
case 'W':
if (currentState == IDLE) {
startWash(normalBalancingDuration, normalWashDuration, normalRinseDuration, normalSpinLowDuration, normalSpinDuration);
}
break;
case 'Q':
if (currentState == IDLE) {
startWash(quickBalancingDuration, quickWashDuration, quickRinseDuration, quickSpinLowDuration, quickSpinDuration);
}
break;
case 'S':
emergencyStop();
break;
}
}
void handleButtonInput() {
if (digitalRead(normalWashButtonPin) == LOW && currentState == IDLE) {
startWash(normalBalancingDuration, normalWashDuration, normalRinseDuration, normalSpinLowDuration, normalSpinDuration);
} else if (digitalRead(quickWashButtonPin) == LOW && currentState == IDLE) {
startWash(quickBalancingDuration, quickWashDuration, quickRinseDuration, quickSpinLowDuration, quickSpinDuration);
}
}
void displayAdditionalInfo(String state) {
String info = isNormalMode ? normalModeInfo : quickModeInfo;
int minutes = timeLeft / 60000; // Convert milliseconds to minutes
int seconds = (timeLeft % 60000) / 1000; // Convert remaining milliseconds to seconds
String timeLeftStr = String(minutes) + ":" + (seconds < 10 ? "0" : "") + String(seconds);
if (!statePrinted(state)) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(info);
lcd.setCursor(0, 1);
lcd.print(state);
markStateAsPrinted(state);
}
// lcd.setCursor(8, 1);
// lcd.print(timeLeftStr);
}
bool statePrinted(String state) {
if (state == "IDLE") return idleMessagePrinted;
if (state == "WASH") return washingMessagePrinted;
if (state == "BALANCING") return balancingMessagePrinted;
if (state == "RINSE") return rinsingMessagePrinted;
if (state == "SPINLOW") return spinningLowMessagePrinted;
if (state == "SPIN") return spinningMessagePrinted;
if (state == "FINISHED") return finishedMessagePrinted;
return false;
}
void markStateAsPrinted(String state) {
if (state == "IDLE") idleMessagePrinted = true;
if (state == "WASH") washingMessagePrinted = true;
if (state == "BALANCING") balancingMessagePrinted = true;
if (state == "RINSE") rinsingMessagePrinted = true;
if (state == "SPINLOW") spinningLowMessagePrinted = true;
if (state == "SPIN") spinningMessagePrinted = true;
if (state == "FINISHED") finishedMessagePrinted = true;
}
void updateTimer() {
unsigned long currentTime = millis();
// Update timeLeft every second
if (currentTime - lastUpdateTime >= updateTimeInterval && timeLeft > 0) {
timeLeft -= updateTimeInterval;
lastUpdateTime = currentTime;
}
}
void startWash(unsigned long balancing, unsigned long wash, unsigned long rinse, unsigned long spinlow, unsigned long spin) {
currentState = BALANCING;
balancingDuration = balancing;
washDuration = wash + fillDuration + drainDuration;
rinseDuration = rinse + fillDuration + drainDuration;
spinDuration = spin;
spinLowDuration = spinlow;
isNormalMode = (wash == normalWashDuration);
timeLeft = washDuration + rinseDuration + spinDuration;
cycleStartTime = millis();
Serial.println(isNormalMode ? "Normal Wash cycle started." : "Quick Wash cycle started.");
}
void emergencyStop() {
digitalWrite(washRelayPin, LOW);
digitalWrite(spinRelayPin, LOW);
currentState = IDLE;
secondCycleRinse = false;
resetFlags();
Serial.println("EMERGENCY STOP. Machine halted.");
}
void resetFlags() {
idleMessagePrinted = false;
fillingWaterMessagePrinted = false;
washingMessagePrinted = false;
drainingWaterMessagePrinted = false;
rinsingMessagePrinted = false;
spinningMessagePrinted = false;
finishedMessagePrinted = false;
washingMessagePrintedSerial = false;
}
void runWashCycle() {
// Fill water
if (!fillingWaterMessagePrinted) {
Serial.println("Filling water...");
fillingWaterMessagePrinted = true;
}
if (millis() - cycleStartTime >= fillDuration) {
digitalWrite(fillRelayPin, LOW); // Turn off fill
}
// Continue washing
if (millis() - cycleStartTime >= fillDuration && millis() - cycleStartTime < fillDuration + washDuration) {
if (!washingMessagePrinted) {
Serial.println("Washing...");
washingMessagePrinted = true;
}
// digitalWrite(washRelayPin, HIGH); // Turn on the relay for WASH state
static unsigned long patternStartTime = millis();
static bool relayOn = true;
// Execute relay pattern with a 3-second interval
if (millis() - patternStartTime >= 2000) {
if (relayOn) {
digitalWrite(washRelayPin, LOW);
Serial.println("relay off...");
relayOn = false;
} else {
digitalWrite(washRelayPin, HIGH);
Serial.println("relay on...");
relayOn = true;
}
patternStartTime = millis();
}
}
// Drain water
if (millis() - cycleStartTime >= fillDuration + washDuration) {
if (!drainingWaterMessagePrinted) {
Serial.println("Draining water...");
drainingWaterMessagePrinted = true;
}
digitalWrite(washRelayPin, LOW); // Turn off washing
digitalWrite(drainRelayPin, HIGH); // Turn on drain
}
// Washing cycle completed, transition to SPIN
if (millis() - cycleStartTime >= fillDuration + washDuration + drainDuration) {
currentState = SPINLOW;
cycleStartTime = millis();
digitalWrite(drainRelayPin, LOW); // Turn off drain
digitalWrite(spinRelayPin, HIGH); // Turn on spin
Serial.println("Washing cycle completed. Starting Spin Low cycle...");
}
}
void runBalancingCycle() {
if (millis() - cycleStartTime < balancingDuration) {
if (!balancingMessagePrinted) {
Serial.println("Balancing...");
balancingMessagePrinted = true;
}
// digitalWrite(washRelayPin, HIGH); // Turn on the relay for BALANCING state
// Serial.println("relay bal on...");
static unsigned long patternStartTime = millis();
static bool relayOn = true;
// Execute relay pattern with a 3-second interval
if (millis() - patternStartTime >= 1000) {
if (relayOn) {
digitalWrite(washRelayPin, LOW);
Serial.println("relay bal off...");
relayOn = false;
} else {
digitalWrite(washRelayPin, HIGH);
Serial.println("relay bal on...");
relayOn = true;
}
patternStartTime = millis();
}
} else {
currentState = WASH;
cycleStartTime = millis();
digitalWrite(washRelayPin, LOW); // Turn off balancing
Serial.println("relay bal off...");
Serial.println("Balancing cycle completed. Starting wash cycle...");
}
}
void runRinseCycle() {
// Fill water
if (!fillingWaterMessagePrinted) {
Serial.println("Filling water...");
fillingWaterMessagePrinted = true;
}
if (millis() - cycleStartTime >= fillDuration) {
digitalWrite(fillRelayPin, LOW); // Turn off fill
}
// Continue washing
if (millis() - cycleStartTime >= fillDuration && millis() - cycleStartTime < fillDuration + rinseDuration) {
if (!washingMessagePrinted) {
Serial.println("Washing...");
washingMessagePrinted = true;
}
// digitalWrite(washRelayPin, HIGH); // Turn on the relay for WASH state
static unsigned long patternStartTime = millis();
static bool relayOn = true;
// Execute relay pattern with a 3-second interval
if (millis() - patternStartTime >= 2000) {
if (relayOn) {
digitalWrite(washRelayPin, LOW);
Serial.println("relay off...");
relayOn = false;
} else {
digitalWrite(washRelayPin, HIGH);
Serial.println("relay on...");
relayOn = true;
}
patternStartTime = millis();
}
}
// Drain water
if (millis() - cycleStartTime >= fillDuration + rinseDuration) {
if (!drainingWaterMessagePrinted) {
Serial.println("Draining water...");
drainingWaterMessagePrinted = true;
}
digitalWrite(washRelayPin, LOW); // Turn off washing
digitalWrite(drainRelayPin, HIGH); // Turn on drain
}
// Washing cycle completed, transition to SPIN
if (isNormalMode && !secondCycleRinse) {
if (millis() - cycleStartTime >= fillDuration + rinseDuration + drainDuration) {
currentState = SPINLOW;
cycleStartTime = millis();
digitalWrite(drainRelayPin, LOW); // Turn off drain
digitalWrite(spinRelayPin, HIGH); // Turn on spin
Serial.println("Rinse cycle completed. Starting Spin Low cycle...");
}
secondCycleRinse = true;
} else {
if (millis() - cycleStartTime >= fillDuration + rinseDuration + drainDuration) {
currentState = SPIN;
cycleStartTime = millis();
digitalWrite(drainRelayPin, LOW); // Turn off drain
digitalWrite(spinRelayPin, HIGH); // Turn on spin
Serial.println("Rinse cycle completed. Starting Spin cycle...");
}
secondCycleRinse = false;
}
}
void runSpinLowCycle() {
digitalWrite(spinRelayPin, HIGH);
if (millis() - cycleStartTime >= spinLowDuration) {
currentState = RINSE;
cycleStartTime = millis();
digitalWrite(spinRelayPin, LOW);
Serial.println("Low Spin cycle completed. Starting Rinse...");
}
}
void runSpinCycle() {
digitalWrite(spinRelayPin, HIGH);
if (millis() - cycleStartTime >= spinDuration) {
currentState = FINISHED;
cycleStartTime = millis();
digitalWrite(spinRelayPin, LOW);
Serial.println("Spin cycle completed. Finished.");
}
}