Button based security code

A project log for TrinketPro Movement Alarm for Bag Theft Prevention

A portable, battery powered device that sounds an alarm when your bag is moved. Once armed, can only be turned off by your secret code.

MakerSelfMakerSelf 12/16/2014 at 04:550 Comments

The last update was talking about the steps to build the circuit, and this is about using the circuit. I needed to program it so that when you pressed the arm button, it would turn on. A event (in the final product, movement) would trigger the alarm, and then the code would turn it off.

I built this up over the course of a few days, starting with a simple version using delays, and then building out the button based security code utilizing non-blocking code. I was very happy with the result, and stripped out some the unnecessary pieces for the power circuit component, and posted it to the forum (see the post) as a standalone button based security code sketch. Hoping to get some feedback, and also wanted to share in case someone wanted to do something similar.

I have posted the code as it stand so far (includes the power on, and the button based code) below, but also wanted to share a video of it operational so far:

The code (the comments make it a little difficult to follow, sorry!)

/* alarmbox.ino

 Implements a security code using buttons as the way to input the code.
 Number of buttons, the number of digits in the secret code, and the 
 numerical value of each button (for the code) can be defined independently.

 This code can be used to take any action when the secret code is entered
 correctly.  In this example, the on board LED is on while the secret code 
 has not been correctly entered, and then is turned off when the secret 
 code is entered correctly.

 The sketch also prints the code that has been entered so far to the serial
 monitor, along with if it has been matched (only when matched). 
 There is no need for resetting the code entered periodically as the code
 entered is simply made up of the last X number of digits that had been
 entered (X depends on the length of the secret code).  
 The circuit: 
 * If no LED on the board that is attached to pin 13, attach an LED from
 pin 13 to ground
 * For each button you choose to have for inputs into the entered code 
 (in this sketch there are four buttons, but you can change that):
  -- Use a normally open button (i.e. only on when you press it, then it pops up)
  -- Connect from one side of the button to ground through a resistor 
     (A decent size, in this example 1k resistors were used but you can use 10k 
     or similar larger value.)
  -- Connect from the other side of the button to a digital I/O pin on the
     arduino board. (in this sketch, button 1 was connected to pin 8,
     button 2 to pin 9, button 3 to pin 10, button 4 to pin 11, but you can
     change that as long as you change it in the sketch (noted where you do
 Created December 2014
 by MakerSelf (
 Please use, modify and be merry!



// --------CONSTANTS---------------
const int secretCodeLength = 7;
const int secretCode[secretCodeLength] = {1, 2, 3, 4, 3, 2, 1};
const int codeEnteredInitializedValue = 0;

const int numberOfButtons = 4;
const int buttonPins[numberOfButtons] = {8, 9, 10, 11};    //put your pins here
const int buttonValues[numberOfButtons] = {1, 2, 3, 4};    //put the values of the button you want to use here
const int buttonInterval = 300;                            //this is the sensitivity of the button (i.e. how quickly can you double press the button)
const byte buttonPressedState = LOW;
const byte buttonNotPressedState = HIGH;

const int OnOffPin = 7;
const int speakerPin = 6;

//------------ VARIABLES---------------------
int codeEntered[secretCodeLength];                       //this gets initilized
byte buttonStates[numberOfButtons];                      //this gets initilized
unsigned long previousButtonMillis[numberOfButtons];     //this gets initilized
byte speakerState;

unsigned long previousSerialMillis;                      //for debugging or printing to the serial if that is the objective.  Gets initialized to zero when begin Serial Communication.

// ==================================================================================

// --------MAIN PROGRAM---------------
void setup() {
  //turn the Circuit on via transistor
  pinMode(OnOffPin, OUTPUT);                                                                 // initialize digital OnOffPin as an output.
  digitalWrite(OnOffPin, HIGH);                                                              // turn the OnOffPin HIGH and thus the transistor gate open by making the voltage HIGH
  pinMode(13, OUTPUT);                                                                       // use digital pin 13 to show when the OnOffPin is high.  for debugging, to be removed in final version.
  digitalWrite(13, HIGH);                                                                    // use digital pin 13 to show when the OnOffPin is high.  for debugging, to be removed in final version.
  //intialize speaker
  pinMode(speakerPin, OUTPUT);
  speakerState = true; 
  //initialize codeEntered and Buttons
  initializeCodeEntered();                                                                   //makes the code entered be all zeros (or whatever value you define)
  initializeButtons();                                                                       //make the buttons ready to be pressed
  //to communicate and debug
  Serial.begin(9600);                                                                        //for debugging, to be removed in final version if you do not plan to use the serial monitor in your project.
  previousSerialMillis = 0;                                                                  //for debugging, to be removed in final version if you do not plan to use the serial monitor in your project.
} //end setup

void loop() {
  //--------REAL WORLD---------------
  readButtonsAndShiftEnteredCode();                                                           //read the buttons and add them to the entered code if a button has been pressed
  boolean isMatched = doesCodeEnteredMatchSecretCode();                                       //check to see if the code matches

  if (isMatched == true) {                                                                    //if the entered code matches the secret code, take some action
    digitalWrite(13, LOW);                                                                    //NOTE: insert the things that you want to do when there is matched code here
    speakerState = false;
  } // if isMatched
  // NOTE: you can put an else in here if there are actions to be taken repeatedly
  // while code is not matched.  However, this will get done extremely rapidly 
  // unless you put in another millis checker (i.e. only do when a certain number 
  // of millis has gone by)
  if (millis() > 5000) {
  //--------SERIAL COMMUNICATIONS-------------                                                 //This section is unnecessary if you do not plan to use the serial monitor in your project.

  //print out the entered code and if matched.                                                 
  if ((millis() - previousSerialMillis) > 1000) {                                              //only print every so often, eg. every 1 second
    for (int x = 0; x < secretCodeLength; x++){                                                //print the secretCode
    } //end for 
    if (isMatched == true) {                                                                   //print if it matches
       Serial.print("   Matched!"); 
    } //end if
   Serial.println();                                                                           //make new line
   previousSerialMillis = millis();                                                            //record when you did the last print
  } //end serial printing if 
} //end loop

// ==================================================================================

// --------FUNCTIONS---------------

void readButtonsAndShiftEnteredCode() {                                                         //PURPOSE:  read the buttons and then call shiftCodeEntered if a button has been are pressed
  for (int x = 0; x < numberOfButtons; x++) {                                                   //step through all buttons
    unsigned long currentMillis = millis();
    if ((currentMillis - previousButtonMillis[x]) > buttonInterval) {                           //check to see if enough time has passed since last press
      int newButtonState = digitalRead(buttonPins[x]);                                          //if enough time has passed, read the buttons
      if (newButtonState == buttonPressedState && buttonStates[x] == buttonNotPressedState) {   //only add to the code entered if it has from NotPressed to Pressed (i.e pressing and holding does not give more than one press)
          shiftCodeEntered(buttonValues[x]);                                                    //if button was pressed, add its value to code array
          previousButtonMillis[x] = currentMillis;                                              //reset button time
      } //end button state check if
      buttonStates[x] = newButtonState;                                                         //update the button state
    } //end millis if
  } //end of number of buttons for loop
} //end readButtons

void shiftCodeEntered(int buttonValue) {                                                        //PURPOSE: shifts the code one to the left, and then adds the value of the most recent pressed button on the right
  for (int x = 0; x < secretCodeLength; x++) {                                                  //step through the code
    codeEntered[x] = codeEntered[x+1];                                                          //for each code spot, shift it to the left.  the first digit gets lost.
    if (x == (secretCodeLength-1)) {                                                            //if the last spot, add the new digit from the button press
      codeEntered[x] = buttonValue;
    } //if
} //end shiftCodeEntered

void initializeCodeEntered() {                                                                  //PURPOSE:  initializes all spots in the code entered at the initization value, which is typically zero.  This is so you dont get an error and should be a different set of characters than is on the buttons (i.e. if the buttons are of value 1 - 4, make initilization 0) or ensure that this code will not be the secret code (i.e. can have any code except for all zeros)  
  //make each of the codes equal to the initial value it is to be assigned (typically 0)
  for (int x = 0; x < secretCodeLength; x++) {                                                  //step through the code entered
    codeEntered[x] = codeEnteredInitializedValue;                                               //for each digit, get it to the initilized value (typically zero)
  }// end for
} //end resetCodeEntered

void initializeButtons() {                                                                      //PURPOSE:  initilizes all the buttons as inputs, as not pressed, and waiting for a press
  for (int x = 0; x < numberOfButtons; x++) {                                                   //step through the buttons
    pinMode(buttonPins[x], INPUT);                                                              //for each button, make that buttons pin an input
    buttonStates[x] = buttonNotPressedState;                                                    //for each button, intialize each button as not pressed
    previousButtonMillis[x] = 0;                                                                //for each button, intialize when it was last pressed at zero (so can record future presses correctly)
 } //end initializeButtons

boolean doesCodeEnteredMatchSecretCode() {                                                      //PURPOSE:  check each digit of the entered code and the secret code against each other to see if they match
  boolean isMatched = true;                                                                     //assume the code is matched, and then make it not matched as soon as there is one different
  for (int x = 0; x < secretCodeLength; x++) {                                                  //step through the code entered
    if (isMatched == false || codeEntered[x] != secretCode[x]) {                                //if the code entered digit at that code spot does not equal the secret code digit at the code spot, or do not match in any previous checks, then make it false  
      isMatched = false;                                                                       //for each digit, get it to the initilized value (typically zero)
    } //end if
  } // end for
  return isMatched;                                                                            //return this to main program, to tell it if the code was matched or not
} //end doesCodeEnteredMatchSecretCode

void speakerPlay(boolean isSpeakerOn) {
  if (isSpeakerOn == true) {
 //   tone(speakerPin, 100, 1000);
    tone(speakerPin, 200, 1000);
  } //end if speaker on
} //end speakerPlay