/*
Wokwi | questions
Countdown clock jumps from 24 to 4 hours
justaguy59301 — 10/4/24 at 8:39 PM
https://wokwi.com/projects/409868497466943489
I am working through this project, I know there are a ton of
different ways to do it, but this made sense for me as a beginner.
***Edited
pin numbers to match wiring
checkallonswitch() for analog
relay polarity so COM and NO close when active
***
Original issue (time > 10 hours) remains
*/
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <Wire.h>
// LCD setup
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Relay output pins
const byte r_outpin[8] = {4, 3, 2, A3, A2, A1, A0, 13};
// Reset switch pin
const int ALL_ON_PIN = A6;
//Delaytime for calibrating clock timing
const unsigned long delaytime = 1000;
// 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'}
};
byte rowPins[ROWS] = {12, 11, 10, 9};
byte colPins[COLS] = {8, 7, 6, 5};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
//Variables
int activezones;
int currentzone;
int rt[6];
int relayhours;
int relayminutes;
int relayseconds;
unsigned long currenthours;
unsigned long currentminutes;
unsigned long currentseconds;
unsigned long remainderseconds;
unsigned long totalseconds;
unsigned long currenttotalseconds;
int toggleswitch;
char startrun;
//Functions
void checkreset();
void setuphardware();
void initializeeeprom();
void readeeprom();
void getrelaytime();
void checkstartup();
void checkallonswitch();
void runsequence();
// initial power up
void setup() {
checkreset(); // checks for 'A' reset at startup
setuphardware(); // initilaize LCD, set all relay outputs High
initializeeeprom(); // check EEPROM for data if none found write all to 0
readeeprom(); // read relay time and active zones from eeprom
checkstartup(); // if relaytimes all == 0 then continue "else" loop()
getrelaytimes(); // get inputs for relay times 3 digits per relay time, writes times to eeprom
}
void loop() {
checkallonswitch(); // checks for all on switch low, if low all active relays are on
runsequence(); // runs through timing for active zones
}
void checkreset() {
delay(1000);
char key = keypad.getKey();
if (key == 'A') {
for (int i = 0; i < EEPROM.length(); i++) { // for all eeprom positions
EEPROM.write(i, 0);
}
}
}
void setuphardware() {
//set pin Rx as input for all active relays on sidequest
pinMode(1, INPUT_PULLUP);
//initialize LCD
lcd.init();
lcd.backlight();
//initialize relay outputs
for (int r = 0; r < 8; r++) {
pinMode(r_outpin[r], OUTPUT);
digitalWrite(r_outpin[r], !HIGH);
}
}
void initializeeeprom() {
if (EEPROM.read(0) == 255) {
for (int i = 0; i < EEPROM.length(); i++) {
EEPROM.write(i, 0);
}
}
}
void readeeprom() {
relayhours = EEPROM.read(0);
relayminutes = EEPROM.read(1);
relayseconds = EEPROM.read(2);
activezones = EEPROM.read(3);
}
void checkstartup() {
if (relayhours == 0 && relayminutes == 0 && relayseconds == 0) {
getzones();
} else {
loop();
}
}
void getzones() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Enter # of zones");
lcd.setCursor(0, 1);
lcd.print("1-8");
char key = keypad.waitForKey();
activezones = (key - '0');
if (activezones == 0 || activezones > 8) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("invalid choice");
delay(1000);
getzones();
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(activezones);
lcd.print(" Zones");
delay(1000);
EEPROM.write(3, activezones);
}
void getrelaytimes() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Enter Zone time");
lcd.setCursor(0, 1);
lcd.print("24:59:59 format");
char key = keypad.waitForKey();
rt[0] = (key - '0');
lcd.setCursor(0, 1);
lcd.print(rt[0]);
key = keypad.waitForKey();
rt[1] = (key - '0');
lcd.print(rt[1]);
key = keypad.waitForKey();
rt[2] = (key - '0');
lcd.setCursor(3, 1);
lcd.print(rt[2]);
key = keypad.waitForKey();
rt[3] = (key - '0');
lcd.print(rt[3]);
key = keypad.waitForKey();
rt[4] = (key - '0');
lcd.setCursor(6, 1);
lcd.print(rt[4]);
key = keypad.waitForKey();
rt[5] = (key - '0');
lcd.print(rt[5]);
relayhours = ((rt[0] * 10) + rt[1]);
relayminutes = ((rt[2] * 10) + rt[3]);
relayseconds = ((rt[4] * 10) + rt[5]);
if (relayhours > 24) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("invalid input");
delay(1000);
getrelaytimes();
}
if (relayminutes > 59) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("invalid input");
delay(1000);
getrelaytimes();
}
if (relayseconds > 59) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("invalid input");
delay(1000);
getrelaytimes();
}
EEPROM.write(0, relayhours);
EEPROM.write(1, relayminutes);
EEPROM.write(2, relayseconds);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("press * to begin");
key = keypad.waitForKey();
if (key = '*') {
loop();
}
}
// editied for analog input
void checkallonswitch() {
toggleswitch = analogRead(ALL_ON_PIN);
if (toggleswitch < 512) {
//if (toggleswitch == 0) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("all active zones");
lcd.setCursor(4, 1);
lcd.print("running");
for (int i = 0; i < activezones; i++) {
digitalWrite(r_outpin[i], !LOW);
}
if (toggleswitch < 512) {
//if (toggleswitch == 0) {
do {
toggleswitch = analogRead(ALL_ON_PIN);
//toggleswitch = digitalRead(1);
delay(100);
}
while (toggleswitch == 0);
}
for (int i = 0; i < activezones; i++) {
digitalWrite(r_outpin[i], LOW);
}
}
}
void runsequence() {
currentzone = 0;
do { // cycle through active zones
currenthours = relayhours;
currentminutes = relayminutes;
currentseconds = relayseconds;
totalseconds = (relayhours * 3600) + (relayminutes * 60) + relayseconds;
currenttotalseconds = totalseconds;
digitalWrite(r_outpin[currentzone], !LOW);
do { // countdown zone timer
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Zone = ");
lcd.setCursor(8, 0);
lcd.print(currentzone + 1);
lcd.setCursor(0, 1);
if (currenthours < 10) {
lcd.print("0");
}
lcd.print(currenthours);
lcd.print(":");
if (currentminutes < 10) {
lcd.print("0");
}
lcd.print(currentminutes);
lcd.print(":");
if (currentseconds < 10) {
lcd.print("0");
}
lcd.print(currentseconds);
currenttotalseconds = currenttotalseconds - 1;
currenthours = currenttotalseconds / 3600;
remainderseconds = currenttotalseconds % 3600;
currentminutes = remainderseconds / 60;
currentseconds = remainderseconds % 60;
delay(delaytime);
toggleswitch = analogRead(ALL_ON_PIN);
if (toggleswitch < 512) {
loop();
}
}
while (currenttotalseconds > 0);
digitalWrite(r_outpin[currentzone], !HIGH);
currentzone = currentzone + 1;
}
while (currentzone < activezones);
loop();
}