#include <Keypad.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
const int buzzerPin = 13;
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] = {19, 18, 5, 17};
byte colPins[COLS] = {16, 4, 2, 15};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
enum Mode {
MODE_IDLE, MODE_WAIT_ACTION, MODE_SET_ID, MODE_SET_INTERVAL, MODE_DELETE, MODE_RUNNING
};
Mode mode = MODE_IDLE;
bool systemRunning = false;
bool allowInput = false;
struct Alarm {
int interval;
unsigned long lastTrigger;
bool active;
bool snoozing;
unsigned long snoozeStart;
};
const int MAX_ALARMS = 100;
Alarm alarms[MAX_ALARMS];
int currentID = -1;
String tempInput = "";
unsigned long snoozeTime = 5000;
unsigned long alertDuration = 3000;
bool alertActive = false;
int currentAlertID = -1;
unsigned long alertStart = 0;
int displayIndex = 0;
bool showingList = false;
unsigned long listShowTime = 0;
const unsigned long listTimeout = 4000; // زمان نمایش هر آلارم (۴ ثانیه)
void displayNextAlarm(); // <- اعلام تابع
void setup() {
lcd.init();
lcd.backlight();
pinMode(buzzerPin, OUTPUT);
lcd.setCursor(0, 0);
lcd.print("Press * to Start");
}
void loop() {
char key = keypad.getKey();
if (key) {
// اگه لیست در حال نمایشه، فقط کلیدهای * و # مجاز باشند
if (showingList) {
if (key == '*') {
displayNextAlarm();
} else if (key == '#') {
showingList = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("A:Add D:Delete");
lcd.setCursor(0, 1);
lcd.print("0000:Show Alarms");
}
return;
}
handleKey(key);
}
if (systemRunning && !alertActive) {
for (int i = 0; i < MAX_ALARMS; i++) {
if (alarms[i].active && !alarms[i].snoozing) {
if (millis() - alarms[i].lastTrigger >= alarms[i].interval) {
alertActive = true;
currentAlertID = i;
alertStart = millis();
tone(buzzerPin, 1000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Alarm ID:");
lcd.print(i);
break;
}
}
}
}
if (alertActive && millis() - alertStart >= alertDuration) {
noTone(buzzerPin);
alertActive = false;
if (currentAlertID != -1) {
alarms[currentAlertID].snoozing = true;
alarms[currentAlertID].snoozeStart = millis();
currentAlertID = -1;
}
}
for (int i = 0; i < MAX_ALARMS; i++) {
if (alarms[i].snoozing && millis() - alarms[i].snoozeStart >= snoozeTime) {
alarms[i].snoozing = false;
}
}
}
void handleKey(char key) {
if (key != '*' && (
(systemRunning && !allowInput && key != 'B' && key != 'C') ||
(!systemRunning && !allowInput)
)) return;
if (key == '*') {
if (allowInput && tempInput == "0000") {
tempInput = "";
showingList = true;
displayIndex = 0;
displayNextAlarm();
return;
}
if (!allowInput) {
allowInput = true;
systemRunning = false;
mode = MODE_WAIT_ACTION;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("A:Add D:Delete");
lcd.setCursor(0, 1);
lcd.print("0000:Show Alarms");
return;
}
else if (allowInput) {
if (mode == MODE_SET_ID && tempInput != "") {
currentID = tempInput.toInt();
tempInput = "";
if (currentID < 0 || currentID >= MAX_ALARMS) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Invalid ID!");
lcd.setCursor(0, 1);
lcd.print("Max ID: ");
lcd.print(MAX_ALARMS - 1);
delay(2000);
lcd.clear();
lcd.print("Add ID:");
return;
}
mode = MODE_SET_INTERVAL;
lcd.clear();
lcd.print("Time (sec):");
return;
}
else if (mode == MODE_SET_INTERVAL && currentID >= 0 && tempInput != "") {
int interval = tempInput.toInt();
if (interval > 0 && currentID < MAX_ALARMS) {
alarms[currentID].interval = interval * 1000;
alarms[currentID].active = true;
alarms[currentID].snoozing = false;
}
tempInput = "";
mode = MODE_WAIT_ACTION;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Alarm Saved!");
lcd.setCursor(0, 1);
lcd.print("0000:Show Alarms");
return;
} else if (mode == MODE_DELETE && tempInput != "") {
int idToDelete = tempInput.toInt();
if (idToDelete >= 0 && idToDelete < MAX_ALARMS) {
alarms[idToDelete].active = false;
alarms[idToDelete].snoozing = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Deleted ID: ");
lcd.print(idToDelete);
lcd.setCursor(0, 1);
lcd.print("0000:Show Alarms");
}
tempInput = "";
mode = MODE_WAIT_ACTION;
return;
}
}
}
if (mode == MODE_WAIT_ACTION && key != 'A' && key != 'D' && key != '#' && key != '0') return;
if ((mode == MODE_SET_ID || mode == MODE_SET_INTERVAL || mode == MODE_DELETE) &&
!(isDigit(key) || key == '*')) return;
if (key == '#') {
systemRunning = true;
allowInput = false;
mode = MODE_RUNNING;
lcd.clear();
lcd.print("System Running");
unsigned long now = millis();
for (int i = 0; i < MAX_ALARMS; i++) {
if (alarms[i].active && alarms[i].lastTrigger == 0) {
alarms[i].lastTrigger = now;
}
}
return;
}
if (key == 'A' && mode == MODE_WAIT_ACTION) {
mode = MODE_SET_ID;
tempInput = "";
lcd.clear();
lcd.print("Add ID:");
return;
}
if (key == 'D' && mode == MODE_WAIT_ACTION) {
mode = MODE_DELETE;
tempInput = "";
lcd.clear();
lcd.print("Del ID:");
return;
}
if (key == 'B') {
if (alertActive && currentAlertID != -1) {
noTone(buzzerPin);
alertActive = false;
alarms[currentAlertID].snoozing = true;
alarms[currentAlertID].snoozeStart = millis();
currentAlertID = -1;
}
return;
}
if (key == 'C') {
if (alertActive && currentAlertID != -1) {
noTone(buzzerPin);
alertActive = false;
alarms[currentAlertID].lastTrigger = millis();
alarms[currentAlertID].snoozing = false;
currentAlertID = -1;
}
return;
}
if (isDigit(key) && (
mode == MODE_SET_ID || mode == MODE_SET_INTERVAL || mode == MODE_DELETE || mode == MODE_WAIT_ACTION
)) {
if (tempInput == "") {
lcd.clear(); // فقط یک بار در اولین ورودی، صفحه پاک میشه
}
tempInput += key;
lcd.setCursor(0, 1);
lcd.print(tempInput);
}
if (showingList && key == '*') {
displayNextAlarm();
return;
}
}
void displayNextAlarm() {
bool found = false;
for (int i = displayIndex; i < MAX_ALARMS; i++) {
if (alarms[i].active) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("ID: ");
lcd.print(i);
lcd.setCursor(0, 1);
lcd.print("Time: ");
lcd.print(alarms[i].interval / 1000);
lcd.print(" sec");
displayIndex = i + 1;
listShowTime = millis();
found = true;
break;
}
}
if (!found) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("End of List");
lcd.setCursor(0, 1);
lcd.print("Press # to exit");
showingList = true; // هنوز در حالت لیست هستیم تا کاربر # بزنه
displayIndex = 0;
}
}