Arduino Safe

Hello everyone,

I decided to show off this project since it is my biggest one yet. With 6 buttons, this project allows you to type in a 6 digit password with 4 characters(1, 2, 3, 4). There is an ‘enter’ button, as well as a ‘clear/lock’ button. When the correct password is entered, a Servo motor turns, allowing the safe to open. For demo purposes, I mounted everything to a shoebox with screws, and strong adhesive for the breadboard. Now this project doesn’t even compare to what this community creates, but I am only 13 and I was incredibly surprised with myself for completing this.

Using some components from SparkFun and Xbee, as well as the XCode software, I think I will try to make an app on my iPhone that allows me to submit a password from there. On top of that, using a photo resistor, I will attempt to make an auto-locking mechanism when the door is closed.

Here is an instructables link - http://www.instructables.com/id/Electronic-Safe-With-Arduino/
Project Hub link - Electronic Safe with Arduino - Arduino Project Hub
Quick YouTube Demo - Electronic Safe using Arduino Uno - YouTube

Thank you for checking this thread out! Any feedback or criticism is appreciated!(i can take it :stuck_out_tongue: )

#include <Liquid.Crystal.h>
#include <EEPROM.h>
#include <Servo.h>

int address = 0;
static unsigned long SaveTimer;                
static unsigned long SaveDelay = (30 * 1000); 

char CODE[10] = "123142E";  //change password here   
char Str[10]; 
char CodeLength = 6;
int Pos = 0;

bool Unlocked;
static unsigned long DisplayTimer; 
static unsigned long DisplayDelay = 200;

LiquidCrystal lcd(12, 11, 9, 8, 7, 6); 

int buttonPin1 = 2;   
int buttonPin2 = 3;
int buttonPin3 = 4;
int buttonPin4 = 5;
int enterbutton = 10; 
int clearlockbutton = 13;

Servo myServo;                    

void setup() {

  myServo.attach(A1);  

  Lock();

  int EEPROMCodeOK = true;

  for (Pos = 0; Pos <= (CodeLength); Pos++) {

    Str[Pos] =  EEPROM.read(Pos);

    if (!(strrchr("1123456789", Str[Pos]))) { 

      EEPROMCodeOK = false;

    }

  }

  Pos++;
  Str[Pos] =  EEPROM.read(Pos); 

  if (Str[CodeLength + 1] != 'E') EEPROMCodeOK = false; 

  if (EEPROMCodeOK) {

    Str[CodeLength + 2] = '\0';
    strncpy(CODE, Str, CodeLength + 1);

  }

  ClearCode();

  pinMode(buttonPin1, INPUT_PULLUP);
  pinMode(buttonPin2, INPUT_PULLUP);
  pinMode(buttonPin3, INPUT_PULLUP);
  pinMode(buttonPin4, INPUT_PULLUP);
  pinMode(enterbutton, INPUT_PULLUP);
  pinMode(clearlockbutton, INPUT_PULLUP);

  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Hello.");
  delay(2000);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Password:");
  DisplayTimer = millis() + 200;

}

void loop() {

  Lock();

  Pos = constrain(Pos, 0, CodeLength);

  int buttonState1 = digitalRead(buttonPin1);  
  int buttonState2 = digitalRead(buttonPin2);
  int buttonState3 = digitalRead(buttonPin3);
  int buttonState4 = digitalRead(buttonPin4);

  int clButtonState = digitalRead(clearlockbutton);
  int enterButtonState = digitalRead(enterbutton);

  lcd.setCursor(9, 0);

  if (buttonState1 == LOW) {

    Str[Pos] = '1';

    Pos++;
    Str[Pos] = '\0';
    delay(250); 

    while (digitalRead(buttonPin1) == LOW); 

  }

  else if (buttonState2 == LOW) {

    Str[Pos] = '2';

    Pos++;
    Str[Pos] = '\0';
    delay(250); 

    while (digitalRead(buttonPin2) == LOW);

  }

  else if (buttonState3 == LOW) {

    Str[Pos] = '3';

    Pos++;
    Str[Pos] = '\0';
    delay(250); 
    while (digitalRead(buttonPin3) == LOW);

  }

  else if (buttonState4 == LOW) {

    Str[Pos] = '4';
    Pos++;
    Str[Pos] = '\0';
    delay(250); 

    while (digitalRead(buttonPin4) == LOW); 

  }

  else if (enterButtonState == LOW) {

    Str[Pos] = 'E';
    Pos++;

    Str[Pos] = '\0';
    delay(250);
    lcd.setCursor(15, 0);
    lcd.print("E");
    delay(400);
    lcd.setCursor(15, 0);
    lcd.print(" ");

    while (digitalRead(buttonPin1) == LOW); 

     if (strcmp (Str,CODE) == 0) {

      Unlocked = true;
      lcd.setCursor(0, 0);
      lcd.print(" Access Granted");
      delay(2000);

      lcd.clear();
      lcd.print("    Unlocked");

    } 

    else { 

      lcd.clear();
      lcd.print(" Access Denied.");
      delay(2000);
      lcd.clear();
      lcd.print("Password:");

    }

    while (Unlocked) {

      Unlock();

      if (digitalRead(clearlockbutton) == LOW) {

        delay(200);
        lcd.clear();
        lcd.print("     Locked");
        delay(2000);
        lcd.clear();
        Unlocked = false;
        SaveTimer = millis() + 30000;

      }

    }

    ClearCode();

  }

  else if (clButtonState == LOW) {

    delay(500);

    while (clearlockbutton == LOW);

    if ((millis() - SaveTimer) > 4500) {

    }

    ClearCode();

  }

  if ( (long)( millis() - DisplayTimer ) >= 0) {

    DisplayTimer += DisplayDelay;

    lcd.setCursor(9, 0); 
    lcd.print(Str);
    lcd.setCursor(15, 0);
    lcd.print(" ");

    if (clButtonState == LOW) {

      lcd.clear();
      lcd.print("Password:");

    }

  }

}

void ClearCode() {

  Pos = 0;
  Str[Pos] = '\0';

  lcd.setCursor(0, 0);
  lcd.print("Password:");
  lcd.setCursor(0, 1);
  lcd.print("          ");

}

void Unlock() {

  myServo.write(117);

}

void Lock() {

  myServo.write(26);

}

Update: Thanks to the Blynk app I can enter a password from my phone. :slight_smile: Video coming soon.

A minor point:

static unsigned long SaveDelay = (30 * 1000);

In this case, the result of the multiplication will work out but if it had been

static unsigned long SaveDelay = (40 * 1000);

you would get a mysterious problem with the delay.

Just to make sure that the multiplication is done as unsigned long instead of int, do this:

static unsigned long SaveDelay = (30 * 1000UL);

And could you single space your code?

Pete

el_supremo:
A minor point:

static unsigned long SaveDelay = (30 * 1000);

In this case, the result of the multiplication will work out but if it had been

static unsigned long SaveDelay = (40 * 1000);

you would get a mysterious problem with the delay.

Just to make sure that the multiplication is done as unsigned long instead of int, do this:

static unsigned long SaveDelay = (30 * 1000UL);

And could you single space your code?

Pete

Thanks for the tip. And I honestly have no clue why it's double spaced, I'll edit the OP.

I'll edit the OP.

Thanks

Pete

It seems to me that all you've done is copy the code from the instructable (which would explain why your original post had double-spaced code) - in which case I don't think you should have posted this in Exhibition/Gallery since it isn't your work.
Anyway, I don't think that code can work, which is not too surprising with an instructable. For sure the very first line will fail - there is no Liquid.Crystal.h, it should be LiquidCrystal.h
But the way it processes the password looks wrong. For example, this

    if (!(strrchr("1123456789", Str[Pos]))) {

will fail if the password has a zero in it.
I'm not going to spend any more time debugging an instructable.

Pete

el_supremo:
It seems to me that all you've done is copy the code from the instructable (which would explain why your original post had double-spaced code) - in which case I don't think you should have posted this in Exhibition/Gallery since it isn't your work.

I made that project, and the Instructable page is mine...

el_supremo:
Anyway, I don't think that code can work, which is not too surprising with an instructable.

What's that supposed to mean?

el_supremo:
For sure the very first line will fail - there is no Liquid.Crystal.h, it should be LiquidCrystal.h

Thanks for pointing that out. May I say it's the only meaningful part of your whole post.

el_supremo:
But the way it processes the password looks wrong. For example, this

    if (!(strrchr("1123456789", Str[Pos]))) {

will fail if the password has a zero in it.

chummer1010:
this project allows you to type in a 6 digit password with 4 characters(1, 2, 3, 4)

Did you even read this post at all?

el_supremo:
I'm not going to spend any more time debugging an instructable.

Pete

I'm not going to spend any more time responding to your worthless post anymore, pete.

Marco

just kidding -

since you like jumping to conclusions so much! :slight_smile:

ahhh. I see what's happening now. My (very) bad!

 Pos = constrain(Pos, 0, CodeLength);

Using this to prevent the user running off the end of the input array is not the best way to handle things. If they enter more numbers than permitted, give an error message and start the process all over again. Something like this:

 if(Pos > CodeLength+1) {
    // Print Error message on LCD and then
    ClearCode();
  }

a 6 digit password with 4 characters(1, 2, 3, 4)

OK. So why do you test the EEPROM password with

if (!(strrchr("1123456789", Str[Pos]))) {

Why isn't it "1234"?
Have you used the EEPROM to store a password?

Pete
I'll hang onto the trampoline. I'll probably need it in the future.

P.S. Using pin 13 for clearlockbutton doesn't work on my NANO. The pin always reads as LOW.

Pete

el_supremo:
ahhh. I see what's happening now. My (very) bad!

 Pos = constrain(Pos, 0, CodeLength);

Using this to prevent the user running off the end of the input array is not the best way to handle things. If they enter more numbers than permitted, give an error message and start the process all over again. Something like this:

 if(Pos > CodeLength+1) {

// Print Error message on LCD and then
    ClearCode();
  }

That makes more sense. Thanks.

el_supremo:
OK. So why do you test the EEPROM password with

if (!(strrchr("1123456789", Str[Pos]))) {

Why isn't it "1234"?
Have you used the EEPROM to store a password?

I don't fully understand how EEPROM works. Plus at the time I think I was going to have more character buttons, but then I realized I didn't have enough pins.

el_supremo:
P.S. Using pin 13 for clearlockbutton doesn't work on my NANO. The pin always reads as LOW.

Pete

That's strange. Try switching the Pins around from the LCD screen or something (and change your code if needed obviously. I don't know why that happened however, because I used an Uno.

I don't fully understand how EEPROM works.

Why have the code there in the first place? Even if there's a password stored in EEPROM, your code is not going to recognize it.

Try switching the Pins around from the LCD screen

I haven't got an LCD attached to the NANO so I modified your code to use the Serial monitor.
I changed the pins to use enterbutton=8 and clearlockbutton=10.

I was also using a wire instead of buttons. Occasionally I had problems with it reading a digit twice. The reason is that although your code debounces the pin when it changes from HIGH to LOW, you don't debounce it when it goes from LOW to HIGH. This problem could occur with buttons as well.

Hmmm. I said I wasn't going to spend any more time debugging an instructable but I just did precisely that. Oh well.

Pete

el_supremo:
Hmmm. I said I wasn't going to spend any more time debugging an instructable but I just did precisely that. Oh well.

Pete

Still don't believe it's mine?

Just because I posted it on Instructables means it's not worth anyone's time? Would it suddenly be 'ok' to debug if I didn't post it on there?

I fail to see your logic, but either way it's quite discouraging for me to make more Instructables, share ideas on this forum, or use Arduino at all, because apparently all I do is steal crappy projects from websites and say they're mine.

Still don't believe it's mine?

That's not what I meant. I was just pointing out that I was doing what I said I wasn't going to do. I'm a man of contradictions.

Pete

el_supremo:
That's not what I meant. I was just pointing out that I was doing what I said I wasn't going to do. I'm a man of contradictions.

Pete

I still don't get what me making an Instructable out of it has anything to do with it's self worth...

Some posters here don't like instructables at all. Use the forum search for "Instructables" to get a sample.
Yours does at least work but it still has oddities. Why have EEPROM code at all - especially when you can't have tested it?

Pete

el_supremo:
Some posters here don't like instructables at all. Use the forum search for "Instructables" to get a sample.
Yours does at least work but it still has oddities. Why have EEPROM code at all - especially when you can't have tested it?

Pete

What would be an alternate for EEPROM? When I was doing research for this project, that's what I thought would be needed.

I am not saying that using EEPROM is wrong. EEPROM is certainly the way to permanently store a password in the Arduino so that it doesn’t have to have the software reloaded after it has been powered off.
My point is, why is that code in there? You’ve said you “don’t fully understand how EEPROM works” in which case why include that part when you distribute/publish the code? Take it out until you do understand it and have fully tested it.

Pete

el_supremo:
I am not saying that using EEPROM is wrong. EEPROM is certainly the way to permanently store a password in the Arduino so that it doesn't have to have the software reloaded after it has been powered off.
My point is, why is that code in there? You've said you "don't fully understand how EEPROM works" in which case why include that part when you distribute/publish the code? Take it out until you do understand it and have fully tested it.

Pete

Could you explain further on how to make the correct fix? Rather than just telling me it's wrong?

Edit: I'm sorry for being so blunt. Whether I'm showing it or not, I really do appreciate your help right now. Thanks,

marco