LoginSignup
45
48

More than 5 years have passed since last update.

Raspberry Piで監視カメラの動体検知時に電話通知

Last updated at Posted at 2016-04-08

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をインストールします

Terminal
apt-get install -y motion

motion.confを変更します

Terminal
vi /etc/motion/motion.conf
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/に画像ファイルが生成されていれば成功です

Terminal
motion -c /etc/motion/motion.conf

Slackの設定

Slackでアカウントを発行します。

SlackのAPIを利用して投稿するため、トークンとチャンネルIDを確認します。
https://api.slack.com/methods/channels.list/test

Sign Inした状態で[Test Mode]押下でトークンとチャンネルIDを取得します。

URL
https://slack.com/api/channels.list?token=<トークン>&pretty=1 
channels.list実行結果
{
    "ok": true,
    "channels": [
        {
            "id": "<チャンネルID>",
            "name": "general",
            "is_channel": true,
              :

画像のアップロード

SlackのAPIを利用して動体検知時にSlackへ自動的に画像投稿します。
まずはSlackへ投稿する箇所をつくります。

motion.py
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)

ソースファイルに実行権限を与えて適当な画像ファイルで画像投稿できるか確認します。

Terminal
chmod 755 motion.py
python motion.py <画像ファイルのPATH>

Slackで確認すると無事画像が投稿されました。

無題.png

電話通知

Asteriskが自動発信するように自動発信用のファイルを作成するようにします。

motion.py
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/ に書き込み権限を与えてファイル実行で電話着信するか確認します。

Terminal
chmod 755 motion.py
python motion.py

電話通知ON/OFF

動体検知時にSlackから get_channel_info を利用して最新の投稿を取得します。

  • 投稿のテキストが「call」だったら電話通知ONにします。
  • 投稿のテキストが「nocall」だったら電話通知OFFにします。

電話通知のON/OFF状態はConfigParserで設定ファイルを作成することで保持します。

もっとスマートなやり方があると思うのだけど、思いつかなかったので今回はこれで。

motion.py
# 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」を投稿後に、撮影されると下記のような設定ファイルが生成されれば成功です。

config.ini
[motion notify]
enable = FALSE

これらを踏まえてソースファイルを作成。

実際に動作させてみると・・・

無題2.png

カメラの前で動くだけでガンガン投稿されて、ガンガン電話がかかってくる。
もはや迷惑(笑)

「nocall」を投稿すると、Slackには写真が投稿されて電話通知はしなくなったのでこれで完成

motionやSlackに関する詳しい説明は下記を参照ください
はじめてのRaspberry PIで監視カメラを作ってみた。

所感

音声合成エンジンOpen JTalkを利用して、動体検知したら何かしゃべらせると面白そう

参考

はじめてのRaspberry PIで監視カメラを作ってみた。

45
48
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
45
48