/*
Coin acceptor with timer : 12-16-24
unit: arduino mega
auth: oliver feronel
preliminary pin sets
*/
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
#define COIN_AC 2 // Coin acceptor pin
#define SET_TIME_TYPE 4 // Set minutes or hour
#define UP_BTN 5 // Move up time
#define DOWN_BTN 6 // Move down time
#define SET_TIME 7 // Set time if it's ok now
#define RELAY_1 8 // SSR 1 connection
bool set_active = false; // Check if set time is active -> allow edit
bool set_min = false; // Check if need to update minutes or hour
int hour = 0;
int minutes = 0;
unsigned long countdownDuration = 0; // Countdown duration in milliseconds
unsigned long previousMillis = 0; // Stores the last time update was made
bool countdownActive = true; // run countdown if thers still time else stop
unsigned long lastDebounceTime = 0; // Last debounce time
unsigned long debounceDelay = 200; // Debounce delay (milliseconds)
String lcd_line_0 = ""; // on this we store LCD data to be print so we can read it later
String lcd_line_1 = "";
String lcd_line_2 = "";
String lcd_line_3 = "";
void setup() {
Serial.begin(115200);
Serial.println("Start of everything here");
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd_line_0 = "WATER VENDO MACHINE";
lcd.print(lcd_line_0);
for (int i = 0; i < 10; i++) {
byte value = EEPROM.read(i); // Read the value at address `i`
// Check if the value is not in the expected range (e.g., ASCII range or custom validation)
if (value < 0 || value > 127) { // Assuming valid data is within 0–127
EEPROM.write(i, 0); // Reset the value to 0
Serial.println("Writing to EEPROM address " + String(i) + " as Zero");
} else {
Serial.println("EEPROM address " + String(i) + " contains valid value: " + String(value));
}
}
hour = EEPROM.read(0);
minutes = EEPROM.read(5);
Serial.println("Set Time is " + String(hour) + " in Hour " + String(minutes) + " in minutes");
pinMode(COIN_AC, INPUT_PULLUP);
pinMode(SET_TIME_TYPE, INPUT_PULLUP);
pinMode(UP_BTN, INPUT_PULLUP);
pinMode(DOWN_BTN, INPUT_PULLUP);
pinMode(SET_TIME, INPUT_PULLUP);
pinMode(RELAY_1, OUTPUT);
attachInterrupt(digitalPinToInterrupt(COIN_AC), coin_inserted_isr, FALLING); // interupt function for coin acceptor
// delay(3000);
// lcd.clear();
// lcd.setCursor(0, );
// lcd.print("TIME: " + formatTime(hour, minutes, 0));
// lcd.setCursor(0, 1);
// lcd.print("MAK TIMER");
}
void loop() {
if(hour == 0 && minutes == 0){
lcd_line_2 = "PLEASE SET TIME";
lcd.setCursor(0, 2);
lcd.print(lcd_line_2);
}else if(lcd_line_2.indexOf("PLEASE SET TIME")){
clearLine(2);
lcd_line_2 = "";
}
if (debounce(SET_TIME)) {
set_active = !set_active;
if (set_active) {
lcd.clear();
lcd.print("Settings Active");
delay(1500);
lcd.clear();
updateDisplay();
} else {
Serial.println("Settings Saved");
lcd.clear();
lcd.print("Settings Saved");
delay(1500);
lcd.setCursor(0, 0);
lcd_line_0 = "WATER VENDO MACHINE";
lcd.print(lcd_line_0);
// updateDisplay();
}
}
if (set_active) {
handleSettings();
} else {
runCountdown();
}
}
void handleSettings() {
if (debounce(SET_TIME_TYPE)) {
set_min = !set_min;
clearLine(1);
clearLine(2);
lcd.setCursor(0, 1);
lcd.print(set_min ? "Set: Minutes" : "Set: Hours");
Serial.println(set_min ? "Setting Minutes" : "Setting Hours");
delay(1000);
updateDisplay();
}
if (debounce(UP_BTN)) {
if (set_min) {
minutes = (minutes + 1) % 60;
} else {
hour = (hour + 1) % 24;
}
updateDisplay();
}
if (debounce(DOWN_BTN)) {
if (set_min) {
minutes = (minutes > 0) ? (minutes - 1) : 59;
} else {
hour = (hour > 0) ? (hour - 1) : 23;
}
updateDisplay();
}
}
void runCountdown() {
if (!countdownActive) {
lcd.setCursor(0, 1);
lcd_line_1 = "PLEASE INSERT COIN";
lcd.print(lcd_line_1 );
digitalWrite(RELAY_1, LOW); // Turn off relay
return; // No countdown to run
}
if (lcd_line_1.indexOf("PLEASE") != -1) {
clearLine(1);
lcd_line_1 = "";
}
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= 1000) { // Update every second
previousMillis = currentMillis;
if (countdownDuration >= 1000) {
countdownDuration -= 1000;
int remainingHours = countdownDuration / 3600000UL;
int remainingMinutes = (countdownDuration % 3600000UL) / 60000UL;
int remainingSeconds = (countdownDuration % 60000UL) / 1000;
lcd.setCursor(0, 1);
lcd.print("TIME: " + formatTime(remainingHours, remainingMinutes, remainingSeconds));
Serial.println("Remaining Time: " + formatTime(remainingHours, remainingMinutes, remainingSeconds));
digitalWrite(RELAY_1, HIGH); // Turn on relay
} else {
countdownActive = false;
digitalWrite(RELAY_1, LOW); // Turn off relay
lcd.setCursor(0, 1);
lcd_line_1 = "PLEASE INSERT COIN";
lcd.print(lcd_line_1);
Serial.println("Countdown Finished");
}
}
}
void coin_inserted_isr() {
Serial.println("Coin inserted");
unsigned long additionalTime = (hour * 3600000UL) + (minutes * 60000UL);
countdownDuration += additionalTime;
if (!countdownActive) {
countdownActive = true;
// digitalWrite(RELAY_1, HIGH); // Start relay
previousMillis = millis();
}
}
bool debounce(int pin) {
bool reading = !digitalRead(pin);
if (reading) {
if (millis() - lastDebounceTime > debounceDelay) {
lastDebounceTime = millis();
return true;
}
}
return false;
}
void updateDisplay() {
lcd.setCursor(0, 0);
lcd.print("TIME: " + formatTime(hour, minutes, 0));
EEPROM.write(0, hour);
EEPROM.write(5, minutes);
}
String formatTime(int h, int m, int s) {
String timeStr = "";
if (h < 10) timeStr += "0";
timeStr += String(h) + ":";
if (m < 10) timeStr += "0";
timeStr += String(m) + ":";
if (s < 10) timeStr += "0";
timeStr += String(s);
return timeStr;
}
void clearLine(int y) {
// Clear LCD line start at 0
String line_space = "";
for (int i = 0; i < 20 ; i ++) { // Adjust '20' to match the width of your LCD
line_space += " ";
}
lcd.setCursor(0, y); // Move cursor to the specified position
lcd.print(line_space); // Print spaces to clear the line
Serial.println("Clear line " + String(y)); // Log the action
}