如果你想做一个报警系统,目的恐怕再明确不过了------你不想让孩子爬上橱柜或是冰箱偷东西吃,也不想其他人偷开你的锁柜。当然啦,可能你会想给偷吃食物的宠物拍张照片。或者,你想学学美剧《办公室》里Dwight Schrute所扮演的角色,看看是谁把同事的工作材料换成了果冻。那么问题来了,你该怎么做呢?
是的,你可以在橱柜/冰箱/锁柜里放上一个设备,一旦它监测到有动静,就会拍一张照片然后发送到你的电子邮件里。还有如果你会IFTTT(让互联网为你服务)的话,甚至可以自动把那些“小偷们”的照片发到社交媒体上,让全世界看看他们的脸。
首先,让我们先来欣赏一下小哥浮夸的演技:
这个报警系统项目,由一个运动传感器(PIR),一个摄像头,以及一个支持无线Wi-Fi连接设备组成。笔者选择了Arduino Yún,因为它非常易于使用,还能轻松配置无线Wi-Fi,而且如果你想换成RaspberryPi,也很容易。当然啦,如果你使用RaspberryPi的话,Wi-Fi配置可能会略微麻烦一些,因为它必须要连接到一台计算机上才能进行配置操作,而使用Arduino Yún就相对轻松多了,任何人都可以在上面直接配置。这个报警系统项目其实非常简单,即便你没有什么焊接/电气方面的技巧,也能在几分钟时间里轻松完成组装。废话不多说,赶紧来看看怎么做吧。
第一步 Arduino基本配置
首先,你需要配置自己的Arduino Yún网络设置,如果你按照教程一步步操作,其实非常简单。 点击查看教程.
如果一切操作正常,打开SSH会话。
默认密码是:“arduino”。
然后,让我们来安装一些有用的软件包
$opkg update
$opkg install openssh-sftp-server
那么,为什么要安装“openssh-sftp-server”呢?因为这个软件包可以让你从Arduino上面轻松上传或下载文件。现在,你可以使用一个通用的SFTP客户端,比如filezilla,transmit,或是cyberduck等等,这样就不用输入麻烦的SCP命令来进行文件传输了。
然后,为了兼容Python,我们还需要安装一个SSL支持包(感谢***kirby!)。因为在默认软件包里,并没有包含这个软件支持包。
$opkg update
$opkg install python-openssl
笔者墙裂推荐你可以在Arduino Yún上插一个SD卡(如果你有一个的话),Arduino Yún设备会自动分配文件路径,地址是mnt/sda1。
然后,我们要在Arduino Yún上面安装USB摄像头和USB声卡。
第二步 安装并测试USB摄像头
通过opkg套件管理系统,已经有支持Linino的UVC软件包了,因此安装摄像头可以说是非常简单的一个步骤。是需要通过ssh连接到Yún上面,然后输入:
$ opkg update
$ opkg install kmod-video-uvc
就可以了。
不过我们还需要一个可以拍照片的软件,笔者使用过一款容量极小,但又非常便于使用的拍照软件fswebcam,按照如下命令,安装即可。
$ opkg install fswebcam
第三步 拍摄你的第一张照片
首先要确保你使用了SD卡作为存储,否则Arduino内存会很快就被耗尽。好了,如果你正在使用SD存储卡的话,你应该已经能够看到它的安装路径地址了/mnt/sda1.如果你还没有使用,那么请将FAT32格式的SD卡插入到设备的SD卡插槽里面,并重启你的Arduino设备。
现在,请把摄像头插进设备的USB端口,然后输入:
$ cd /mnt/sda1
$ fswebcam test.png
如果一切正常的话,你现在就能拍摄自己的第一张照片啦!注意看看你的SD卡里的内容哦,:)
这意味着,现在我们可以通过Yún’s Bridge库,在自己的Arduino设备里面拍照片,按照下面这种操作方式就能实现:
Process.runShellCommand("fswebcam /mnt/sda1/test.png");
第四步 安装声卡
在Yún上打开一个ssh会话,然后输入:
$opkg install kmod-u***-audio
$opkg install madplay
完成安装之后,现在Arduino Yún设备就有了声卡支持了。笔者只尝试了下MP3格式的音乐播放,还没有自己录制一些音频,但是很快就会去尝试下!
如果想要测试一下声卡效果,其实也非常简单,你只需在SD卡里复制一个MP3音频文件,然后输入:
$cd /mnt/sda1
$madplay yoursound.mp3
这意味着现在我们可以通过Yún’s Bridge库,在Arduino设备里面播放声音了,按照下面这种操作方式就能实现:
Process.runShellCommand("madplay /mnt/sda1/test.mp3");
第五步 电子邮件脚本
现在,我们的监控设备可以拍照片并且支持播放声音….但是我们还想要更多功能!我们想让这款设备能通过电子邮件发送文件。
所以,我们该怎么做呢?答案其实非常简单….一个python脚本就能搞定!Arduino Yún整合了Temboo库,笔者想让这个监控系统更加具有兼容性,因此我们会使用一个非常简单的python脚本编码图像文件,并通过电子邮件发送出去。
笔者选择的电子邮箱是Gmail,但是这个代码脚本其实可以选择任何支持SMTP服务器的电子邮箱。
你可以创建一个新文件,称之为“sendemail.py”,然后把下面这段代码复制进去,
# coding=utf-8
# Copyright (C) 2014 Stefano Guglielmetti # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
import smtplib, os, sys
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders
#From address, to address, subject and message body
from_address = 'FROM_ADDRESS@EMAIL.COM'
to_address = ['YOUR_ADDRESS@EMAIL.COM']
email_subject = 'Alert!!! Zombies!!! Ahead!!!'
email_body = 'A non dead intruder has been detected and needs to be eliminated!'
# Credentials (if needed)
username = 'EMAIL_LOGIN'
password = 'EMAIL_PASSWORD'
# The actual mail send
server = 'smtp.gmail.com:587'
def send_mail(send_from, send_to, subject, text, files=[], server="localhost"):
assert type(send_to)==list
assert type(files)==list
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = COMMASPACE.join(send_to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach( MIMEText(text) )
for f in files:
part = MIMEBase('application', "octet-stream")
part.set_payload( open(f,"rb").read() )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(f))
msg.attach(part)
smtp = smtplib.SMTP(server)
smtp.starttls()
smtp.login(username,password)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.close()
send_mail(from_address, to_address, email_subject, email_body, [sys.argv[1]], server) #the first command line argument will be used as the image file name
现在,你需要把相关电子邮件设置做下改动,如下
#From address, to address, subject and message body
from_address = 'FROM_ADDRESS@EMAIL.COM'
to_address = ['YOUR_ADDRESS@EMAIL.COM']
email_subject = 'Alert!!! Zombies!!! Ahead!!!'
email_body = 'An undead intruder has been detected and needs to be eliminated!'
# Credentials (if needed)
username = 'EMAIL_LOGIN'
password = 'EMAIL_PASSWORD'
# The actual mail send
server = 'smtp.gmail.com:587'
接下来,你可以通过SFTP(或是SCP,如果你喜欢的话)把这段脚本文件上传到Arduino Yún的SD卡里,然后再次打开SSH会话,输入下面这段命令:
$cd /mnt/sda1
$python sendemail.py test.png
几秒钟之后,你就会收到一封电子邮件,附件就是Arduino Yún拍摄的照片,是不是很神奇!
别担心,这一个步骤其实也是非常简单的。你根本用不着焊接什么材料,所有部件都能靠组装完成。笔者使用了这款PIR传感器,是因为它即可靠,又方便使用。你可以参照下图来进行相关操作:
我们已经连上了这个PIR传感器。如果监控系统设备发现了一些动作,上面的LED灯就会打开。
第七步 现在是时候加上Arduino Sketch了
在Arduino IDE上复制下面这段代码,然后上传到你的Yún上:
*
* Switches a LED, takes a picture and sends it via email
* according to the state of the sensors output pin.
* Determines the beginning and end of continuous motion sequences.
*
* @author: Stefano Guglielmetti / stefano (at) mikamai (dot) com / http://jeko.net * @date: feb 5, 2014
*
* based on the example by Kristian Gohlke / krigoo (_) gmail (_) com / http://krx.at *
* stefano guglielmetti (cleft) 2014
*
* released under a creative commons "Attribution-NonCommercial-ShareAlike 2.0" license
*
*
* The Parallax PIR Sensor is an easy to use digital infrared motion sensor module.
*
* The sensor's output pin goes to HIGH if motion is present.
* However, even if motion is present it goes to LOW from time to time,
* which might give the impression no motion is present.
* This program deals with this issue by ignoring LOW-phases shorter than a given time,
* assuming continuous motion is present during these phases.
*
*/
#include
/////////////////////////////
//VARS
//the time we give the sensor to calibrate (10-60 secs according to the datasheet)
int calibrationTime = 10;
//the time when the sensor outputs a low impulse
long unsigned int lowIn;
//the amount of milliseconds the sensor has to be low
//before we assume all motion has stopped
long unsigned int pause = 5000;
boolean lockLow = true;
boolean takeLowTime;
int pirPin = 6; //the digital pin connected to the PIR sensor's output
int ledPin = 13;
Process p;
String imageName;
/////////////////////////////
//SETUP
void setup(){
Bridge.begin();
Serial.begin(9600);
pinMode(pirPin, INPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(pirPin, LOW);
//give the sensor some time to calibrate
Serial.print("calibrating sensor ");
for(int i = 0; i < calibrationTime; i++){
Serial.print(".");
delay(1000);
}
Serial.println(" done");
Serial.println("SENSOR ACTIVE");
delay(50);
}
////////////////////////////
//LOOP
void loop(){
if(digitalRead(pirPin) == HIGH){
digitalWrite(ledPin, HIGH); //the led visualizes the sensors output pin state
if(lockLow){
//makes sure we wait for a transition to LOW before any further output is made:
lockLow = false;
Serial.println("---");
Serial.print("motion detected at ");
Serial.print(millis()/1000);
Serial.println(" sec");
imageName = uniqueFileName("png"); //generate a new, uniqe file name
p.runShellCommand("fswebcam /mnt/sda1/" + imageName); //takes the picture
while(p.running()); //wait till the process ends
p.runShellCommand("madplay /mnt/sda1/sounds/sirena.mp3"); //play the siren sound
while(p.running()); //wait till the process ends
p.runShellCommand("python /mnt/sda1/sendemail.py /mnt/sda1/" + imageName); //sends the picture via email
while(p.running()); //wait till the process ends
delay(50);
}
takeLowTime = true;
}
if(digitalRead(pirPin) == LOW){
digitalWrite(ledPin, LOW); //the led visualizes the sensors output pin state
if(takeLowTime){
lowIn = millis(); //save the time of the transition from high to LOW
takeLowTime = false; //make sure this is only done at the start of a LOW phase
}
//if the sensor is low for more than the given pause,
//we assume that no more motion is going to happen
if(!lockLow && millis() - lowIn > pause){
//makes sure this block of code is only executed again after
//a new motion sequence has been detected
lockLow = true;
Serial.print("motion ended at "); //output
Serial.print((millis() - pause)/1000);
Serial.println(" sec");
delay(50);
}
}
}
/* A simple function to generate unique timestamp based filenames */
String uniqueFileName(String ext){
String filename = "";
p.runShellCommand("date +%s");
while(p.running());
while (p.available()>0) {
char c = p.read();
filename += c;
}
filename.trim();
filename += "." + ext;
return filename;
}
十秒钟之后(校准时间),就将开始工作,并拍摄照片了!!!
一切搞定!下面这张照片,就是组装完成后的效果图。在GitHub上,有这个项目的详细文档。
14