#include <MsTimer2.h>
/*
PIR sensor tester
*/
#include <MsTimer2.h>
const int INTERVAL = 500; // 500ms
const int DOOR_OPENED = HIGH;
const int DOOR_CLOSED = LOW;
const int PIR_TRIGGERED = HIGH;
const int PIR_RESET = LOW;
const int LED_ON = LOW;
const int LED_OFF = HIGH;
const int RELAY_ON = HIGH;
const int RELAY_OFF = LOW;
const int GUARD_TIMEOUT = (30 * 1000 / INTERVAL);
const int GUARD_BEGIN = (GUARD_TIMEOUT - (10 * 1000 / INTERVAL));
const int DEBOUNCE_TIME = 10;
enum STATE {
IDLE = 0,
GUARD,
INHIBIT,
ALARM
};
int relayPin = 5; // choose the input pin (for PIR sensor)
int ledPin = 4; // choose the pin for the LED
int pirPin = 3; // choose the input pin (for PIR sensor)
int doorPin = 2;
int pirState = PIR_RESET; // we start, assuming no motion detected
int pirVal = 0; // variable for reading the pin status
int doorState = DOOR_CLOSED;
int doorVal = 0;
bool timerStarted = false;
bool timerTriggered = false;
int timer = 0;
STATE state = IDLE;
void log(char* msg) {
Serial.println(msg);
}
void onTimer() {
timer ++;
timerTriggered = true;
log("onTimer");
}
void setup() {
pinMode(relayPin, OUTPUT); // declare LED as output
digitalWrite(relayPin, RELAY_OFF);
pinMode(ledPin, OUTPUT); // declare LED as output
digitalWrite(ledPin, LED_OFF);
pinMode(pirPin, INPUT); // declare sensor as input
pinMode(doorPin, INPUT_PULLUP); // declare sensor as input
MsTimer2::set(INTERVAL, onTimer); // 500ms period
Serial.begin(9600);
}
void StartTimer(int begin) {
if (!timerStarted)
MsTimer2::start();
if (begin != -1)
timer = begin;
timerStarted = true;
}
void StopTimer() {
MsTimer2::stop();
timerStarted = false;
timer = 0;
}
void EnterGuardState(int begin, bool resetPIRState) {
state = GUARD;
digitalWrite(ledPin, LED_ON);
if (resetPIRState)
pirState = PIR_RESET;
StartTimer(begin);
}
void loop() {
pirVal = digitalRead(pirPin); // read PIR value
doorVal = digitalRead(doorPin); // read door value
if (doorVal != doorState) {
delay(DEBOUNCE_TIME);
doorVal = digitalRead(doorPin);
}
switch (state) {
case IDLE:
if (pirVal != pirState && pirVal == PIR_TRIGGERED) {
log("IDLE: Motion detected! goto GUARD");
EnterGuardState(0, false);
} else if (doorVal != doorState && doorVal == DOOR_OPENED) {
log("IDLE: DOOR opened, Relay on!");
digitalWrite(relayPin, RELAY_ON);
state = ALARM;
log("IDLE: goto ALARM");
}
break;
case GUARD:
if (pirVal != pirState) {
if (pirVal == PIR_TRIGGERED) {
log("GUARD: Motion detected, reset timer");
digitalWrite(ledPin, LED_ON);
timer = 0;
} else {
log("GUARD: Motion reset!");
}
} else if (doorVal != doorState && doorVal == DOOR_OPENED) {
log("GUARD: DOOR opened, goto INHIBIT");
StopTimer();
state = INHIBIT;
break;
}
// Check timeout
if (timer >= GUARD_TIMEOUT) {
digitalWrite(ledPin, LED_OFF);
StopTimer();
state = IDLE;
log("GUARD: Timeout, goto IDLE");
} else {
if (timer >= GUARD_BEGIN && timerTriggered) {
timerTriggered = false;
if (timer & 0x1)
digitalWrite(ledPin, LED_OFF);
else
digitalWrite(ledPin, LED_ON);
}
}
break;
case INHIBIT:
if (doorVal != doorState && doorVal == DOOR_CLOSED) {
log("INHIBIT: DOOR closed, goto GUARD");
EnterGuardState(GUARD_BEGIN, true);
}
break;
case ALARM:
if (doorVal != doorState && doorVal == DOOR_CLOSED) {
log("ALARM: DOOR closed, Relay off, goto GUARD");
digitalWrite(relayPin, RELAY_OFF);
EnterGuardState(GUARD_BEGIN, true);
}
break;
}
if (pirState != pirVal) {
pirState = pirVal;
log("Update pirState");
}
if (doorState != doorVal) {
doorState = doorVal;
log("Update doorState");
}
}