RaspberryPi 人感センサーからカメラ撮影してメール送信しちゃう

ラズベリーパイで遊ぶ

少し前に買って放置されていたRaspberryPi で遊んでみました。
人感センサーをつけて、反応したらカメラ撮影してそのままGmail使ってメールを投げます。

パーツを揃える

  • ラズパイ:Raspberry Pi Model B+ (Plus)
  • ラズパイカメラ:Raspberry Pi Video Module Raspberry Pi Camera Board 775-7731
  • 人感センサー: 焦電型赤外線(人感)センサーモジュール SB412A





接続する

接続はこんな感じ。

f:id:skymay:20171211134750p:plain
接続

センサーはジャンパーケーブルで直接接続しました。5V,GPIO4,GROUND
f:id:skymay:20160904105849j:plain

f:id:skymay:20171209111656j:plain


人感センサーのデータシートはここ
焦電型赤外線(人感)センサーモジュール SB412A: センサ一般 秋月電子通商 電子部品 ネット通販
ラズパイのGPIO配置はここ。
GPIO: Models A+, B+, Raspberry Pi 2 B and Raspberry Pi 3 B - Raspberry Pi Documentation




設定する

まずは、ソフトウェアを諸々アップデートします。
いろいろバグとかでハマっても面倒なので。

#パッケージアップデート
$> sudo apt-get update
$> sudo apt-get upgrade
#アプリケーションのアップデート
$> sudo rpi-update


cameraを有効化

sudo rspi-config

enable cameraでenableにします。


センサーの設定GPIO4に指しているので、export設定をします。
センサーに反応があるとgipo4のvalueファイルに1、反応がなくなると0が出力されます。

$sudo echo 25 > /sys/class/gpio/export
$cd /sys/class/gpio/gpio4
$sudo echo in > direction

動作確認

センサーでうまく値が入ってくるか確認します。
カメラの動作もとりあえずコマンドで単体チェックします。

$raspistill -o test.jpg

スクリプトを書く

gpioのvalueを確認して1が入っていた場合はカメラで写真をとってメール送信します。
メールがたくさん送られてきても面倒なので、sleep入れて少し止めています。

from __future__ import print_function
import socket
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(4, GPIO.IN)
from contextlib import closing

import time
import picamera
import datetime
import smtplib
import threading
from email import Encoders
from email.Utils import formatdate
from email.MIMEBase import MIMEBase
from email.Header import Header
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.mime.image import MIMEImage


def main():
    while True:
        inputValue = GPIO.input(4)
        if (inputValue == True):
            filename=capture()
            send(filename)
            time.sleep(300)
        time.sleep(1)
            
def send(file):
    img = [file]
    send_email_img('no_reply@gmail.com', '******@gmail.com', u'Alert', u'Alert\n', img)

def send_email_img(from_addr, to_addr, subject, body, imgs=[], server='smtp.gmail.com', port=587):
    encoding='utf-8'
    msg = MIMEMultipart()
    mt = MIMEText(body.encode(encoding), 'plain', encoding)

    if imgs:
        for fn in imgs:
            img = open(fn, 'rb').read()
            mj = MIMEImage(img, 'png', filename=fn)
            mj.add_header("Content-Disposition", "attachment", filename=fn)
            msg.attach(mj)
        msg.attach(mt)
    else:
        msg = mt

    msg['Subject'] = Header(subject, encoding)
    msg['From'] = from_addr
    msg['To'] = to_addr
    msg['Date'] = formatdate()
    
    ADDRESS = "******@gmail.com"
 
    _user =  "*************************"
    _pass = "************************* "


    smtp = smtplib.SMTP(server, port)
    smtp.ehlo()
    smtp.starttls()
    smtp.ehlo()
    smtp.login(_user, _pass)
    smtp.sendmail(from_addr, [to_addr], msg.as_string())
    smtp.close()
     
                
def capture():
    camera = picamera.PiCamera()
    camera.hflip = True
    camera.vflip = True
    camera.resolution = (480,360)
    now = datetime.datetime.now()
    fmt_name = "pic_{0:%Y%m%d-%H%M%S}.png".format(now)
    time.sleep(2)
    camera.capture(fmt_name)
    time.sleep(2)
    camera.close()
    return fmt_name
    
if __name__ == '__main__':
    main()

他のサイトでcamera.close()の記載がないところがありますが、これないとエラーで止まります。
キャプチャ取り忘れたんですが、Out of resourcesとかOut of memory とかその辺のエラーだった気がします。

写真をとって貯め続けるので、容量注意してください。
メールで送られるので上書きでも良いかも。

最終動作テスト

スクリプトを起動して、メールが受信されるか確認します。

まとめ

ハード部分は全然詳しくないのですが、いろいろなサイトを参考にしながら、意外に簡単にできました。
Web経由で再起動、ストリーミング操作機能とかをつけてもおもしろいかもしれない。ラズパイ可能性は無限大ですね。
いずれは自宅警備を格安ラズパイロボットへ。