Skip to content

Instantly share code, notes, and snippets.

@thedod
Last active March 1, 2022 04:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thedod/bbd8ca46adc9b909ea36 to your computer and use it in GitHub Desktop.
Save thedod/bbd8ca46adc9b909ea36 to your computer and use it in GitHub Desktop.
Gotcha - Simple Arduiono alarm system with "dead man switch" support

Lately, somebody started stealing from us. Took us time to figure it out. At first we thought things got lost. When they took a gas tank, it became obvious ;). As far as I know, it ain't over and it's no game. It's a lousy perimeter to defend, especially for old hippies who moved to the land of smiles because they got tired of saying "perimeter"[1].

But enough about me

This is a generic Arduino sketch that lets you whip up a simple and friendly alarm system from whatever sensors and controllers you've got lying around in cat-infested shoe boxes.

  • A sensor (PIR motion detector, magnetic door switch, weight sensor, etc.).
  • A controller (hidden button, keypad, RFID reader, etc.) to temporarily disable ("chill") the system.
  • A noisy device (buzzer, ghetto-blaster, tennis ball cannon aimed at a gong, GSM modem for sending SMS, etc.).
  • A LED.
  • Optional "dead man switch" slave device (see below).

Dead man switch

The early prototypes were battery powered, but doing battery replacement rounds in the mud would have been too much of a hassle, so the live systems are all AC powered (luckily, all problematic places are close to a socket). The drawback here is that one could disable the whole thing by cutting the power. The "dead man switch" trick is to have a pin that always outputs a HIGH signal sent to a slave device that should make a fuss if that signal drops. This may either be an attack or a genuine power cut (i.e. false alarm), and both may happen while I sleep, so I should wake up fast, and immediately understand we're not necessarily under attack ;). It should also be robust enough to withstand whatever took down the mother system (so that it can vow to avenge it in an extreme zoom out from above).

Does such a magical device exist? Here comes the clever bit: the relay (yellow ellipse) activates the power outlet that feeds the portable emergency lamp in our bedroom. Anything goes wrong, lights go up, and motion starts filming us getting dressed ;)

"Batteries no longer included"®

The inputs

  • "Chill controller" — hidden button, keypad, rfid, etc. to invoke a temporary CHILL state (1-2 minutes).
  • Sensor — PIR motion sensor, magnetic door switch, weight sensor, etc.

The outputs

  • LED — Indicates state.
  • Alarm — buzzer, piano-dropper, etc.
  • [Optional] "dead man switch" slave device.

The logic

It's as simple and sleepy-user-friendly as it gets (I thank my wife for surviving the early versions without resorting to violence. Believe me. It's friendly now). There are 5 states (indicated by the LED):

  1. READYLED is on: This is the normal state.
  2. WARNINGLED blinks: Happens when the sensor gets triggered [door opened, motion detected, etc.].
  3. ALARMLED blinks faster, alarm goes off: Happens when a WARNING isn't dealt with within a grace perion (a few seconds).
  4. CHILLLED blinks in a "hearbeat" pattern: User has activated the "chill controller" to temporarily disable the system (for 1-2 minutes), but the sensor is still getting triggered [door is open, motion is detected, etc.].
  5. COOLLED is off: We're in a CHILL, and the sensor's relaxed as well.

TL;DR

It's simple, friendly, flexible, easy to "knit" from leftover components, and beats worrying manually ;)


[1] On the [terribly fat] chance that the burglars are reading this [or English, for that matter], consider this gist an appeal to your common sense. Don't kid yourselves this "gives you intel". Just stay away. That's the best case scenario for us as well as you. "You don't want to see me when I'm non-violent"TM.

//--- states
int state;
#define STATE_READY 0 // LED on. Waiting for sensor to trigger WARNING
#define STATE_WARNING 1 // LED blinks. Sensor was triggered [->ALARM at say_when]
#define STATE_ALARM 2 // LED blinks faster, alarm goes off
#define STATE_CHILL 3 // temporary CHILL state [->ready at say_when]
// In STATE_CHILL, LED had a "hearbeat" blink pattern if sensor_triggered
// There's no "official" STATE_COOL, but the only time LED's off is
// when !sensor_triggered() during STATE_CHILL (and that's as cool as it gets).
//---- inputs ----
#define CHILL_PIN 2 // hidden button, keypad, rfid, etc. to invoke temporary CHILL state
#define SENSOR_PIN 3 // PIR motion sensor, magnetic door switch, weight sensor, etc.
//---- outputs ----
#define LED_PIN 6 // Indicates state
#define ALARM_PIN 7 // buzzer, piano-dropper, etc.
#define DMS_PIN 8 // Dead man switch: HIGH unless power cut, physical damage, etc.
// Best DMS device ever: relay activating mains plug feeding a
// portable emergency lamp where you sleep :)
//---- timers
unsigned long say_when; // [unless 0] when should relevant timer fire
#define WARNING_MILLISECONDS 6000 // 6 seconds before it's ALARM (unless chilled).
#define CHILL_MILLISECONDS 60000 // a CHILL is 1 minute long
//---- begin "hardware drivers" ----
bool sensor_triggered() {
// depends on sensor (PIR, door, etc.)
// Door magnet with a pull-down resistor:
return digitalRead(SENSOR_PIN)==LOW;
}
bool should_chill() {
// depends on control (hidden button, keypad, rfid, etc.)
// hidden button:
return digitalRead(CHILL_PIN)==HIGH;
}
void alarm(bool be_noisy) {
// if true: bring da noize (bullhorn, fireworks, etc.)
// if false: quiet down (activate sprinklers, tweet "JK", etc.)
// car horn:
// honk [if needed] in a "distinctively funky"TM beat
digitalWrite(ALARM_PIN,be_noisy&&(((millis()/100)%23)&21)?HIGH:LOW);
}
//---- end "hardware drivers" ----
#define DEBUG false // set to true for boring Serial debug prints
void setup() {
pinMode(LED_PIN,OUTPUT);
pinMode(DMS_PIN,OUTPUT);
digitalWrite(DMS_PIN,HIGH); // if we go down, aux sys bringz da noize
state = STATE_READY;
say_when = 0; // there's nothing we're waiting for
if (DEBUG) Serial.begin(9600);
}
void loop() {
if (DEBUG) {
Serial.print(millis());
Serial.print(':');
Serial.print(state);
Serial.print(',');
Serial.print(say_when);
Serial.print(',');
Serial.println(sensor_triggered());
}
if (should_chill()) { // chill control activated
state = STATE_CHILL;
say_when = millis()+CHILL_MILLISECONDS;
}
switch (state) {
case STATE_READY:
alarm(false);
digitalWrite(LED_PIN,HIGH);
if (!sensor_triggered()) break; // all's well
// Sensing. We're WARNING
state = STATE_WARNING;
say_when = millis()+WARNING_MILLISECONDS;
case STATE_WARNING:
digitalWrite(LED_PIN,((millis()/500)&1)?HIGH:LOW);
if (say_when>millis()) {
break; // keep waiting for timer
}
// time's up. activate
state = STATE_ALARM;
case STATE_ALARM:
alarm(true);
digitalWrite(LED_PIN,((millis()/200)&1)?HIGH:LOW);
break;
case STATE_CHILL:
alarm(false);
digitalWrite(LED_PIN,sensor_triggered()&&((millis()/100)%23)&5?HIGH:LOW); // "heartbeat" to warn we're still triggered
if (say_when>millis()) {
break; // keep waiting for timer
}
// back to normal
state = STATE_READY;
}
delay(100);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment