GeekFactory

int128.hatenablog.com

motionイベントのトラップ送信スクリプト

motionとZabbixによる監視カメラシステム - GeekFactory では、監視カメラの動きを検出した時にZabbixにトラップを送信する仕組みを紹介しました。

動き検出にmotionというデーモンを利用しています。motionは動きを検出した場合に任意のスクリプトを実行できます。今回は4つのイベントを使います:

  • on_event_start
    • Command to be executed when an event starts. An event starts at first motion detected after a period of no motion defined by gap.
  • on_event_end
    • Command to be executed when an event ends after a period of no motion. The period of no motion is defined by option gap.
  • on_motion_detected
    • Command to be executed when a motion frame is detected.
  • on_camera_lost
    • Command to be executed when a camera can't be opened or if it is lost.

イベントが発生すると指定したスクリプトが実行され、画像の変化量などを受け取れます。測定値をZabbixでグラフ化する場合、変化がない間は測定値が存在しないことに注意が必要です。例えば、8時に変化量10、17時に変化量100であった場合、グラフは (8, 10)-(17, 100) を結ぶ直線になります。この場合、8時から17時の間は変化がないので変化量0で描画したいため、一工夫します。

on_event_startでは動き検出の起点が得られます。動きを検出した時点をT、変化量をDとすると、以下の測定値を出力すると、立ち上がりのグラフが描けます:

時刻
T - 60秒*1 0
T D

この考え方でスクリプトを書き直してみました。

#!/bin/bash
#
# motion-zabbix-sender
#
# Specify this script in motion.conf:
#   on_event_start     /usr/local/bin/motion-zabbix-sender %s on_event_start %D %i %J
#   on_event_end       /usr/local/bin/motion-zabbix-sender %s on_event_end
#   on_motion_detected /usr/local/bin/motion-zabbix-sender %s on_motion_detected %D %i %J
#   on_camera_lost     /usr/local/bin/motion-zabbix-sender %s on_camera_lost
#
SENDER="/usr/bin/zabbix_sender"
SENDER_OPTIONS="-z xxx.xxx.xxx.xxx -p 10051"
ARGS="$*"
function send_traps () {
  ${SENDER} ${SENDER_OPTIONS} -T -i - "$@" || logger -t motion "could not send trap: $ARGS"
}
timestamp="$1"
trigger="$2"
shift 2

case "$trigger" in
'on_event_start')
timestamp_previous="$(($timestamp - 60))"
send_traps << EOF
$HOSTNAME motion.is_alive $timestamp 1
$HOSTNAME motion.changed $timestamp $1
$HOSTNAME motion.changed $timestamp_previous 0
$HOSTNAME motion.area $timestamp $(($2 * $3))
$HOSTNAME motion.area $timestamp_previous 0
EOF
;;

'on_event_end')
send_traps << EOF
$HOSTNAME motion.is_alive $timestamp 1
$HOSTNAME motion.changed $timestamp 0
$HOSTNAME motion.area $timestamp 0
EOF
;;

'on_motion_detected')
send_traps << EOF
$HOSTNAME motion.is_alive $timestamp 1
$HOSTNAME motion.changed $timestamp $1
$HOSTNAME motion.area $timestamp $(($2 * $3))
EOF
;;

'on_camera_lost')
send_traps << EOF
$HOSTNAME motion.is_alive $timestamp 0
EOF
;;

*)
echo 'invalid argument'; exit 1;;
esac

*1:できるだけ短い方がよい。60秒より短くしたらグラフがおかしくなったので、とりあえず60秒にしています。