Raspberry Piを監視カメラとして動かすのは定番ですが
動体検知時に指定した番号へ電話通知するものはなかったのでつくってみました。
#仕様
- motionを利用して動体検知を行う
- 動体検知時に撮影してSlackへ自動投稿
- Slackへ投稿するついでに指定番号に電話をかけて知らせる
- Slackに着信ON/OFFとなる投稿。電話で通知してほしい時に着信させる
用途としては・・
自宅に子供が帰っきたことを動体検知して電話着信。
↓
「お?電話がきた」。Slackで子供の姿を確認
↓
着信OFFをSlackに投稿して動体検知しても着信させない
#環境
- Raspberry Pi Model B
- Raspbian (Kernel version 3.18)
- Asterisk 13.5.0
- Python 2.6.6
カメラは LOGICOOL ウェブカム HD画質 120万画素 C270(Amazon) を使用。
#手順
##Asteriskの設定
Asteriskの設定は下記を参考
Raspberry PiとAsteriskでIP電話システムの構築(その1)
Raspberry PiとAsteriskでIP電話システムの構築(その2)
##motionの設定
motionをインストールします
apt-get install -y motion
motion.confを変更します
vi /etc/motion/motion.conf
# Threshold for number of changed pixels in an image that
# triggers motion detection (default: 1500)
#threshold 1500
threshold 8000 #写真を撮影するトリガとなるしきい値を上げます
:
# Target base directory for pictures and films
# Recommended to use absolute path. (Default: current working directory)
target_dir /tmp/motion #撮影した画像の保存先を設定します
:
#撮影時にmotion.pyファイルを実行します。パラメータの%fは撮影したファイルPATH
on_picture_save python /home/hasuo/motion/motion.py %f
motionを実行して、カメラが動体検知して/home/tmp/に画像ファイルが生成されていれば成功です
motion -c /etc/motion/motion.conf
##Slackの設定
Slackでアカウントを発行します。
SlackのAPIを利用して投稿するため、トークンとチャンネルIDを確認します。
https://api.slack.com/methods/channels.list/test
Sign Inした状態で[Test Mode]押下でトークンとチャンネルIDを取得します。
https://slack.com/api/channels.list?token=<トークン>&pretty=1
{
"ok": true,
"channels": [
{
"id": "<チャンネルID>",
"name": "general",
"is_channel": true,
:
##画像のアップロード
SlackのAPIを利用して動体検知時にSlackへ自動的に画像投稿します。
まずはSlackへ投稿する箇所をつくります。
TOKEN = '<トークン>'
CHANNEL = '<チャンネルID>'
# slack API : files.upload
# 参考:https://api.slack.com/methods/files.upload
####
def upload_file(file_path, channel):
with open(file_path,'rb') as f:
param = {'token':TOKEN, 'channels':CHANNEL,}
r = requests.post("https://slack.com/api/files.upload", params=param,files={'file':f})
if __name__ == "__main__":
arg = sys.argv
file_path = arg[1]
upload_file(file_path, CHANNEL)
ソースファイルに実行権限を与えて適当な画像ファイルで画像投稿できるか確認します。
chmod 755 motion.py
python motion.py <画像ファイルのPATH>
Slackで確認すると無事画像が投稿されました。
##電話通知
Asteriskが自動発信するように自動発信用のファイルを作成するようにします。
TOKEN = '<トークン>'
CHANNEL = '<チャンネルID>'
CALLFILE_DIR = '<自動発信ファイルディレクトリ>'
CALLFILE_NAME = 'auto_call.call' # 自動発信ファイル名
OUTGOING_DIR = '/var/spool/asterisk/outgoing/'
# 自動発信ファイル生成 -> outgoing
####
def outgoing_call():
file_str = '''#
Channel: SIP/<通知したい電話番号>@<外線発信するセクション名>
MaxRetries: 0 # コール回数は1回
RetryTime: 60 # 再度コールするまでの待ち時間(秒)
WaitTime: 30 # 30秒間コールする
Context: <extensions.confに沿ったContext設定>
Extension: <extensions.confに沿ったExten設定>
Priority: 1'''
file = open(CALLFILE_DIR +CALLFILE_NAME, "w")
file.writelines(file_str);
file.close()
os.chmod(CALLFILE_DIR + CALLFILE_NAME, 0755)
shutil.move(CALLFILE_DIR + CALLFILE_NAME, OUTGOING_DIR)
if __name__ == "__main__":
outgoing_call()
ソースファイルに実行権限、/var/spool/asterisk/outgoing/ に書き込み権限を与えてファイル実行で電話着信するか確認します。
chmod 755 motion.py
python motion.py
##電話通知ON/OFF
動体検知時にSlackから get_channel_info を利用して最新の投稿を取得します。
- 投稿のテキストが「call」だったら電話通知ONにします。
- 投稿のテキストが「nocall」だったら電話通知OFFにします。
電話通知のON/OFF状態はConfigParserで設定ファイルを作成することで保持します。
もっとスマートなやり方があると思うのだけど、思いつかなかったので今回はこれで。
# coding:utf-8
import sys
import os
import shutil
import pprint
import urllib
import urllib2
import json
import ConfigParser
TOKEN = '<トークン>'
CHANNEL = '<チャンネルID>'
CALL_NOTIFY_START_STR = 'call'; # 電話通知ON判定文字列
CALL_NOTIFY_END_STR = 'nocall'; # 電話通知OFF判定文字列
INIFILE_PATH = 'config.ini' # 設定ファイル
SECTION = 'motion notify'
# slack API : channels.info
# 参考:https://api.slack.com/methods/channels.info
####
def get_channel_info():
url = "https://slack.com/api/channels.info"
params = {'token' : TOKEN,
'channel': CHANNEL,
}
params = urllib.urlencode(params)
req = urllib2.Request(url)
req.add_header('Content-Type', 'application/x-www-form-urlencoded')
req.add_data(params)
res = urllib2.urlopen(req)
body = res.read()
result = json.loads(body)
return result
# 電話通知ON/OFF設定
# slack_last_text : slackから受信した最新の投稿のテキスト部分
####
def set_call_notify(slack_last_text):
config = ConfigParser.SafeConfigParser()
if not config.has_section(SECTION):
config.add_section(SECTION)
# 設定ファイルの内容取得
try :
config.read(INIFILE_PATH)
ini_set = config.get(SECTION,'enable')
except Exception as e:
ini_set = 'FALSE'
if slack_last_text == CALL_NOTIFY_START_STR:
config.set(SECTION, 'enable', 'TRUE')
ini_set = 'TRUE'
elif slack_last_text == CALL_NOTIFY_END_STR:
config.set(SECTION, 'enable', 'FALSE')
ini_set = 'FALSE'
else:
config.set(SECTION, 'enable', ini_set)
config.write(open(INIFILE_PATH, 'w'))
return ini_set
if __name__ == "__main__":
channnels_info = get_channel_info()
is_call = set_call_notify(channnels_info['channel']['latest']['text'])
print is_call
Slackで「callon」「calloff」を投稿後に、撮影されると下記のような設定ファイルが生成されれば成功です。
[motion notify]
enable = FALSE
これらを踏まえてソースファイルを作成。
実際に動作させてみると・・・
カメラの前で動くだけでガンガン投稿されて、ガンガン電話がかかってくる。
もはや迷惑(笑)
「nocall」を投稿すると、Slackには写真が投稿されて電話通知はしなくなったのでこれで完成
motionやSlackに関する詳しい説明は下記を参照ください
はじめてのRaspberry PIで監視カメラを作ってみた。
#所感
音声合成エンジンOpen JTalkを利用して、動体検知したら何かしゃべらせると面白そう