#include "Servo.h"; // Hardware Pins ==================================================== const int knockLED = 7; //Knock sensor light const int knockSensor = 2; //Analog input const int servoPin1 = 3; //Servo motor 1 const int servoPin2 = 5; //Servo motor 2 const int servoPin3 = 6; //Servo motor 3 const int servoPin4 = 9; //Servo motor 4 const int servoPin5 = 10; //Servo motor 5 const int servoPin6 = 11; //Servo motor 6 // Hardware variables ================================================ Servo theServo1; //make servo 1 available Servo theServo2; //make servo 2 available Servo theServo3; //make servo 3 available Servo theServo4; //make servo 4 available Servo theServo5; //make servo 5 available Servo theServo6; //make servo 6 available const int threshold = 150; //threshold for knock sensor (turn down to make more sensitive) const int rejectValue = 25; // percentage of error we don't unlock to const int averageRejectValue = 15; // average timing of the knocks being off by that we don't unlock const int knockFadeTime = 150; // milliseconds we allow a knock to fade before we listen for another one (Debounce timer) const int maximumKnocks = 20; // Maximum number of knocks to listen for in a pattern const int knockComplete = 1200; // Longest time to wait for a knock before we assume that it's finished // Secret knock variables ============================================== //The values always have to range from 0-100, and do not relate across different patterns, just internally. A quarter note can be 25, //50, or 100 depending on if there are half notes, eighth notes, etc. These are the durations of THE PAUSES, not the "notes" int secretCode1[maximumKnocks] = { 50, 25, 25, 50, 100, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // "Shave and a Hair Cut, two bits." int secretCode2[maximumKnocks] = { 50, 50, 100, 100, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // "Happy Birthday to Bob" int secretCode3[maximumKnocks] = { 100, 100, 100, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // "Row, Row, Row your boat" int secretCode4[maximumKnocks] = { 100, 100, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //"Here Comes the Bride" int secretCode5[maximumKnocks] = { 50, 50, 100, 50, 50, 100, 50, 50, 100, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //"Jingle Bells, jingle bells, jingle all the way" int secretCode6[maximumKnocks] = { 100, 100, 100, 100, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //"We will, we will rock you" int knockReadings[maximumKnocks]; // When someone knocks this array fills with delays between knocks. int knockSensorValue = 0; // Last reading of the knock sensor. void triggerDoorUnlock(int); int z; void setup() { Serial.begin(9600); //output stuff to debug screen pinMode(knockLED, OUTPUT); //declare knock sensor light theServo1.attach(servoPin1); //declare servo 1 theServo2.attach(servoPin2); //declare servo 2 theServo3.attach(servoPin3); //declare servo 3 theServo4.attach(servoPin4); //declare servo 4 theServo5.attach(servoPin5); //declare servo 5 theServo6.attach(servoPin6); //declare servo 6 } void loop() { // Serial.println(analogRead(servoPin1)); //output servo value knockSensorValue = analogRead(knockSensor); if (knockSensorValue >= threshold) { listenToSecretKnock(); } } // ==========SECRET KNOCK FUNCTIONS ===================================== void listenToSecretKnock(){ Serial.println("knock starting"); int i = 0; // First lets reset the listening array. for (i=0;i=threshold){ //got another knock... //record the delay time. now=millis(); delaytime = now-startTime; Serial.println(delaytime); knockReadings[currentKnockNumber] = delaytime; currentKnockNumber++; //increment the counter startTime=now; // and reset our timer for the next knock digitalWrite(knockLED, LOW); delay(knockFadeTime); // again, a little delay to let the knock decay. digitalWrite(knockLED, HIGH); } now=millis(); //did we timeout or run out of knocks? } while ((now-startTime < knockComplete) && (currentKnockNumber < maximumKnocks)); //we've got our knock recorded, lets see if it's valid int knockpattern = validateKnock(); if (knockpattern > 0){ triggerDoorUnlock(knockpattern); } else { Serial.println("Secret knock failed."); Serial.println("******************"); Serial.println(knockReadings[0]); Serial.println(knockReadings[1]); Serial.println(knockReadings[2]); Serial.println(knockReadings[3]); Serial.println(knockReadings[4]); Serial.println(knockReadings[5]); Serial.println(knockReadings[6]); Serial.println(knockReadings[7]); Serial.println(knockReadings[8]); Serial.println("******************"); } digitalWrite(knockLED, LOW); // We didn't unlock, so blink the red LED as visual feedback. for (i=0;i<4;i++){ digitalWrite(knockLED, HIGH); delay(100); digitalWrite(knockLED, LOW); delay(100); } digitalWrite(knockLED, HIGH); } // SECRET KNOCK FUNCTION- TRIGGER DOOR ============================================= void triggerDoorUnlock(int door){ Serial.println("Door unlocked!"); int i=0; Serial.print("Door number: "); Serial.println(door); switch (door) { case 1: theServo1.write(189); Serial.println("Servo 1 activated!"); delay(2000); theServo1.write(10); //reset the servo Serial.println("Servo 1 reset!"); break; case 2: theServo2.write(189); Serial.println("Servo 2 activated!"); delay(2000); theServo2.write(10); //reset the servo Serial.println("Servo 2 reset!"); break; case 3: theServo3.write(189); Serial.println("Servo 3 activated!"); delay(2000); theServo3.write(10); //reset the servo Serial.println("Servo 3 reset!"); break; case 4: theServo4.write(189); Serial.println("Servo 4 activated!"); delay(2000); theServo4.write(10); //reset the servo Serial.println("Servo 4 reset!"); break; case 5: theServo5.write(189); Serial.println("Servo 5 activated!"); delay(2000); theServo5.write(10); //reset the servo Serial.println("Servo 5 reset!"); break; case 6: theServo6.write(189); Serial.println("Servo 6 activated!"); delay(2000); theServo6.write(10); //reset the servo Serial.println("Servo 6 reset!"); break; } } // SECRET KNOCK FUNCTION- VALIDATE KNOCK ========================================= int validateKnock(){ //if knock doesn't validate, returns 0. Otherwise returns int of which knock validated. int i=0; int knockid = 0; boolean confirm1 = true; //the confirms start true for all patterns, then are made false one at a time boolean confirm2 = true; boolean confirm3 = true; boolean confirm4 = true; boolean confirm5 = true; boolean confirm6 = true; // simplest check first: Did we get the right number of knocks? int currentKnockCount = 0; int secretKnockCount1 = 0; int secretKnockCount2 = 0; int secretKnockCount3 = 0; int secretKnockCount4 = 0; int secretKnockCount5 = 0; int secretKnockCount6 = 0; int maxKnockInterval = 0; // We use this later to normalize the times. for (i=0;i 0){ currentKnockCount++; } if (secretCode1[i] > 0){ //Number of knocks in secretknock 1 secretKnockCount1++; } if (secretCode2[i] > 0){ //Number of knocks in secretknock 2 secretKnockCount2++; } if (secretCode3[i] > 0){ secretKnockCount3++; } if (secretCode4[i] > 0){ secretKnockCount4++; } if (secretCode5[i] > 0){ secretKnockCount5++; } if (secretCode6[i] > 0){ secretKnockCount6++; } if (knockReadings[i] > maxKnockInterval){ // collect normalization data while we're looping. maxKnockInterval = knockReadings[i]; } } Serial.print("currentKnockCount="); Serial.println(currentKnockCount); Serial.println(maxKnockInterval); if (currentKnockCount != secretKnockCount1 && currentKnockCount != secretKnockCount2 && currentKnockCount != secretKnockCount3 && currentKnockCount != secretKnockCount4 && currentKnockCount != secretKnockCount5 && currentKnockCount != secretKnockCount6){ //if the number of knocks aren't right, it's wrong Serial.println("Wrong number of knocks!"); return 0; } /* Now we compare the relative intervals of our knocks, not the absolute time between them. (ie: if you do the same pattern slow or fast it should still open the door.) This makes it less picky, which while making it less secure can also make it less of a pain to use if your tempo is a little slow or fast. */ int totaltimeDifferences1=0; int totaltimeDifferences2=0; int totaltimeDifferences3=0; int totaltimeDifferences4=0; int totaltimeDifferences5=0; int totaltimeDifferences6=0; int timeDiff1=0; int timeDiff2=0; int timeDiff3=0; int timeDiff4=0; int timeDiff5=0; int timeDiff6=0; Serial.print("maximumKnocks: "); Serial.println(maximumKnocks); for (i=0;i rejectValue){ // Individual value too far out of whack confirm1 = false; Serial.println("doesn't match pattern 1!"); } if (timeDiff2 > rejectValue){ confirm2 = false; Serial.println("doesn't match pattern 2!"); } if (timeDiff3 > rejectValue){ confirm3 = false; Serial.println("doesn't match pattern 3!"); } if (timeDiff4 > rejectValue){ confirm4 = false; Serial.println("doesn't match pattern 4!"); } if (timeDiff5 > rejectValue){ confirm5 = false; Serial.println("doesn't match pattern 5!"); } if (timeDiff6 > rejectValue){ confirm6 = false; Serial.println("doesn't match pattern 6!"); } totaltimeDifferences1 += timeDiff1; totaltimeDifferences2 += timeDiff2; totaltimeDifferences3 += timeDiff3; totaltimeDifferences4 += timeDiff4; totaltimeDifferences5 += timeDiff5; totaltimeDifferences6 += timeDiff6; } // It can also fail if the whole thing is too inaccurate. if (totaltimeDifferences1/secretKnockCount1>averageRejectValue || totaltimeDifferences2/secretKnockCount2>averageRejectValue || totaltimeDifferences3/secretKnockCount3>averageRejectValue || totaltimeDifferences4/secretKnockCount4>averageRejectValue || totaltimeDifferences5/secretKnockCount5>averageRejectValue || totaltimeDifferences6/secretKnockCount6>averageRejectValue){ Serial.println("the whole thing is too inaccurate!"); // return 0; } if (confirm1) { return 1; } //if it's true, return it! else if (confirm2) { return 2; } else if (confirm3) { return 3; } else if (confirm4) { return 4; } else if (confirm5) { return 5; } else if (confirm6) { return 6; } }