Built-in project · Arduino Uno R3

Secret knock lock on an Arduino Uno

An SW-420 vibration sensor on the door listens for a secret rhythm, three quick knocks and one after a pause: the right one opens the servo bolt, anything else flashes red. The whole build, an Arduino Uno and 6 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

IntermediateRuns in your browser. Free, and no account needed.

Secret knock lock · Arduino Uno R3live0.000 s 0.00x
Click to open it in the editor
The circuit itself, running here on the simulator. Press what can be pressed; click anything else to open it in the editor.

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · Arduino Uno R3
// Secret knock lock: an SW-420 vibration sensor taped to the door, a servo
// that slides the bolt, and two lamps.
//
//   pin 2   the SW-420's DO (low when still, pulses high on a knock)
//   pin 9   the servo's signal wire (its red wire on 5 V, brown on GND)
//   pin 7   through 220 ohm to the green LED
//   pin 6   through 220 ohm to the red LED
//
// The secret is a rhythm, not a count: knock, knock, knock, pause, knock. The
// gaps are short, short, long, the long one twice the others. Knocking faster
// or slower is fine, because the sketch compares the gaps with the longest
// one, not with a clock.
//
// # Hearing one knock
//
// A knock is not one clean pulse on DO. The switch inside the can bounces for
// a few tens of milliseconds, so DO pulses high several times. The sketch
// takes the first edge as the knock and ignores DO for 100 ms after it.
//
// # The rhythm
//
// After 1.5 s with no knock the sequence is over. Each gap is scaled so the
// longest is 100, and each has to be within 25 of the secret's.

#include <Servo.h>

const int SENSOR = 2;
const int BOLT = 9;
const int GREEN_LED = 7;
const int RED_LED = 6;

const int LOCKED = 0;
const int OPEN = 90;

const int MAX_KNOCKS = 10;
const unsigned long DEBOUNCE_MS = 100;
const unsigned long DONE_MS = 1500;
const int TOLERANCE = 25;

// The secret, as gaps scaled to the longest: short, short, long.
const int SECRET[] = {50, 50, 100};
const int SECRET_GAPS = sizeof(SECRET) / sizeof(SECRET[0]);

Servo bolt;
unsigned long knockAt[MAX_KNOCKS];
int knocks = 0;

void setup() {
  Serial.begin(115200);
  Serial.println("Mokxi Arduino Uno: secret knock lock");
  pinMode(SENSOR, INPUT);
  pinMode(GREEN_LED, OUTPUT);
  pinMode(RED_LED, OUTPUT);
  bolt.attach(BOLT);
  bolt.write(LOCKED);
}

bool rhythmMatches() {
  if (knocks - 1 != SECRET_GAPS) return false;
  unsigned long longest = 1;
  for (int i = 1; i < knocks; i++) {
    unsigned long gap = knockAt[i] - knockAt[i - 1];
    if (gap > longest) longest = gap;
  }
  for (int i = 1; i < knocks; i++) {
    int scaled = (int)((knockAt[i] - knockAt[i - 1]) * 100 / longest);
    Serial.print("  gap ");
    Serial.print(scaled);
    Serial.print(" (want ");
    Serial.print(SECRET[i - 1]);
    Serial.println(")");
    int off = scaled - SECRET[i - 1];
    if (off < -TOLERANCE || off > TOLERANCE) return false;
  }
  return true;
}

void unlock() {
  Serial.println("unlocked");
  digitalWrite(GREEN_LED, HIGH);
  bolt.write(OPEN);
  delay(4000);
  bolt.write(LOCKED);
  digitalWrite(GREEN_LED, LOW);
  Serial.println("locked");
}

void refuse() {
  Serial.println("wrong knock");
  for (int i = 0; i < 3; i++) {
    digitalWrite(RED_LED, HIGH);
    delay(150);
    digitalWrite(RED_LED, LOW);
    delay(150);
  }
}

void loop() {
  unsigned long now = millis();
  if (digitalRead(SENSOR) == HIGH) {
    if (knocks == 0 || now - knockAt[knocks - 1] > DEBOUNCE_MS) {
      if (knocks < MAX_KNOCKS) {
        knockAt[knocks] = now;
        knocks++;
        Serial.print("knock ");
        Serial.println(knocks);
      }
    }
  }
  if (knocks > 0 && now - knockAt[knocks - 1] > DONE_MS) {
    if (rhythmMatches()) {
      unlock();
    } else {
      refuse();
    }
    knocks = 0;
  }
}

Parts list

8 parts, plus the jumper wires. Every one is in the editor's parts bin.

How it is wired

8 connections, pin by pin, read from the circuit itself. Each line is one set of pins joined together, by a jumper wire or a breadboard strip.

  • Arduino Uno R3 pin 9; Hobby servo pin PWM
  • Arduino Uno R3 pin 7; Resistor, 220 Ω (1) pin 1
  • Arduino Uno R3 pin 6; Resistor, 220 Ω (2) pin 1
  • Arduino Uno R3 pin 2; Vibration sensor, SW-420 pin DO
  • Arduino Uno R3 pin 5V; Vibration sensor, SW-420 pin VCC; Hobby servo pin VCC
  • Ground: Arduino Uno R3 pin GND; Vibration sensor, SW-420 pin GND; Hobby servo pin GND; LED, green pin C; LED, red pin C
  • Resistor, 220 Ω (1) pin 2; LED, green pin A
  • Resistor, 220 Ω (2) pin 2; LED, red pin A

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.