Projektityö: Varashälytin Arduinolla
Categories:
[school]
Tags:
[arduino],
[prototyping-course]
Prototyypin rakentaminen-kurssin projektityönä minulla on varashälytin, joka liikkeen sekä oven avaamisen. Se kerää lokitiedostoa tietokoneelle ja lähettää hälytyksen sähköpostitse jos hälytys laukeaa.
Laitteeseen on kytketty näyttö, josta näkee tilatietoa varashälyttimen tilasta. Laitteessa on myös RFID-lukija, jolla varashälytin aktivoidaan ja deaktivoidaan.
Arduinon pinnijärjestys
Arduinon lähes kaikki digitaalipinnit ovat käytössä. Seuraavassa lista pinneistä ja mihin ne on kytketty:
- 2: LCD pin D7
- 3: LCD pin D6
- 4: LCD pin D5
- 5: LCD pin D4
- 6: Vihreä led
- 7: Magneettikytkimen signaalijohto
- 8: Liiketunnistimen signaalijohto
- 9: Piezo
- 10: iButton RFID-lukija
- 11: LCD pin Enable
- 12: LCD pin RS
- 13: Punainen Led
Arduinon ohjelmalogiikka
Varashälyttimen toimintalogiikka Arduinossa on jaettu SchedulerARMAVR-kirjaston avulla kahteen looppiin, joista toinen tarkkailee RFID-lukijaa sekä ohjaa näyttöä, ja toinen joka tarkkailee magneettisensoria ja liiketunnistinta.
Varashälytin tarkkailee jatkuvasti sensoreita, mutta ilmoittaa tapahtumista näytöllä vain “Armed”-tilassa. Sarjaportin yli tapahtumia kirjataan jatkuvasti hälytyksen tilasta riippumatta.
Kun hälytin kytketään “Armed”-tilaan, Arduino tarkkailee magneettikytkintä ja liiketunnistinta. Jos liikettä havaitaan tai ovi on auki yli 10 sekunnin ajan(toteutuksessa on havaittu ettei aikaraja aina täsmää jos liike ei ole jatkuvaa), hälytys laukeaa joka ilmoitetaan äänimerkillä, näytöllä sekä sarjaportin ylitse tietokoneelle. Aikaraja näkyy näytön oikeassa yläreunassa. Hälytyksen voi kuitata vain oikealla RFID-tunnisteella tai painamalla Arduinon Reset-painiketta.
varashalytin_final.ino:
#include <SchedulerARMAVR.h>
#include <LiquidCrystal.h>
#include <OneWire.h>
/*
Varashälytinohjelma, joka tarkkailee liikettä
ja magneettikytkintä ja hälyttää niistä sarja-
portin ylitse.
Author: Joni Junni
Date: 13.5.2013
*/
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int redLedPin = 13;
int greenLed = 6;
int pirPin = 8;
int magnetPin = 7;
int pirState = LOW;
int val = 0;
int i = 0;
int sensorPin = 0;
int alertTimer = 10;
boolean armedState;
boolean magnetState;
boolean motionState;
boolean alarmConfirmed;
// Piezo stuff
int NOTEg = 2550; // 392 Hz
int NOTEC = 1912; // 523 Hz
int NOTER = 0; // REST-note
int speakerOut = 9;
int melody[] = {NOTEC, NOTEg};
int beats[] = {16, 16};
int MAX_COUNT = sizeof(melody) / 2; // Melody length, for looping.
long tempo = 10000;
int rest_count = 100;
int tone_ = 0;
int beat = 0;
long duration = 0;
void playTone() {
long elapsed_time = 0;
if (tone_ > 0) { // if this isn't a Rest beat, while the tone has
// played less long than 'duration', pulse speaker HIGH and LOW
while (elapsed_time < duration) {
digitalWrite(speakerOut,HIGH);
delayMicroseconds(tone_ / 2);
digitalWrite(speakerOut, LOW);
delayMicroseconds(tone_ / 2);
elapsed_time += (tone_);
}
}
else { // Rest beat; loop times delay
for (int j = 0; j < rest_count; j++) { // See NOTE on rest_count
delayMicroseconds(duration);
}
}
}
// RFID Stuff
OneWire ds(10); // iButton reader pin
byte addr[8]; // Data read from the iButton reader
int but[6] = {
195,133,181,20,0,0}; // Allowed RFID-authentication button
String keyStatus="";
void setup() {
Serial.begin(9600);
pinMode(redLedPin, OUTPUT);
pinMode(greenLed, OUTPUT);
pinMode(magnetPin, INPUT);
pinMode(pirPin, INPUT);
pinMode(speakerOut, OUTPUT);
lcd.begin(16, 2);
armedState = false; // Used for setting system state
motionState = false; // Used for detecting motion state
magnetState = false; // Used for detecting door state
alarmConfirmed = false; // Used to reset triggered alarm
Scheduler.startLoop(loop2); // Starts additional loop function
}
void loop() {
// Check for auth key button
getKeyCode();
if(armedState == false) {
lcd.clear();
lcd.print("SYSTEM:DISARMED");
}
else {
if(alertTimer == 0 && alarmConfirmed == false) {
lcd.clear();
lcd.print("ALARM TRIGGERED!");
lcd.setCursor(0, 1);
lcd.print("EMAIL SENT!");
} else {
lcd.clear();
lcd.print("SYSTEM:ARMED ");
lcd.print(alertTimer);
if(motionState == true) {
lcd.setCursor(0, 1);
lcd.print("MOTION DETECTED");
}
if(magnetState == true) {
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print("DOOR OPEN");
}
}
}
Scheduler.delay(1000); // Poll every second
}
void loop2() {
checkPirSensor();
checkMagnetSensor();
Scheduler.delay(1000);
yield();
}
void checkPirSensor() {
val = digitalRead(pirPin);
// Motion detected
if (val == HIGH) {
motionState = true;
if(armedState == true) {
if(alertTimer > 0) {
alertTimer = alertTimer - 1;
}
else {
Serial.println("ALARM");
// Trigger alarm
triggerAlarm();
}
blinkAlertLed();
}
Serial.println("P");
}
else {
// Send a signal to serial port that motion has stopped
if(motionState == true) {
Serial.println("PS");
}
motionState = false;
}
}
void checkMagnetSensor() {
val = digitalRead(magnetPin);
// Magnet switch is open (Door is open)
if (val == HIGH) {
//lcd.clear();
lcd.setCursor(0, 1);
magnetState = true;
if(armedState == true) {
if(alertTimer > 0) {
alertTimer = alertTimer - 1;
}
else {
// Trigger alarm
Serial.println("ALARM");
triggerAlarm();
}
blinkAlertLed();
}
Serial.println("M");
}
else {
// Send a signal to serial port that door has been closed
if(magnetState == true) {
Serial.println("MS");
}
magnetState = false;
}
}
void checkLogin() {
// If key button format is ok
if(keyStatus=="ok"){
/*
byte i;
for( i = 5; i >0; i--) {
Serial.print(" : ");
Serial.print(addr[i], DEC);
}
Serial.println();
*/
// Check if user is authorized
if(addr[1] == but[0] && addr[2] == but[1] && addr[3] == but[2] && addr[4] == but[3]) {
FlashGreenLed();
Serial.println("AU");
if(armedState == false) {
setArmed();
}
else {
setDisarmed();
}
if(alarmConfirmed == false && alertTimer == 0) {
alarmConfirmed = true;
}
}
else {
Serial.println("UU");
blinkAlertLed();
}
}
}
void getKeyCode(){
keyStatus="";
// If there is nothing to read, stop and return
if ( !ds.search(addr)) {
ds.reset_search();
return;
}
keyStatus="ok";
checkLogin();
ds.reset();
}
void blinkAlertLed() {
// Blink the alert led
for(i=0;i<5;i++) {
digitalWrite(redLedPin, HIGH);
Scheduler.delay(200);
digitalWrite(redLedPin, LOW);
Scheduler.delay(200);
}
}
void FlashGreenLed() {
digitalWrite(greenLed, HIGH);
Scheduler.delay(1500);
digitalWrite(greenLed, LOW);
}
void setArmed() {
Serial.println("A");
armedState = true;
alertTimer = 10; // Reset alert timer
alarmConfirmed = false;
}
void setDisarmed() {
Serial.println("D");
armedState = false;
}
void triggerAlarm() {
// Set up a counter to pull from melody[] and beats[]
while(alarmConfirmed == false) {
for (int i=0; i<MAX_COUNT; i++) {
tone_ = melody[i];
beat = beats[i];
duration = beat * tempo; // Set up timing
playTone();
Scheduler.delay(1);
}
}
}
Sarjaporttikommunikaatio tietokoneen kanssa
Varashälytin kommunikoi tietokoneen kanssa sarjaportin yli lokitiedoston kirjoittamista sekä varoitusviestin lähettämistä varten. Määritin varashälyttimen koodiin seuraavanlaiset komennot jota se voi tietokoneelle lähettää:
- P: Liiketunnistin havaitsee liikettä
- M: Ovi on auki (magneettikytkin)
- AU: Sallittu käyttäjä tunnistautunut (RFID)
- UU: Ei-sallittu käyttäjä tunnistautunut (RFID)
- A: Hälytin Armed-tilassa
- D: Hälytin Disarmed-tilassa
- ALARM: Hälytys on lauennut
- MS: Ovi on sulkeutunut (magneettikytkin)
- PS: Liiketunnistin ei havaitse enää liikettä
Tietokoneen päässä on python-ohjelma kuuntelemassa sarjaporttia ja se suorittaa komentoja sen mukaan mitä varashälytin sille syöttää. Ohjelma hoitaa tapahtumien kirjoittamisen lokiin sekä sähköpostivaroituksen lähettämisen jos hälytys laukeaa.
varashalytin.py:
#!/usr/bin/env python
#coding: utf8
# Ohjelma joka kuuntelee varashälyttimen sarjaporttia
# ja suorittaa komentoja sen mukaan mitä hälytin käskee
# Author: Joni Junni
# Date: 13.5.2013
import serial
import time
import smtplib
ser1 = serial.Serial("/dev/tty.usbmodem1421")
while True:
try:
line = ser1.readline()
#print(line)
timestamp = time.asctime( time.localtime(time.time()) )
if line.find('ALARM') !=-1:
message = timestamp + ': ALARM WAS TRIGGERED'
sender = 'arduinohalytys@gmail.com'
receivers = ['joni.junni@me.com']
emailmsg = """From: Arduino Alert <arduinohalytys@gmail.com>
To: Joni Junni <joni.junni@me.com>
Subject: Alert was triggered!
Your home might be intruded.
"""
try:
smtpObj = smtplib.SMTP('smtp.gmail.com', 587)
smtpObj.ehlo()
smtpObj.starttls()
smtpObj.ehlo()
smtpObj.login('arduinohalytys','Trolololo')
smtpObj.sendmail(sender, receivers, emailmsg)
print "Successfully sent email"
except smtplib.SMTPException:
print "Error: unable to send email"
elif line.find('UU') !=-1:
message = timestamp + ': Unauthorized user tried to log in'
elif line.find('AU') !=-1:
message = timestamp + ': Authorized user has been logged'
elif line.find('MS') !=-1:
message = timestamp + ': Door was Closed'
elif line.find('PS') !=-1:
message = timestamp + ': Motion stopped'
elif line.find('P') !=-1:
message = timestamp + ': Motion detected'
elif line.find('M') !=-1:
message = timestamp + ': Door Open'
elif line.find('A') !=-1:
message = timestamp + ': System Armed'
elif line.find('D') !=-1:
message = timestamp + ': System Disarmed'
f = open('alertLog.log','a')
f.write(message + '\n')
print message
except (serial.serialutil.SerialException, OSError):
pass
Lähteet
- Python Date & Time (http://www.tutorialspoint.com/python/python_date_time.htm)
- Python Errors & Exceptions (http://docs.python.org/2/tutorial/errors.html#exceptions)
- Arduino SchedulerARMAVR-kirjasto (http://arduino.cc/forum/index.php?topic=142101.0)
- Arduino – Scheduler Reference (http://arduino.cc/en/Reference/Scheduler)
- Joni Junni: RFID-sensori Arduinolla (http://www.junni.org/2013/04/prototyypin-rakentaminen-rfid-sensori-arduinolla/)
- Suvi Kiviniemi: Arduino-testailuja: iButton (http://suvikiviniemi.com/skivinie/arduino-testailuja-ibutton/)
- The iButton garage-door opener (http://www.instructables.com/id/The-iButton-garage-door-opener-Arduino/)
- Joni Junni: LCD-näytöt ja sarjaporttiliikenne (http://www.junni.org/2013/04/prototyypin-rakentaminen-lcd-naytot-ja-sarjaporttiliikenne/)
- Arduino Playground – OneWire (http://playground.arduino.cc/Learning/OneWire)