Prototype complete: bag movement alarm

After figuring out the modified power circuit and the battery power monitor circuit, I could finally finish the prototype of the bag movement alarm.  I also added the same power switch circuit for the speaker, which allowed me to use a much better speaker (when I had tried it before with the old power circuit, it beeped constantly).

Thankfully, I completed this on December 24th as I had planned on doing this for my parents for Christmas.  I had hoped to have it completed and in the project box, but after a late night on the 24th night and not finishing laying out the circuit on a PCB, I gave up and went to bed.  Parents are getting the prototype and the project box, and I will have to get it in there in the next few days.

The completed circuit in all its glory:

Completed bag movement alarm prototype!

Completed bag movement alarm prototype!

Prototype close up

Prototype close up

A video of the prototype in action:

And the code:

/* alarmbox.ino

 Implements a movement alarm box with a security code using buttons as the
 way to input the code.
 
 The project includes utilizes an accelerometer to track movement, a set of
 buttons to input the security code and power the project on, and Trinket Pro
 as the brains (although other implementations of an ATMega328 could be 
 substituted).
 
 The number of buttons, the number of digits in the secret code, and the 
 numerical value of each button (for the code), the sensitivity of the 
 movement testing, and the timeframes for various components of the user
 experience can all be defined independently.

 The box has a power circuit where pressing and holding the power button turns
 the project on, but then does not work to turn the box off.  The box can only
 be turned off by the software.

 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).  
 
 User interface [indicate changable elements]:
 (1) Device is normally off.  Press and hold power button for 3-5 seconds
 to turn decice on; wait for the Status LED [green LED] to turn on. 
 (2) After powering up, Status LED will blink for [10] seconds.  During this
 time the user must enter the [secret code].  This is to ensure against turning
 on accidentally as well as to ensure that user remembers what the code is 
 before the device gets armed.  If the user does not successfully enter
 the secret code during this time, the device turns itself off.
 (3) After successfully entering the code, the Status LED will turn solid
 on.  This indicates that the device is giving the user time to put the device
 stationary, in this sketch [20] seconds.
 (4) The Status LED turns off, indicating that the device is now armed and 
 listening to the accelerometer.  If there is movement, the Status LED
 blinks slightly to indicate movement.
 (5) If there is movement for more than [5] seconds and above [threshhold],
 the alarm goes off and turns the Status LED solid on.  The alarm stays on 
 until the user enters the secret code.
 (6) Once the device is on, if the user enters the secret code after or during
 the settling time, the Status LED will blink once long, then three short, and
 then then the device will turn itself off without turning the alarm on.
 (5) If the battery is low voltage, set as below [6.5] volts, then when the
 Status LED is turned on in step (1) or in (5) or (6), the Battery Low Voltage
 LED [yellow LED] will turn on solid on.
 
 Created December 2014
 by MakerSelf (makerself.com)
 Please use, modify and be merry!

*/

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

// --------***CONSTANTS USER CHANGE***---------------
// --SECRET CODE--
const int secretCodeLength = 7;                                  //secret code can be any length.  Suggest 4-7 digits.
const int secretCode[secretCodeLength] = {1, 2, 3, 4, 3, 2, 1};  //secret code is hard coded
const int codeEnteredInitializedValue = 0;                       //suggest something that is NOT in the possible values from the buttons pressed

// --BUTTONS--
const int numberOfButtons = 4;                             //reflects number of buttons in the circuit
const int buttonPins[numberOfButtons] = {9, 10, 11, 12};   //put your pins here, depending on which pins your have wired to in the circuit.
const int buttonValues[numberOfButtons] = {1, 2, 3, 4};    //put the values of the button you want to use here
const int buttonInterval = 200;                            //this is the sensitivity of the button (i.e. how quickly can you double press the button)
const byte buttonPressedState = HIGH;                      //can either tie pins to ground (in this sketch) or to +5V rail
const byte buttonNotPressedState = LOW;

// --CIRCUIT PINS--                                        //put your pins here for your circuit
const int statusLEDPin = 6;                                //must be PWM pin
const int batteryLEDPin = 5;                               //either PWM or just HIGH/LOW out
const int OnOffPin = 4;                                    //either PWM or just HIGH/LOW out
const int speakerPin = 3;                                  //suggest PWM pin, depending on your speaker/alarm
const int batteryVoltagePin = A3;                          //must be an analog in pin    

// --ACCELEROMETER--
const int AcSensitivity = 1400;            //high enough so that little bumps dont trigger it, but movement does.  Will need to experiment.
const int maxMovementTime = 5000;          //number of milliseconds of movement allowed before the alarm goes off.  5000 = 5 seconds.
const int maxStillnessThreshold = 20;      // % threshold of stillness above which the thing is moving
const int readMPUinterval = 250;           //number of milliseconds between checks of the accelerometer
const int upfrontSettleTime = 20000;       //number of milliseconds before starts checking accelermeter

// --BATTERY LOW VOLTAGE MONITOR--
float lowVoltageLevel = 6.5;              //Warning level.  Trinket Pro indicates that it needs 5.5 V (although apparently can handle a bit less), so this give a bit of head room before it becomes a problem, and is approximately the knee of the battery discharge curve for 9V ones I have found
float actual5vOutVoltage = 4.99;          //use a volt meter to test what the AREF is to get what the logic level is.  This should nominally be 5v.  Just helps the accuracy of the battery monitor, but not necessary:  can just assign as 5.00.

// --STATUS LED--
const int movedLEDbrightness = 150;       //whatever you want.  Set here for about 50% brightness, which is visable but not annoying.

// --STARTUP PHASE ASKING FOR CODE TO BE ENTERED--
const int startingTime = 10000;                  //time up front where the user needs to enter the code to cause it arm
const int startingMillisBlinkInterval = 200;     //whatever you want

// ---------***CONSTANTS THAT THE USER DOES NOT CHANGE***---------
const int MPU=0x68;                                                              // I2C address of the MPU-6050
const int maxMovementTimeArrayDifference = maxMovementTime / readMPUinterval;    // number of array entries necessary for their to be movement
const int movedRecordLength = maxMovementTimeArrayDifference  * 2;               //need to keep more than just the maxMovementTime otherwise if the first or the last in the array is 'not moved' then sketch will consider it to be not moved.
boolean movedRecord[movedRecordLength];                                          //the array of each check to see if it moved.  Recent ones gets added, and old ones get shifted out.

//------------**** VARIABLES ****---------------------
int codeEntered[secretCodeLength];                       //array of the buttons pressed so far.  This gets initilized.
byte buttonStates[numberOfButtons];                      //array of buttonStates, for debouncing. This gets initilized.
unsigned long previousButtonMillis[numberOfButtons];     //timer for button presses.  Array of last time the button was pressed, for debouncing.  This gets initilized.
byte speakerState;                                       //gets set before speaker is called

int AcX,AcY,AcZ;                                         //accelerometer values
int OldAcX,OldAcY,OldAcZ = 0;                            //old accelerometer values from last time it was checked
boolean moved = false;                                   //to track if it is moved
boolean isStolen = false;                                //to track if the device has been stolen (exceeds the max movement time and threshold)

unsigned long previousMPUmillis = 0;                     //timer for checking the accelerometer
unsigned long endOfSetupMillis;                          //to track when the setup has ended (user has successfully put in the code to arm the device)
unsigned long previousSerialMillis;                      //for debugging or printing to the serial.  Gets initialized to zero when begin Serial Communication.  Unecessary for sketch to work.

// -------LIBRARIES----------------
#include<Wire.h>                                         //for communicating to the accelerometer


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

// --------MAIN PROGRAM---------------
void setup() {
  //--TURN ON CIRCUIT VIA SOFTWARE--
  //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 power circuit transistor on by making the voltage HIGH
  pinMode(statusLEDPin, OUTPUT);                         // initialize the statusLED as an output
  digitalWrite(statusLEDPin, HIGH);                      // turn the statusLED on to show that the power is flowing to the TrinketPro without the continued press of the power button.
  
  //INITALIZE THINGS
  //intialize speaker
  pinMode(speakerPin, OUTPUT);                           //intialize the speakerPin as an output
   
  //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

  //initialize MPU accelerometer
  beginMPUcommunications();                              //start communicating with the accelerometer
  initializeMovedRecord();                               //set the moved record as all 'not moved'
  
  //initialize battery monitor
  pinMode(batteryVoltagePin, INPUT);                     //initilize the analog in pin for reviewing the battry voltage
  pinMode(batteryLEDPin, OUTPUT);                        //Battery LED pin 
  digitalWrite(batteryLEDPin, LOW);                      //assume that the battery is fine unless below the threshold.
  
  //to communicate and debug
  Serial.begin(9600);                                    //for debugging.  Unecessary for sketch to work.
  previousSerialMillis = 0;                              //for debugging.  Unecessary for sketch to work.

  //--ACTUAL ACTION--
  //check battery and put on LED if low
  boolean isVoltageTooLow = voltageCheck();              
  if (isVoltageTooLow == true) {
    digitalWrite(batteryLEDPin, HIGH);                  //battery LED is solid on, even if the status LED is flashing
  } //end if
  
  //blink to indicate that code is to be entered.  If not entered, shut off.
  unsigned long currentMillis = millis();
  unsigned long previousStartingMillis = currentMillis;                            //need these as they get tested once before being set again in the while loop
  int startingLEDstate = HIGH;
  digitalWrite(statusLEDPin, startingLEDstate);
  boolean isMatchedSetup = doesCodeEnteredMatchSecretCode();                       //this is probably unnecessary (could just set isMatchedSetup == false) as at this point user will have had to be milisecond quick to have entered the code, but might as well leave it in and it only gets run once. 
  
  while (isMatchedSetup == false && currentMillis < startingTime) {                //stays in this while loop until the code is matched or starting time elapses with no code pressed.  Nothing else happens except this.
    //blink the LED
    if ((currentMillis - previousStartingMillis) > startingMillisBlinkInterval) {  //blink to LED on the blink interval set above
      startingLEDstate = !startingLEDstate;
      digitalWrite(statusLEDPin, startingLEDstate);
      previousStartingMillis = currentMillis;
    } //end if to blink LED
    
    //read buttons and see if the code entered via the button matches the secret code yet
    readButtonsAndShiftEnteredCode();
    isMatchedSetup = doesCodeEnteredMatchSecretCode();

    //reset the timer
    currentMillis = millis();
  } //end the while for waiting for the code to be entered successfully or starting time to pass
  
  //code was entered successfully
  if (isMatchedSetup == true) {
    digitalWrite(statusLEDPin, HIGH);                                             //when the code has been entered successfully, set the Status pin to solid (indicating waiting time) and...
    initializeCodeEntered();                                                      //...reinitilize the code entered so far back to zeros
  }
  else                                                                            //isMatched == false, so it was the currentMillis that ended the while and code was not entered successfully in the startingTime 
  {
    digitalWrite(OnOffPin, LOW);                                                  //shut off the circuit
  } 
  
  //exit from setup and go to loop
  endOfSetupMillis = millis();                                                    //need this so the settling time can start properly
} //end setup

void loop() {
  //--------REAL WORLD---------------
  
  // Get new timer for each round of the loop
  unsigned long currentMillis = millis();
  
  // indicate that you are within the settle time by turning the LED high, if not, put the pin low
  if (currentMillis < (endOfSetupMillis + upfrontSettleTime)) {
    digitalWrite(statusLEDPin, HIGH);
  }
  else
  {
    digitalWrite(statusLEDPin, LOW);
    digitalWrite(batteryLEDPin, LOW);                                              //if battery LED pin is on, it will turn off.  If battery LED pin was off, this makes no difference.
  }

  // start reading the MPU on a regular basis (if outside of the upfront settle time) and then check to see if device has been stolen after each reading
  if (((currentMillis - previousMPUmillis) > readMPUinterval) && (isStolen == false) && (currentMillis > (endOfSetupMillis + upfrontSettleTime))){
    // read the MPU and process the data
    checkPositionChangeAndShiftRecord();
    printMovedRecord();                                                              //for debugging.  Not necessary for sketch to work.
    isStolen = checkIfStolen();
    previousMPUmillis = currentMillis;     //reset timer
  } //end if

  //read the buttons and check to see if it matches
  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
  
  //take action if stolen
  if (isStolen == true) {
    digitalWrite(statusLEDPin, HIGH);
    if (isMatched == true) {                                                         //if the entered code matches the secret code, turn the LED off, the speaker off, and the device off 2 seconds later (could shut it off at the same time, but I wanted to make it obvious they were separate)
      digitalWrite(statusLEDPin, LOW);                                               
      speakerState = false;
      speakerPlayBuzzer(speakerState);                                               //this speaker play can be changed to different function depending on what type of buzzer you are using (e.g. does it need a tone, etc.)
      
      //turn off device
      delay(2000);
      digitalWrite(OnOffPin, LOW); 
    } // if isMatched
    else { //code does not yet match
      speakerState = true;
      speakerPlayBuzzer(speakerState);                                               //see comment above about the speaker play function
    }
      
  } else {                                                                           //end if stolen now look at when it has not been stolen
    if (isMatched == true) {                                                         //if the entered code matches the secret code (and it was not stolen), turn on the LED to flash it, then turn the device off.
        //check battery and put on LED if low
        boolean isFinalVoltageTooLow = voltageCheck();                               //check the voltage again and put on the LED.  Could be different than during the setup, as some time may have passed.
        byte voltageLEDfinalStatus = LOW; 
        if (isFinalVoltageTooLow == true) {
          voltageLEDfinalStatus = HIGH;
        } //end if   
      
      //flash the status pin before turning off.  This is quick and dirty flash based on delays.  I could have made this based on some timer, but felt it was unnecessary as the code is just heading to shutting the device down.
      digitalWrite(statusLEDPin, HIGH);                                              //flash the status LED
      digitalWrite(batteryLEDPin, voltageLEDfinalStatus);                            //flash the battery LED along with the status LED
      delay(1000);
      digitalWrite(statusLEDPin, LOW); 
      digitalWrite(batteryLEDPin, LOW);
      delay(100);
      digitalWrite(statusLEDPin, HIGH); 
      digitalWrite(batteryLEDPin, voltageLEDfinalStatus);
      delay(200);
      digitalWrite(statusLEDPin, LOW); 
      digitalWrite(batteryLEDPin, LOW);
      delay(100);
      digitalWrite(statusLEDPin, HIGH);
      digitalWrite(batteryLEDPin, voltageLEDfinalStatus);
      delay(200);
      digitalWrite(statusLEDPin, LOW); 
      digitalWrite(batteryLEDPin, LOW);
      delay(100);
      digitalWrite(statusLEDPin, HIGH);
      digitalWrite(batteryLEDPin, voltageLEDfinalStatus);
      delay(200);
      digitalWrite(statusLEDPin, LOW); 
      digitalWrite(batteryLEDPin, LOW);

      //turn off device
      delay(2000);
      digitalWrite(OnOffPin, LOW);
    } //if matched 
  }//else
  
  //--------SERIAL COMMUNICATIONS-------------                                                 //This section is for debugging, and is unnecessary for the sketch to run.

  //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
       Serial.print(codeEntered[x]);  
    } //end for 
   Serial.println();                                                                           //make new line
   previousSerialMillis = millis();                                                            //record when you did the last print
  } //end serial printing if 
  //-------------------------------------------

  
} //end loop

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

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

//--Button and code 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
  }//for
} //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


// --Speaker Functions--
void speakerPlayPiezo(boolean isSpeakerOn) {                                                   //PURPOSE:  Turn the speaker on or off.  For use with a simple piezo speaker.
  if (isSpeakerOn == true) {
    tone(speakerPin, 200, 1000);                                                               //chose your tone, or have several tones.
  } //end if isSpeakerOn
} //end speakerPlayPiezo

void speakerPlayMallory(boolean isSpeakerOn) {                                                 //PURPOSE:  Turn the speaker on or off.  For use with a mallory speaker (this may need adjustment)
  int frequency = ((1 / 3400)*1000000)/2;                                                      //chose based on the frequency of the speaker
  for (long i = 0; i < 3400 * 3; i++ ) 
  {
     digitalWrite(speakerPin, HIGH);
     delayMicroseconds(frequency);
     digitalWrite(speakerPin, LOW);
     delayMicroseconds(frequency);
  } //end if
} //end SpeakerPlayMallory

void speakerPlayBuzzer(boolean isSpeakerOn) {                                                  //PURPOSE:  Turn the speaker on or off.  For use with a simple ON/OFF buzzer.
  if (isSpeakerOn == true) {
    digitalWrite(speakerPin, HIGH);
  }
  else //isSpeakerOn == false
  {
    digitalWrite(speakerPin, LOW);
  } //end if isSpeakerOn
  
} //end speakerPlayBuzzer

//--Battery Voltage Monitor functions--
boolean voltageCheck() {                                                                        //PURPOSE:  check the voltage on the battery and see if it is less than the threshold, returning a boolean of if it is too low or not
  // read the input on the voltage
  int sensorValue = analogRead(batteryVoltagePin);

  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = sensorValue * (actual5vOutVoltage/1023.0) * 2;                                //in circuit, use a voltage divider to bring the 9v below the 5v for the analog in pin.  Use two equal resistors for the voltage divider so multiply by two here to get the actual voltage.
  
  //Serial                                                                                      //only for debugging purposes.  Unnecessary for sketch to run.
  Serial.print(" SV: ");
  Serial.print(sensorValue);
  Serial.print(" Voltage: ");
  Serial.print(voltage);
 
  // check to see if the voltage is below the threshold
  boolean isVoltageTooLow = false;                                                              //assume it is not too low, unless the comparison results in it being too low
  if (voltage < lowVoltageLevel) {
    isVoltageTooLow = true;
  }
  return isVoltageTooLow;
}

//--Accelerometer functions--
void initializeMovedRecord() {                                                                  //PURPOSE: set the moved record at all false to begin with.
  for (int x = 0; x < movedRecordLength; x++) {
    movedRecord[x] = false;
  } //end for
} //end initializeMovedRecord


void beginMPUcommunications() {                                                                 //PURPOSE: begin communications with MPU accelerometer. Done once.
  Wire.begin();
  Wire.beginTransmission(MPU);
  Wire.write(0x6B);                                                                             // PWR_MGMT_1 register
  Wire.write(0);                                                                                // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
} //end beginMPUcommunications

void readMPUrawvalues() {                                                                       //PURPOSE:  read the raw values from the accelerometer.
  Wire.beginTransmission(MPU);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU,14,true);  // request a total of 14 registers
  AcX=Wire.read()<<8|Wire.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)     
  AcY=Wire.read()<<8|Wire.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ=Wire.read()<<8|Wire.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
} //end readMPUrawvalues

void checkPositionChangeAndShiftRecord() {                                                      //PURPOSE: read the raw values from the accelerometer, check against the old values.  If there is movement above the sensitivity level, add 'true' to the movement record, if not, add 'false' to the movement record  
   readMPUrawvalues();
  //Check to see if it has moved and add to the move record
  if (abs(OldAcX - AcX) > AcSensitivity) { moved = true; }
  if (abs(OldAcY - AcY) > AcSensitivity) { moved = true; }
  if (abs(OldAcY - AcY) > AcSensitivity) { moved = true; }
  shiftMovedRecord(moved);                                                                      //add the moved value (either true or false) to the moved record
  
  //turn on Status if moved
  if (moved == true) {
    analogWrite(statusLEDPin, movedLEDbrightness);
  }
  
  //reset the values for next check
  OldAcX = AcX;
  OldAcY = AcY;
  OldAcZ = AcZ;
  moved = false;  
} //end checkPositionChangeAndShiftRecord

void shiftMovedRecord(boolean movedValue) {                                                    //PURPOSE: shifts the movedRecord one to the left, and then adds the value of the most recent moved record the right
  for (int x = 0; x < movedRecordLength; x++) {                                                //step through the movedRecord
    movedRecord[x] = movedRecord[x+1];                                                         //for each record spot, shift it to the left.  the first record gets lost.
    if (x == (movedRecordLength-1)) {                                                          //if the last spot, add the new record from the most recent record
      movedRecord [x] = movedValue;
    } //end if
  }//end for
} //end shiftMovedRecord

boolean checkIfStolen() {                                                                     //PURPOSE:  step through the moved record and see if the record meets the circumstances deemed to mean the at the device is stolen
  boolean stolenStatus = false; //assume it has not been stolen until it has been proven stolen
  
  //---------------First test:  is there movement more than 5 seconds apart
  int firstMoved = movedRecordLength -1;                                                       //initalize as the far end of where it will start
  int lastMoved = 0;                                                                           //initalize as the far end of where it will start
  boolean firstMovedSet = false; 
  boolean lastMovedSet = false;
  boolean movedEnoughTime = false;
  
  for (int x = 0; x < movedRecordLength; x++) {                                                // get first moved, starting from 0.  Note this will cycle through the whole record, even if it finds first moved early.  Okay but slightly inefficient.
    if (movedRecord[x] == true && firstMovedSet == false) {
      firstMoved = x;
      firstMovedSet = true;
    } //end if
  } //end for  

  for (int x = (movedRecordLength - 1); x >= 0; x--) {                                         // get last moved, starting from the end of the moved record.  Note this will cycle through the whole record, even if it finds last moved early.  Okay but slightly inefficient.
    if (movedRecord[x] == true && lastMovedSet == false) {
      lastMoved = x;
      lastMovedSet = true;
    } //end if
  } //end for 
 
  if ((lastMoved - firstMoved) > maxMovementTimeArrayDifference){
     movedEnoughTime = true;
  } 
  //-------------end First test -----------------------------------------

  //---------------Second test:  if there is movement over 5 seconds, is it more than the threshold

  if (movedEnoughTime == true){
    int trueCounter = 0;
    for (int x = firstMoved; x <= lastMoved; x++) {                                                //step through the movedRecord between the first moved and the last moved positions
      if (movedRecord[x] == true) {
        trueCounter++;                                                                             //count the number of trues in the section of movedRecord
      } //end if
    } //end for
    
    int movementPercent = map(trueCounter, 0, lastMoved - firstMoved + 1, 0, 100);                 //map the trueCounter amount out of the number of records being checked, to a 0 to 100 percentage.  This allows the use of interger math.
    if (movementPercent > maxStillnessThreshold) {
      stolenStatus = true;
    } //end greater than maxStillnessThreshold
    else {
      stolenStatus = false;
    } //end less than maxStillnessThreshold
  
  } //end-----------------Second test --------- if movement over difference in array

  return stolenStatus;
} //end checkIfStolen


//--------------------SERIAL COMMUNICATIONS --------------------------------------
//only for debugging.  Unnecessary for the sketch to run.
void printMovedRecord() {
  for (int x = 0; x < movedRecordLength; x++) {
    Serial.print(movedRecord[x]);
  } //end for
  Serial.println();
} //end initializeMovedRecord
Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s