raspberry pi でカメラ自動撮影&自動送信アプリを作る
子供の写真を自動で返してもらう
みなさんご存知のraspberry piで遊んでみました。 今回はこのバージョンでの動作確認を行ってます。
Raspberry Pi3 Model B ボード&ケースセット 3ple Decker対応 (Clear)-Physical Computing Lab
- 出版社/メーカー: TechShare
- メディア: エレクトロニクス
- この商品を含むブログ (4件) を見る
最近子供が産まれたのですが、 仕事中に子供の写真で癒やされたいため、 リアルタイムな写真が欲しいところです。
そんなアプリを作ってみました。
処理の流れ
lineのbotとか使ってみたのですが、管理が意外とめんどかったので、 レガシーなgmailを使ってみました。
ざっくりとこんな流れ
- 私がメールで写真を撮れと、司令する(gmailに)
- raspberry pi が gmailのメールを受信する
- 送信元アドレスをチェックして、送っていいか確認する
( 知らん人からメールが来ても送らないようにする)
- 送っちゃ行けない場合は処理終了
- 送っていい場合は4へ
- 写真を撮影する
- 撮った写真を添付して送信アドレスに返す
1だけが私の処理で、2-5がraspberry pi 側の処理ですね。
準備(ほぼ割愛)
さて、今回はこのカメラを使用しました。
Raspberry Pi Official Camera V2 for 3B/2B/B+/A+/B/A ソニー製808万画素CMOSセンサ使用 ラズベリーパイ公式 HDカメラ
- 出版社/メーカー: きばん本舗
- メディア: エレクトロニクス
- この商品を含むブログを見る
差込口等で迷うこともないし、 OS等も入っていててpython3も入っている前提で。
撮影モジュール作成
さて、なんにしてもカメラで撮影できるようにならなければ始まりません。 python3で撮影するための関数を用意しました。
# カメラ撮影関数 import RPi.GPIO as GPIO import subprocess import os import sys import datetime def shotPicture(): d = datetime.datetime.today() filename = "{0}{1:02d}{2:02d}{3:02d}{4:02d}{5:02d}.jpg".format(d.year, d.month, d.day, d.hour, d.minute, d.second) args = ['raspistill', '-o', filename, '-t', '1'] subprocess.Popen(args) return filename
ちょこっと解説すると、 raspberry piのOS側のコマンド(つまりshellコマンド)で、
raspistill -o ${任意のfilename} -t 1
と打つと撮影できるので、 このコマンドをpython側から実行します。 そのためのpythonの関数が
subprocess.Popen(args)
です。 argsに実行したいコマンドの中身をリスト形式で渡せばOKです。 撮影した写真のファイル名はYYYYMMDDHHMMSS.jpgにしました。
これで
file = shotPicture()
すれば、写真を撮影した上、撮影したファイル名がfile変数に格納されます。
メールの送受信
今回はメールの受信と送信モジュールが必要なので、こちらも関数で用意します。 受信についてはメールの本文は不要で、送ってきたメールアドレスだけが必要なので、
- gmailにログイン
- 新着メール有無チェック
- 新着メールがあったらメールアドレスを返す(ただし重複は弾く)
で行きます。
# メール受信 import imaplib, re, email, six def recieveGmail(s,u,p): # s=server,u=username,p=password client = imaplib.IMAP4_SSL(s) client.login(u,p) # 受信箱指定 client.select('INBOX') # 未読メールをメモリに格納(この時点で既読になる) typ, [data] = client.search(None, "(UNSEEN)") # ない場合は空のcuesリストを返す # 未読メールがあったか確認 cues = [] if typ == "OK": if data != b'': print("new mail(s)") # メールを一件ずつ処理 for num in data.split(): result, d = client.fetch(num, "(RFC822)") raw_email = d[0][1] #文字コード取得用 msg = email.message_from_string(raw_email.decode('utf-8')) fromObj = email.header.decode_header(msg.get('From')) for f in fromObj: cue = "" if isinstance(f[0],bytes): cue = f[0].decode('utf-8') else: cue = str(f[0]) cue = re.search(r'<(.+)>',cue) cue = cue.group(0).replace("<","").replace(">","") cues.append(cue) client.close() client.logout() return cues
特に解説はいらないですよね?(私もよくわかっていないだけ) ネットのコードを切った張った修正した、だけですが、これで
reply_address = recieveGmail(s,u,p)
すればreplay_addressにリスト形式でメールアドレスを返してくれます。
続いて送信側
# メール送信 import gmail def sendGmail(u,p,t,s,b,a): #u=user,p=pass,t=to_addr,s=subject,b=body,a=attachment client = gmail.GMail(u, p) if a == '': message = gmail.Message(s,to=t,text=b) else: message = gmail.Message(s,to=t,text=b,attachments=[a]) client.send(message) client.close()
こちらは添付ファイル有りなしで分岐がありますが、ただメールを送るだけです。
全部繋げる
あとはこれで完成
# -*- coding: utf-8 -*- import os import sys import gmail from time import sleep import RPi.GPIO as GPIO from time import sleep import subprocess import datetime import imaplib, re, email, six # カメラ撮影関数 def shotPicture(): d = datetime.datetime.today() filename = "{0}{1:02d}{2:02d}{3:02d}{4:02d}{5:02d}.jpg".format(d.year, d.month, d.day, d.hour, d.minute, d.second) args = ['raspistill', '-o', filename, '-t', '1'] subprocess.Popen(args) return filename # メール送信 def sendGmail(u,p,t,s,b,a): #u=user,p=pass,t=to_addr,s=subject,b=body,a=attachment client = gmail.GMail(u, p) if a == '': message = gmail.Message(s,to=t,text=b) else: message = gmail.Message(s,to=t,text=b,attachments=[a]) client.send(message) client.close() # メール受信 def recieveGmail(s,u,p): # s=server,u=username,p=password client = imaplib.IMAP4_SSL(s) client.login(u,p) # 受信箱指定 client.select('INBOX') # 未読メールをメモリに格納(この時点で既読になる) typ, [data] = client.search(None, "(UNSEEN)") # ない場合は空のcuesリストを返す # 未読メールがあったか確認 cues = [] if typ == "OK": if data != b'': print("new mail(s)") # メールを一件ずつ処理 for num in data.split(): result, d = client.fetch(num, "(RFC822)") raw_email = d[0][1] #文字コード取得用 msg = email.message_from_string(raw_email.decode('utf-8')) fromObj = email.header.decode_header(msg.get('From')) for f in fromObj: cue = "" if isinstance(f[0],bytes): cue = f[0].decode('utf-8') else: cue = str(f[0]) cue = re.search(r'<(.+)>',cue) cue = cue.group(0).replace("<","").replace(">","") cues.append(cue) client.close() client.logout() return cues # gmail定義 username = 'アカウント名@gmail.com' password = 'パスワード' server = 'imap.gmail.com' # 返信するホワイトリスト定義 whitelist = ['返信する','パスワード','のリスト','hogehoge@gmail.com'] while True: cues = recieveGmail(server,username,password) cues = list(set(cues)) if cues == []: sleep(2) else: print(cues) for addr in cues: if addr in whitelist: sendGmail(username,password,addr,'かしこまり','ちょっと待ってね','') pictpass = shotPicture() sleep(3) sendGmail(username,password,addr,'はいどうぞ','いかが?',pictpass)
これを適当に名前をつけて(app.pyとか)保存し、
python3 app.py
すればおk。