This project monitors two garage doors. On the LCD screen you can see the last movements of your doors. When a door opens or closes the movements are logged. A door that is not completely opened or stays open for to long triggers an alarm.
Alarms are sent by SMS.
Using one (for security reasons) other mobile number, it is possible to send a command to open or close a door. Only acceptable commands are processed (close when door is open or open when door is closed).
SMS is used as a communication system as this is more secure as a plain internet connection. In order to check the door state proximity magnetic switches are used. Of course those can be replaced by microswitches.
(The protoshield on the left of the arduino replaces the breadboard)
/*
Pin configuration
D0
D1
D2 GSM
D3 GSM
D4
D5
D6
D7
D8 close door1
D9 close door2
D10
D11
D12
D13
A0 D14 Upper door1
A1 D15 Lower door1
A2 D16 Upper door2
A3 D17 Lower door2
A4 D18 clock
A5 D19 clock
*/
//Library for LCD
#include <LiquidCrystal_I2C.h>
//Library for Clock
#include <Wire.h>
#include "RTClib.h"
//Library for GSM
#include <SoftwareSerial.h>
#include <SerialGSM.h>
DS1307 rtc;
SerialGSM cell(2,3);
// initialize the library with the i2c adress and chars and lines
LiquidCrystal_I2C lcd(0x3F,20,4);
const byte Doors = 2;//number of doors to manage
const byte Lines = 2;//number of lines on the lcd
const byte Chars = 16;//number of characters on the lcd
const long int ClosingTrigger = 60000;//time before an alarm is triggered
const long int ClosingTime = 20000;//time needed to close the door !!Measure this time for your door!!
static const uint8_t PinsIn[] = {14,15,16,17};//Array of pins used to minitor the doors
static const uint8_t PinsOut[] = {8,9};//Array of pins used to control the doors
char GSMNum[13]="+XXXXXXXXXXX"; // telephone number to send sms
String ValidAction;//used to check if incomming sms is valid
String PrevMessage01;//used to move the LCD message one line
String PrevMessage02;//used to move the LCD message one line
String PrevMessage03;//used to move the LCD message one line
byte PrevLine = 1; //previous used line on the LCD
byte UpperSensor[Doors];
byte PrevUpperSensor[Doors];
byte LowerSensor[Doors];
byte PrevLowerSensor[Doors];
char DoorState[Doors];//M=movement, O=open, C=Closed
byte x=0;//for loop trough number of doors. We start at 0 because list numbering starts at 0
byte DoorToActivate;//door that has to be activated extracted from SMS
long int StartMillis[Doors];//remember the starttime of the not closed timer
bool TimerStarted[Doors];//remember if the not closed timer has been started for a given door
bool SMSsend[Doors];//remember if a SMS has been send
void setup() {
//start LCD
lcd.init();
lcd.backlight();
// Print a message to the LCD.
lcdmessage("LCD Booted", 1);
// init clock
Wire.begin();
rtc.begin();
if (! rtc.isrunning()) {
lcdmessage("RTC is NOT running!", 1);
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(__DATE__, __TIME__));
}
//loop trough the inputs. 2 inputs for each door
for(byte y=0;y<2*Doors;y++)
{
pinMode(PinsIn[y],INPUT);
}
//loop trough the outputs. 1 output for each door
//reset timers voor each door
for(byte y=0;y<Doors;y++)
{
pinMode(PinsOut[y],OUTPUT);
//In order to work with a relay module HIGH is Normal Open
digitalWrite(PinsOut[y], HIGH);
StartMillis[y]=0;
TimerStarted[y]=0;
SMSsend[y]=0;
}
Serial.begin(9600);
//setup GSM shield
cell.begin(9600);
//for debug cell.Verbose(true);
lcdmessage("Booting GSM", 1);
cell.Boot();
cell.FwdSMS2Serial();
cell.DeleteAllSMS();
lcdmessage("GSM Booted", 1);
}
void loop() {
if (x < Doors)
{
//check uppersensors and compare to previous state
PrevUpperSensor[x] = UpperSensor[x];
UpperSensor[x] = digitalRead(PinsIn[(2*x)]);
if (!(PrevUpperSensor[x] == UpperSensor[x]))
{
MakeMessage(x, 'U');
}
//check lowersensors and compare to previous state
PrevLowerSensor[x] = LowerSensor[x];
LowerSensor[x] = digitalRead(PinsIn[(2*x)+1]);
if (!(PrevLowerSensor[x] == LowerSensor[x]))
{
MakeMessage(x, 'L');
}
//Start timer if door not closed else reset timers
if (!(DoorState[x] == 'C'))
{
CheckTimer(x);
}
else
{
TimerStarted[x] = 0;
StartMillis[x]=0;
SMSsend[x]=0;
}
x= x+1;
}
else
{
x=0;//reset doornumber in order to restart the checking cycle
}
//process incomming SMS messages
if (cell.ReceiveSMS())
{
//check if number is valid
String SMSSender=cell.Sender();
SMSSender.remove(12);
String ValidSender=GSMNum;
if (SMSSender == ValidSender)
{
//retrieve DoorToActivate from SMSMessage
String SMSMessage=cell.Message();
lcdmessage(SMSMessage, 1);
SMSMessage.remove(1);
DoorToActivate=SMSMessage.toInt();
switch (DoorState[DoorToActivate-1])
{
case 'C':
ValidAction="Open";
break;
case 'O':
ValidAction="Close";
break;
}
SMSMessage=cell.Message();
SMSMessage.substring(2);
if (SMSMessage.substring(2) == ValidAction)
{
ActivateDoor(DoorToActivate);
}
else
{
lcdmessage("No Valid action", 10);
}
//delete all SMS messages
cell.DeleteAllSMS();
SMSsend[DoorToActivate-1]=0;
}
else
{
lcdmessage("Wrong number", 10);
}
}
}
//make message for logging if doorstate has changed.
void MakeMessage(byte door, char location)
{
String message = "D";
message.concat(door+1);
switch (location)
{
case 'U':
if (PrevUpperSensor[door] < UpperSensor[door])
{
message.concat(" = O ");
DoorState[door]='O';
}
else
{
message.concat(" > C ");
DoorState[door]='M';
}
break;
case 'L':
if (PrevLowerSensor[door] < LowerSensor[door])
{
message.concat(" = C ");
DoorState[door]='C';
}
else
{
message.concat(" > O ");
DoorState[door]='M';
}
break;
}
DateTime now = rtc.now();
char buf[100];
strncpy(buf,"hh:mm:ss\0",100);
message.concat(now.format(buf));
lcdmessage(message, 1);
}
//Check if timer has started for a door and if trigger has been reached, then send SMS
void CheckTimer(byte door)
{
if (TimerStarted[door] == 0)
{
TimerStarted[door]=1;
StartMillis[door]=millis();
}
else
{
if ((millis()-StartMillis[door] > ClosingTrigger) && (SMSsend[door] == 0))
{
Warning(door);
// Wait till door normally should be closed
delay (ClosingTime);
}
}
}
//Creates a message and sends it by SMS
void Warning(byte door)
{
//create the message
char txtMsg[100];
String SMSMessage = "Door ";
SMSMessage.concat(door+1);
SMSMessage.concat(" is not closed.");
SMSMessage.toCharArray(txtMsg,100);
//send the message
sendSMS(GSMNum, txtMsg);
SMSsend[door]=1;
}
//Sends a SMS message to a number
void sendSMS(char num[13], char msg[100])
{
cell.DeleteAllSMS();
cell.Rcpt(num);
lcdmessage(msg, 1);
cell.Message(msg);
cell.SendSMS();
}
//Activate a door in order to close or open. Action is always the same.
//HIGH is normal mode LOW is activated state
void ActivateDoor(byte door)
{
Serial.print("Digital out to low : ");
Serial.println(PinsOut[door-1]);
String Message = "Activate D";
Message.concat(door);
lcdmessage(Message, 1);
digitalWrite(PinsOut[door-1], LOW);
delay(2000);
digitalWrite(PinsOut[door-1], HIGH);
}
//shows a message on the LCD screen
void lcdmessage(String message, byte visible)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print(PrevMessage03);
lcd.setCursor(0,1);
lcd.print(PrevMessage02);
lcd.setCursor(0,2);
lcd.print(PrevMessage01);
lcd.setCursor(0,3);
lcd.print(message);
PrevMessage03 = PrevMessage02;
PrevMessage02 = PrevMessage01;
PrevMessage01 = message;
delay(visible*1000);
}
Comments