ラズパイで見守りシステム開発その2:動体検知と通知機能の実装


こんにちは。

前回はディスプレイとキーボードがない環境でのラズパイ初期設定を行ったので、今回はいよいよ動体検知とそれを通知する機能を実装します。

3回目のリモート接続設定はこちらです。

システム概要

環境

ラズパイ:Raspberry Pi4 Model B
OS: Raspberry Pi OS(32bit)
動体検知: motion
通知システム: LINE Notify

動体検知やリアルタイムでのストリーム配信には有名ツールであるmotionを使います。コーディング無しで簡単に実装可能な素晴らしいツールです。

構成

今回実装したシステムの概要図です。動体検知は広く使われているmotionを使い、通知はLINEのAPIにリクエストするだけなのでほぼノーコードです。

カメラの接続と有効化

では作成済みのラズパイにカメラを接続します。

私が今回購入したのはこちらのカメラ

基本的に子どもが寝ている状態で使いたいので赤外線LED付きのものにしました。

カメラの有効化

……カメラをラズパイに接続した写真を撮り忘れたのですが難しいことではないので省略します。

カメラを接続したらラズパイから有効化します。VNCでラズパイに接続しPreferencesRaspberry Pi ConfigurationInterfacesと進み、CameraEnabledに変更します。その後リブートすれば、カメラの接続は完了です。

カメラの動作確認

ラズパイのコンソールを立ち上げvcgencmd get_cameraを実行します。supported,detectedが1となればOKです。

pi@raspberrypi:~$ vcgencmd get_camera
supported=1 detected=1

それではカメラを使って写真を撮ってみます。raspistillコマンドで写真を撮影して画像ファイルに保存できます。

pi@raspberrypi:~$ sudo raspistill -o image.jpg

-oで指定した名前で画像ファイルが作成されます。

motionの導入

インストール

見守りシステムの要、動体検知を行うmotionを導入します。

aptやyumリポジトリからインストールできます。(今回はapt)

pi@raspberrypi:~$ sudo apt-get install motion

motion.confの編集

見守りシステムの要です。/etc/motion/motion.confの設定内容に従って動体検知や通知を行います。

私がデフォルトから変更した部分をセクションごとに示します。

起動設定

項目 設定値 概要
daemon on motionプロセスをバックグラウンドで起動する

撮影画像に関する設定

項目 設定値 概要
width 640 保存およびストリーム配信画像の横サイズ
height 480 保存およびストリーム配信画像の縦サイズ
framerate 2 1秒あたりの撮影フレーム数

動体検知に関する設定

項目 設定値 概要
threshold 4500 動体検知する際のしきい値。
単位はpixelで、フレーム間でこれ以上のpixelが変化した場合に動体検知する。
event_gap 3 動体検知イベントの間隔。動体検知すると指定した秒数を一つのイベントとして扱うため、動体検知時に保存される動画の秒数になる。-1の場合はすべてのイベントをひとつの動画に保存する。0の場合には動体検知のたびに動画が保存される。

event_gapをデフォルト60から3にした理由ですが、後述のとおり画像で保存するフレーム指定(output_pictures)をfirstまたはbestとすると、event_gapで指定した秒数だけ画像保存が遅延するためです。

画像保存に関する設定

項目 設定値 概要
output_pictures best 動体検知時にどの画像を保存するかを設定する。
off: 保存しない
on: 全フレーム
first: 最初のフレーム
best: 最も変化が大きかったフレーム
quality 100 保存画像の画質(圧縮率)。

output_picturesがonだとフレームの数だけ通知が来てしまうので私はbestに設定しました。

ただしfirstまたはbestに設定した場合は前述のevent_gapで設定した秒数が経過しないと画像が保存されない=通知が行われないため、注意が必要です。

動画保存に関する設定

項目 設定値 概要
ffmpeg_output_movies off 動体検知時の動画保存設定。動画保存する場合はonにする。
quality 100 保存画像の画質(圧縮率)。

ffmpeg_output_moviesについて、今回はevent_gapを3にしている関係で、動体検知のたびに3秒単位の動画大量に保存されてしまうためoffとしました。

ストリーム配信に関する設定

項目 設定値 概要
stream_localhost off onの場合にはローカルホストからのみストリーム配信が確認できる
quality 100 ストリーム配信画像の画質(圧縮率)。

イベント通知に関する設定

項目 設定値 概要
on_picture_save /home/pi/motion_notify.sh %f & 動体検知で画像が保存された際に実行されるコマンド。%付きの変数が利用可能。
ちなみに%fは保存ファイルの絶対パスで、その他にいくつか動的パラメータが用意されている。

コマンドの中身は後述します。

起動時のデーモン設定

motion.conf内のdaemonとの関連性がよくわかりませんが、/etc/default/motionを以下のとおり修正して起動時のデーモン設定を有効化します。

/etc/default/motion
# set to 'yes' to enable the motion daemon
start_motion_daemon=yes

起動してみる

ここまでできたらmotionを起動して動作確認してみます。

pi@raspberrypi:~$ sudo motion

http://ラズパイIP:8081にアクセスすると、ストリーム配信で1秒ごとの撮影画像を見ることができます。

また動体検知すると指定のフォルダ(デフォルトでは/var/lib/motion)に検知時の画像ファイルが保存されています。

(おまけ)自動起動設定

ラズパイの再起動時などイチイチ手動でmotionを起動するのも面倒なのでsystemdで自動起動するように設定します。

/etc/systemd/system/motion.service
[Unit]
Description=motion
After=network.service

[Service]
Type=forking
Restart=on-success
ExecStart=motion
ExecStop=pkill motion

[Install]
WantedBy=multi-user.target
sudo systemctl enable motion

通知の実装

最後に動体検知が行われた場合にLINEに通知を行う仕組みを実装します。

LINE Notifyの登録

プログラム等からLINEに通知する簡単な方法がLINE Notifyを利用することです。LINE Notifyからの送信先を選択して登録することでAPIトークンが発行されるので、それを使ってHTTPリクエストでメッセージを飛ばせます。

LINE Notifyの登録にはLINE Notifyからログインします。

ログインしたらトップページ右上から「登録サービス管理」を選択します。

表示されたページの「トークンを発行する」をクリックします。

するとLINE Notifyでの配信先選択になるので一番上「1:1でLINE Notifyから通知を受ける」を選択して「発行する」をクリックします。これで現在ログインしているLINEアカウントにLINE Notifyからメッセージが送られます。

APIトークンが表示されるのでコピーしておきます。

HTTPのPOSTリクエストのAuthorizationヘッダにこのAPIトークンを設定すればLINEで通知を受け取れます。

motionの通知処理実装

motionにおける動体検知時の実行処理は前述のとおりmotion.conf内のon_pictures_saveで定義します。

ここに直接curlコマンドを書いてもいいのですが、今回やりたかったこととして「1分間に1回だけ通知する」というのがあります。

motion.confのトピックで書いたとおりevent_gapを3にしているため、何も考えずにLINE Notifyにリクエストを投げると最短で3秒に1回通知されてしまうためです。

これを回避するために以下のShellScriptを作りました。

/home/pi/motion_notify.sh
#!/bin/bash

ENABLE_FILE="/home/pi/send_enable"
if [ -e $ENABLE_FILE ]; then
        rm $ENABLE_FILE
        curl -X POST -H "Authorization: Bearer APIトークン" -F "message=ラズパイで動体検知したよ!http://192.168.10.21:8081" -F "imageFile=@$1" https://notify-api.line.me/api/notify
        sleep 60
        touch $ENABLE_FILE
fi

通知の本体は以下のcurlコマンドです。LINE Notifyの仕様に乗っ取り、Authorizationヘッダに先程のAPIトークンを設定、メッセージ本文には動体検知時の画像(motion.conf内の第1引数で画像ファイルの絶対パスを渡す)と、すぐにストリーム配信が確認できるようにURLを書いて送信します。

curl -X POST -H "Authorization: Bearer APIトークン" -F "message=ラズパイで動体検知したよ!http://192.168.10.21:8081" -F "imageFile=@$1" https://notify-api.line.me/api/notify

この通知を1分間に1回に抑えるように/home/pi/send_enableというファイルが存在した時だけcurlを実行するようにしています。curl実行直後に当該ファイルを削除しそのまま60秒間待機します。

動体検知のテスト

実際にmotionが動体検知すると、その時の画像を付けてLINEに通知が来るようになりました!

URLも付いているので通知が来て「おやっ?」と思ったら即座にストリーム配信も確認できます。

なお今回はご覧のとおりローカルIPのため家にいる時限定ですが、例えば外からも確認したい場合には別途対応が必要です。それは次回にしたいと思います。

ひととおりできました

ということで2回目にして見守りシステムは完成しました。ラズパイは初めてだったのですが初心者にも優しい作り、かつインターネット上にも情報がたくさんあるので問題なく作ることができました。

次回はおまけになりますが、外からも見守りシステムを使えるような設定をしてみたいと思います。

参考URL

https://www7390uo.sakura.ne.jp/wordpress/archives/250
https://www.itmedia.co.jp/news/articles/1912/01/news009.html