//hari final DEC 2023 (modified for lockout + master unlock)
#include <Wire.h>
#include <Keypad.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#include <RTClib.h>
long offAt = 0;
long offAt1 = 0;
Servo ServoMotor;
# define Lock 4 // relay1
# define Lock2 A0 // relay2
# define GSMPower 3 // relay
# define ServoPower A1
# define Feedback A2
# define buzzer 13
const byte numRows = 4; //number of rows on the keypad
const byte numCols = 4; //number of columns on the keypad
RTC_DS3231 rtc;
int position = 0;
int pos = 0;
int posa = 0;
byte Lockicon1[8] = {
B01110,
B10001,
B10000,
B10000,
B11111,
B11111,
B11111,
B11111,
};
byte Lockicon2[8] = {
B01110,
B10001,
B10001,
B11111,
B11111,
B11111,
B11111,
B00000,
};
byte Standby1[8] = {
B01110,
B10001,
B10000,
B01110,
B00001,
B10001,
B01110,
B00000,
};
char keymap[numRows][numCols] = {
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', 'C' },
{ '*', '0', '#', 'D' }
};
char keypressed;
char keypressed1;
char code[] = { '1', '1', '1', '1' }; // user code
char code2[] = { '1', '1', '1', '1' }; // box code
char check1[sizeof(code)];
char check2[sizeof(code)];
char check3[sizeof(code2)];
short a = 0, i = 0, s = 0, j = 0;
short la = 0, ki = 0, mj = 0;
byte rowPins[numRows] = { 12, 11, 10, 9 };
byte colPins[numCols] = { 8, 7, 6, 5 };
Keypad myKeypad = Keypad(makeKeymap(keymap), rowPins, colPins, numRows, numCols);
LiquidCrystal_I2C lcd(0x27, 16, 2);
//RTC_DS3231 rtc;
int wrongAttempts = 0; // counts wrong password submissions
const int MAX_WRONG = 3; // threshold to lock system
const char MASTER_CODE[] = { '9','9','9','9' }; // master unlock code (change if needed)
bool systemLocked = false; // true when locked after MAX_WRONG wrong attempts
void setup() {
pos = 0;
posa = 0;
position = 0;
Serial.begin(115200);
rtc.begin();
lcd.init();
lcd.backlight();
ServoMotor.attach(A3);
lcd.print(" Bike Security");
lcd.setCursor(0, 1);
lcd.print(" Password System");
pinMode(Lock, OUTPUT);
pinMode(Lock2, OUTPUT);
pinMode(GSMPower, OUTPUT);
pinMode(ServoPower, OUTPUT);
pinMode(Feedback, OUTPUT);
pinMode(buzzer, OUTPUT);
digitalWrite(GSMPower, HIGH);
digitalWrite(Feedback, HIGH);
if ((digitalRead(Lock) == LOW) && (posa == 0))
{
offAt1 = millis() + 10000;
}
lcd.clear();
}
void loop() {
updateLCD();
if (Serial.available()) {
char input = Serial.read();
if (input == 'u') updateRTC();
}
// show lock icon
if (digitalRead(Lock) == HIGH)
{
lcd.createChar(0, Lockicon1);
lcd.setCursor(14, 1);
lcd.write(0);
}
else
{
lcd.createChar(0, Lockicon2);
lcd.setCursor(14, 1);
lcd.write(0);
}
digitalWrite(ServoPower, LOW);
ServoMotor.write(0);
// If system is locked, ignore normal operations except attempt to enter master code
if (systemLocked) {
// show locked message and prompt for master
lcd.clear();
lcd.setCursor(0,0);
lcd.print("SYSTEM LOCKED !!");
lcd.setCursor(0,1);
lcd.print("Enter MASTER *");
toneBeeperLocked(); // brief indication
// wait for master entry - this blocks until master is entered (by design)
bool unlocked = ReadAndCheckMaster();
if (unlocked) {
wrongAttempts = 0;
systemLocked = false;
lcd.clear();
lcd.print("MASTER ACCEPTED");
delay(1000);
lcd.clear();
} else {
// ReadAndCheckMaster only returns false if master wrong (but it loops until correct in our impl)
// For safety we keep systemLocked true.
lcd.clear();
}
return; // restart loop after unlocking attempt
}
keypressed = myKeypad.getKey(); //Constantly waiting for a key to be pressed
// OPEN IGNITION (A) path
if ((keypressed == 'A') && (digitalRead(Lock) == LOW))
{ // * to open the lock
beep();
delay(200);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" Enter Password "); //Message to show
ReadCode(); //Getting code function
if (a == sizeof(code)) { // success
OpenLOCK();
wrongAttempts = 0; // reset attempts on success
}
else { // wrong password
wrongAttempts++;
// feedback
lcd.clear();
lcd.print(" Wrong code");
lcd.setCursor(0, 1);
lcd.print(" pls try again..");
digitalWrite(buzzer, HIGH);
delay(1000);
digitalWrite(buzzer, LOW);
// check threshold
if (wrongAttempts >= MAX_WRONG) {
LockSystem();
}
}
lcd.clear();
}
// BOX OPENINGS & other keys follow original logic with added wrongAttempts increment for box code
keypressed1 = myKeypad.getKey();
if ((keypressed == 'B') && (digitalRead(Lock) == HIGH)) { //To change the code it calls the changecode function
beep();
OpenBox();
lcd.clear();
}
if ((keypressed == 'B') && (digitalRead(Lock) == LOW)) { // box code when ignition locked
beep();
lcd.backlight();
delay(200);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" Enter box code"); //Message to show
ReadCode1(); //Getting code function
if (la == sizeof(code2)) { // box open success
OpenBox();
wrongAttempts = 0;
} else {
lcd.clear();
lcd.print("Wrong Box code ");
lcd.setCursor(0, 1);
lcd.print(" Pls try agian..");
delay(800);
wrongAttempts++;
if (wrongAttempts >= MAX_WRONG) {
LockSystem();
}
}
lcd.clear();
}
if ((keypressed == 'C') && (digitalRead(Lock) == HIGH)) {
beep();
ChangeCode();
delay(100);
lcd.clear();
}
// rest of your existing logic, with some ref checks and no change in behavior:
if ((keypressed == '#') && (posa == 1)) {
beep();
delay(100);
beep();
delay(100);
beep();
delay(100);
beep();
delay(100);
beep();
delay(100);
beep();
delay(100);
lcd.backlight();
lcd.clear();
digitalWrite(Lock, LOW);
digitalWrite(ServoPower, LOW);
lcd.print(" Ignition Locked");
lcd.setCursor(0, 1);
lcd.print("Press A to begin..");
delay(1000);
lcd.clear();
posa = 0;
offAt1 = millis() + 10000;
}
if ((digitalRead(Lock) == LOW) && (posa == 0))
{
if (millis() >= offAt1) {
digitalWrite(Feedback, LOW);
}
}
if ((keypressed == '#') && (posa == 2))
{
beep();
posa = posa - 1;
digitalWrite(Lock, LOW);
}
if ((keypressed == '#') && (posa == 3))
{
beep();
posa = posa - 1;
}
if ((keypressed == '8') && (posa == 1))
{
beep();
posa = posa + 1;
lcd.setCursor(13, 1);
lcd.clear();
}
if ((keypressed == '9') && (posa == 2))
{
beep();
digitalWrite(Lock, HIGH);
digitalWrite(Feedback, HIGH);
posa = posa + 1;
lcd.backlight();
}
if ((posa == 1) && (digitalRead(Lock) == LOW))
{
lcd.createChar(1, Standby1);
lcd.setCursor(13, 1);
lcd.write(1);
lcd.noBacklight();
}
if ((keypressed == '#') && (posa == 0))
{
lcd.init();
delay(100);
}
if ((keypressed == 'D') && (digitalRead(Lock) == LOW))
{
delay(100);
digitalWrite(Feedback, HIGH);
offAt1 = millis() + 25000;
}
if ((keypressed == 'D') && (digitalRead(Lock) == HIGH))
{
lcd.init();
digitalWrite(Lock2, LOW);
}
if (digitalRead(ServoPower) == LOW)
{
if (millis() >= offAt) {
digitalWrite(Lock2, LOW);
}
}
}
// ----- existing functions (ReadCode, ReadCode1, etc.) with no change except minor resets -----
void ReadCode() { //Getting code sequence
i = 0;
a = 0;
j = 0;
keypressed = NO_KEY;
while (keypressed != '*') {
keypressed = myKeypad.getKey();
if (keypressed != NO_KEY && keypressed != '*') {
lcd.setCursor(j, 1);
lcd.print("*");
j++;
beep();
if (keypressed == code[i] && i < sizeof(code)) {
a++;
i++;
}
else
a--;
}
}
keypressed = NO_KEY;
}
void ReadCode1() { //Getting box code sequence
ki = 0;
la = 0;
mj = 0;
keypressed1 = NO_KEY;
while (keypressed1 != '*') {
keypressed1 = myKeypad.getKey();
if (keypressed1 != NO_KEY && keypressed1 != '*') {
lcd.setCursor(mj, 1);
lcd.print("*");
mj++;
beep();
if (keypressed1 == code2[ki] && ki < sizeof(code2)) {
la++;
ki++;
} else
la--;
}
}
keypressed1 = NO_KEY;
}
void ChangeCode() { //Change code sequence
lcd.clear();
delay(1000);
lcd.print(" Changing code");
delay(1000);
lcd.clear();
lcd.print("Enter old code");
ReadCode(); //verify the old code first so you can change it
if (a == sizeof(code)) {
lcd.clear();
lcd.print("Changing code");
GetNewCode1(); //Get the new code
GetNewCode2(); //Get the new code again to confirm it
s = 0;
for (i = 0; i < sizeof(code); i++) {
if (check1[i] == check2[i])
s++;
}
if (s == sizeof(code)) {
for (i = 0; i < sizeof(code); i++) {
code[i] = check2[i];
EEPROM.put(i, code[i]);
}
lcd.clear();
lcd.print("Code Changed");
delay(1000);
delay(500);
}
else
{
lcd.clear();
lcd.print("Codes are not");
lcd.setCursor(0, 1);
lcd.print("matching !!");
delay(500);
}
}
else
{
lcd.clear();
lcd.print("Enter Wrong Code");
lcd.setCursor(0, 1);
lcd.print("Pls try again.. !!");
digitalWrite(buzzer, HIGH);
delay(1000);
digitalWrite(buzzer, LOW);
}
}
void GetNewCode1() {
i = 0;
j = 0;
lcd.clear();
lcd.print("Enter new code");
lcd.setCursor(0, 1);
lcd.print("and press A");
delay(100);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Enter new code");
keypressed = NO_KEY;
while (keypressed != '*') {
keypressed = myKeypad.getKey();
if (keypressed != NO_KEY && keypressed != '*') {
lcd.setCursor(j, 1);
lcd.print("*");
check1[i] = keypressed;
i++;
j++;
beep();
}
}
keypressed = NO_KEY;
}
void GetNewCode2() {
i = 0;
j = 0;
lcd.clear();
lcd.print("Confirm code");
lcd.setCursor(0, 1);
lcd.print("and press A");
delay(100);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Confirm code");
keypressed = NO_KEY;
while (keypressed != '*') {
keypressed = myKeypad.getKey();
if (keypressed != NO_KEY && keypressed != '*') {
lcd.setCursor(j, 1);
lcd.print("*");
check2[i] = keypressed;
i++;
j++;
beep();
}
}
keypressed = NO_KEY;
}
void OpenLOCK() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(".....WELCOME.....");
lcd.setCursor(0, 1);
lcd.print("Ignition Active");
digitalWrite(Lock, HIGH);
digitalWrite(GSMPower, HIGH);
digitalWrite(Feedback, HIGH);
digitalWrite(buzzer, HIGH);
delay(400);
digitalWrite(buzzer, LOW);
digitalWrite(ServoPower, LOW);
posa = 3;
delay(500);
}
void OpenBox() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" BOX IS OPENING");
digitalWrite(ServoPower, HIGH);
lcd.setCursor(0, 1);
lcd.print("Prs Seat to LOCK");
delay(400);
beep();
for (pos = 0; pos <= 60; pos += 1) {
ServoMotor.write(pos);
delay(5);
}
for (pos = 60; pos >= 0; pos -= 1) {
ServoMotor.write(pos);
delay(5);
}
digitalWrite(Lock2, HIGH);
offAt = millis() + 20000;
delay(1000);
beep();
delay(100);
beep();
delay(100);
beep();
digitalWrite(buzzer, HIGH);
delay(100);
digitalWrite(buzzer, LOW);
lcd.clear();
digitalWrite(ServoPower, LOW);
}
void beep() {
digitalWrite(buzzer, HIGH);
delay(20);
digitalWrite(buzzer, LOW);
}
void toneBeeperLocked() {
// small buzzer pattern to indicate lock state
for (int k=0; k<2; k++) {
digitalWrite(buzzer, HIGH);
delay(80);
digitalWrite(buzzer, LOW);
delay(80);
}
}
// ----- LOCK & MASTER handling -----
void LockSystem() {
systemLocked = true;
digitalWrite(buzzer, HIGH);
delay(500);
digitalWrite(buzzer, LOW);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("TOO MANY ATTEMPTS");
lcd.setCursor(0,1);
lcd.print("System LOCKED!!");
// keep state locked until master entered (handled in loop)
}
bool ReadAndCheckMaster() {
// Prompt and read a master code from keypad, '*' to finish
char entered[sizeof(MASTER_CODE)];
int idx = 0;
lcd.setCursor(0,1);
lcd.print("Enter MASTER *");
keypressed = NO_KEY;
// read digits until '*' (terminator)
while (true) {
char k = myKeypad.getKey();
if (k != NO_KEY) {
if (k == '*') {
break;
}
// only accept digits or known keys
if (idx < (int)sizeof(entered)) {
entered[idx++] = k;
// feedback
lcd.setCursor(idx-1, 1);
lcd.print("*");
beep();
}
}
}
// If user entered fewer digits than master code, fail
if (idx != (int)sizeof(MASTER_CODE)) {
// optional: allow retry
lcd.clear();
lcd.print("Invalid Master");
delay(800);
return false;
}
// compare
for (int p=0; p< (int)sizeof(MASTER_CODE); p++) {
if (entered[p] != MASTER_CODE[p]) {
lcd.clear();
lcd.print("Master Wrong");
delay(800);
return false;
}
}
// correct
return true;
}
// ----- RTC and LCD functions (unchanged) -----
void updateRTC() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Edit Mode..");
const char txt[6][15] = { "year [4-digit]", "month [1~12]", "day [1~31]",
"hours [0~23]", "minutes [0~59]", "seconds [0~59]"
};
String str = "";
long newDate[6];
while (Serial.available()) {
Serial.read(); // clear serial buffer
}
for (int i = 0; i < 6; i++) {
Serial.print("Enter ");
Serial.print(txt[i]);
Serial.print(": ");
while (!Serial.available()) { ; }
str = Serial.readString();
newDate[i] = str.toInt();
Serial.println(newDate[i]);
}
rtc.adjust(DateTime(newDate[0], newDate[1], newDate[2], newDate[3], newDate[4], newDate[5]));
Serial.println("Updated!");
}
void updateLCD() {
const char dayInWords[7][4] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
const char monthInWords[13][4] = { " ", "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
"JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
};
DateTime rtcTime = rtc.now();
int ss = rtcTime.second();
int mm = rtcTime.minute();
int hh = rtcTime.twelveHour();
int DD = rtcTime.dayOfTheWeek();
int dd = rtcTime.day();
int MM = rtcTime.month();
int yyyy = rtcTime.year();
lcd.setCursor(0, 0);
if (dd < 10) lcd.print("0");
lcd.print(dd);
lcd.print("-");
lcd.print(monthInWords[MM]);
lcd.print("-");
lcd.print(yyyy);
lcd.print(" ");
lcd.print(dayInWords[DD]);
lcd.setCursor(0, 1);
if (hh < 10) lcd.print("0");
lcd.print(hh);
lcd.print(':');
if (mm < 10) lcd.print("0");
lcd.print(mm);
lcd.print(':');
if (ss < 10) lcd.print("0");
lcd.print(ss);
if (rtcTime.isPM()) lcd.print(" PM");
else lcd.print(" AM");
delay(100);
}