それをなんとか使えないかと思ったけど、面倒くさいと思ってしまった。
すごく邪道な方法で検出時の画像と動画をSlackに投稿する方法を考えた。
それは、zmの吐き出すログをイベントトリガーとするもの。
ついでに検出時に音を鳴らすようにした。
1.インストール
sudo apt-get install ffmpeg
2.ZoneMinderの画像保存先を漁るスクリプト
/usr/local/bin/Victrola4ZM.sh
sudo chown syslog Victrola4ZM.sh
これは、NanoPIの/etc/rsyslog.conf内の"$FileOwner syslog"のため
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
#Victrola For ZoneMinder (Victrola4ZM) | |
logger -p local1.info "[V4ZM] Victrola For ZoneMinder (Victrola4ZM) $1" | |
#PSOT方法設定(SELF or AMIS_SERVER) | |
POST_MODE=SELF | |
POST_CMD="/usr/local/Gillie/Post2slack.js file" | |
POST_CHANNEL=******** | |
#作業ディレクトリ設定 | |
ZMPATH=/usr/share/zoneminder/www/events/Monitor-2 | |
TMPPATH=/tmp | |
TRIGFLG=victrola.trigflg | |
#通知用LED設定 NOTFI_BLINK_CNT*NOTFI_BLINK_SEC*2が通知時間 | |
NOTFI_PORTwPI=5 | |
NOTFI_BLINK_CNT=10 | |
NOTFI_BLINK_SEC=0.1 | |
#通知用サウンド設定 | |
NOTFI_SOUND=/usr/local/etc/Victrola/blink1.mp3 | |
#動画作成用環境設定 | |
MOVIEFPS=4 | |
TRIGER_HEADER_IMG=/usr/local/etc/Victrola/img/header-img.png | |
# Slackへプッシュする | |
# $1:FPATH $2:MdyDT | |
function pushSlack() { | |
FPATH=$1 | |
MdyDT=$2 | |
#ファイル名単体取り出し | |
FNAME="${FPATH##*/}" | |
FDT_STRING=$(date -d @$MdyDT +"%Y%m%d%H%M%S") | |
logger -p local1.info "[V4ZM] Upload to Slack ($POST_MODE) $FNAME - $FDT_STRING" | |
if [ "$POST_MODE" = "SELF" ]; then | |
echo "[Upload to Slack(Self)] FileName="$FNAME | |
echo "[Upload to Slack(Self)] DateTime="$FDT_STRING | |
#channel,filename,filepath,title,text,cleanup | |
$(nodejs $POST_CMD $POST_CHANNEL $FNAME $FPATH $FNAME $SLACK_MESSAGE 'false') | |
logger -p local1.info "[V4ZM] nodejs $POST_CMD $POST_CHANNEL $FNAME $FPATH $FNAME $SLACK_MESSAGE 'false'" | |
fi | |
} | |
function blinkLED(){ | |
#検知LED点灯 | |
gpio mode $NOTFI_PORTwPI out | |
for ((i=0;i<$NOTFI_BLINK_CNT;i++)); do | |
gpio write $NOTFI_PORTwPI 0 | |
sleep $NOTFI_BLINK_SEC | |
gpio write $NOTFI_PORTwPI 1 | |
sleep $NOTFI_BLINK_SEC | |
done | |
} | |
function searchDIR(){ | |
# ディレクトリを探す | |
Cdate=$(date "+%-y/%m/%d") | |
Cwk=$(ls -altr /usr/share/zoneminder/www/events/Monitor-2/$Cdate/ | grep '^l' | tail -1) | |
set $Cwk | |
Cdir=$9 | |
ZJSEARCH=$ZMPATH/$Cdate/$Cdir/*-analyse.jpg | |
ZJPATH=$(ls -tr $ZJSEARCH | head -1) | |
MdyDT=$(stat -c %Y $ZJPATH) | |
} | |
function prepare_video(){ | |
SECONDS=0 | |
# 検出時の赤画像 | |
convert $ZJPATH -resize 160x120 $WKDIR/${ZJPATH##*/}.mpc | |
ls -tr $ZMPATH/$Cdate/$Cdir/*-capture.jpg | while read line | |
do | |
convert $line -background black -extent 320x360 $WKDIR/${line##*/}.mpc | |
APATH=${line//-capture/-analyse} | |
if [ -e $APATH ]; then | |
convert $APATH -resize 160x120 $WKDIR/${APATH##*/}.mpc | |
#元画像 | |
#赤枠画像 | |
#解析画像 の順 | |
convert $WKDIR/${line##*/}.mpc \ | |
$WKDIR/${ZJPATH##*/}.mpc -gravity northwest -geometry +0+240 -compose over -composite \ | |
$WKDIR/${APATH##*/}.mpc -gravity northwest -geometry +160+240 -compose over -composite \ | |
$TRIGER_HEADER_IMG -gravity northwest -geometry +0+240 -compose over -composite \ | |
$WKDIR2/${line##*/} | |
else | |
convert $WKDIR/${line##*/}.mpc \ | |
$WKDIR/${ZJPATH##*/}.mpc -gravity northwest -geometry +0+240 -compose over -composite \ | |
$TRIGER_HEADER_IMG -gravity northwest -geometry +0+240 -compose over -composite \ | |
$WKDIR2/${line##*/} | |
fi | |
done | |
# 終了待ち | |
#wait | |
time=$SECONDS | |
logger -p local1.info "[V4ZM] SET Processing time=$time" | |
} | |
function prepare_video3(){ | |
#1.リサイズ | |
logger -p local1.info "[V4ZM] Resize and Extent Image=$ZMPATH/$Cdate/$Cdir/*-*.jpg" | |
#処理時間計測開始 | |
SECONDS=0 | |
ls -tr $ZMPATH/$Cdate/$Cdir/*-capture.jpg | while read line | |
do | |
APATH=${line//-capture/-analyse} | |
if [ -e $APATH ]; then | |
#アナライズ画像リサイズ | |
convert $APATH -resize 160x120 $WKDIR/${APATH##*/} & | |
fi | |
convert $line -background black -extent 320x360 $WKDIR/${line##*/} & | |
done | |
#終了待ち | |
wait | |
time=$SECONDS | |
logger -p local1.info "[V4ZM] Resize and Extent Processing time=$time" | |
#2.検出画像 ファイル名のみ取得しWKと結合する | |
SECONDS=0 | |
ZJPATH=$WKDIR/${ZJPATH##*/} | |
# 検出時の赤画像 | |
convert $ZJPATH -resize 160x120 $WKDIR/${ZJPATH##*/} | |
#3.静止画作成 | |
ls -tr $WKDIR/*-capture.jpg | while read line | |
do | |
#echo $line | |
#logger -p local1.info "[V4ZM] Synthesis Image=$line" | |
APATH=${line//-capture/-analyse} | |
if [ -e $APATH ]; then | |
convert $line \ | |
$ZJPATH -gravity northwest -geometry +0+240 -compose over -composite \ | |
$APATH -gravity northwest -geometry +160+240 -compose over -composite \ | |
$TRIGER_HEADER_IMG -gravity northwest -geometry +0+240 -compose over -composite \ | |
$WKDIR2/${line##*/} & | |
else | |
convert $line \ | |
$ZJPATH -gravity northwest -geometry +0+240 -compose over -composite \ | |
$TRIGER_HEADER_IMG -gravity northwest -geometry +0+240 -compose over -composite \ | |
$WKDIR2/${line##*/} & | |
fi | |
done | |
#終了待ち | |
wiat | |
time=$SECONDS | |
logger -p local1.info "[V4ZM] Synthesis Processing time=$time" | |
} | |
#スタートの通知 | |
if [ $1 = "start" ]; then | |
#flag on | |
touch $TMPPATH/$TRIGFLG | |
#サウンド再生 | |
logger -p local1.info "[V4ZM] mpg123 $NOTFI_SOUND" | |
mpg123 $NOTFI_SOUND& | |
#検知LED点灯 | |
blinkLED& | |
#ディレクトリを探す | |
searchDIR | |
#検出した静止画(赤線あり)を送信する | |
SLACK_MESSAGE=":home:ZM検出画像" | |
logger -p local1.info "[V4ZM] TriggerImage=$ZJPATH" | |
pushSlack $ZJPATH $MdyDT | |
exit 0 | |
fi | |
#検知LED点灯 | |
gpio mode $NOTFI_PORTwPI out | |
gpio write $NOTFI_PORTwPI 1 | |
# ディレクトリを探す | |
searchDIR | |
# 記録された静止画を動画に結合して送信する | |
#0.作業用ディレクトリ作成 | |
WKDIR=$TMPPATH/$Cdir | |
WKDIR2=$TMPPATH/$Cdir"2" | |
mkdir $WKDIR | |
mkdir $WKDIR2 | |
# | |
prepare_video3 | |
#4.動画化 | |
SECONDS=0 | |
ZJSEARCH=$WKDIR2/%05d-capture.jpg | |
ZMNAME=$(date -d @$MdyDT +"%Y-%m-%d_%H-%M-%S") | |
ZJPATH=$WKDIR2/$ZMNAME.mp4 | |
logger -p local1.info "[V4ZM] Create Video=$ZJPATH" | |
ffmpeg -r $MOVIEFPS -i $ZJSEARCH -vcodec h264 -y -f mp4 $ZJPATH | |
time=$SECONDS | |
logger -p local1.info "[V4ZM] Create Video Processing time=$time" | |
#5.slackに通知 | |
SLACK_MESSAGE=":home:ZM検出動画" | |
logger -p local1.info "[V4ZM] Movie=$ZJPATH" | |
pushSlack $ZJPATH $MdyDT | |
#6.後片付け | |
rm -rf $WKDIR | |
rm -rf $WKDIR2 | |
#flag off | |
rm -f $TMPPATH/$TRIGFLG | |
#検知LED消灯 | |
gpio write $NOTFI_PORTwPI 0 |
これはSlackAPIのトークンが含まれるためowner(=syslog)以外参照させないchmod 700
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Post2slack.js | |
var request = require('request'); | |
var fs = require('fs'); | |
var slackApiKey = '********'; | |
var slackurl = "https://slack.com/api/chat.postMessage"; | |
var slackurlTest = "https://slack.com/api/auth.test"; | |
var slackurlFile = "https://slack.com/api/files.upload"; | |
//ヘッダーを定義 | |
var headers = { | |
'Content-Type':'application/x-www-form-urlencoded' | |
} | |
console.log(process.argv.length); | |
if(process.argv.length >= 3){ | |
if(process.argv[2]=="text"){ | |
//テキストの投稿 | |
//channel,emoji,pretext,color,title,text | |
if(process.argv.length == 9){ | |
channel = process.argv[3]; | |
emoji = process.argv[4]; | |
pretext = process.argv[5]; | |
color = process.argv[6]; | |
title = process.argv[7]; | |
text = process.argv[8]; | |
//attachments | |
var att = { | |
'pretext' :emoji+pretext, | |
'fallback':pretext, | |
'color' :color, | |
'title' :title, | |
'text' :text | |
} | |
//オプションを定義 | |
var options = { | |
url : slackurl, | |
method : 'POST', | |
headers: headers, | |
form: { | |
'token' :slackApiKey, | |
'channel' :'#'+channel, | |
'as_user' :'true', | |
'attachments':JSON.stringify([att]) | |
} | |
} | |
//リクエスト送信 | |
console.log(att); | |
request(options, function (error, response, body) { | |
//コールバック | |
if (!error && response.statusCode == 200) { | |
console.log(body); | |
}else{ | |
console.log('error: '+ response.statusCode); | |
} | |
}); | |
}else{ | |
console.log("引数が必要:channel,emoji,pretext,color,title,text"); | |
} | |
}else if(process.argv[2]=="test"){ | |
//auth.test | |
//オプションを定義 | |
var options = { | |
url : slackurlTest, | |
method : 'POST', | |
headers: headers, | |
form: { | |
'token' :slackApiKey | |
} | |
} | |
//リクエスト送信 | |
request(options, function (error, response, body) { | |
//コールバック | |
if (!error && response.statusCode == 200) { | |
console.log(body); | |
}else{ | |
console.log('error: '+ response.statusCode); | |
} | |
}); | |
}else if(process.argv[2]=="file"){ | |
//ファイルのアップロード | |
//channel,filename,filepath,title,text,cleanup | |
if(process.argv.length == 9){ | |
channel = process.argv[3]; | |
filename= process.argv[4]; | |
filepath= process.argv[5]; | |
title = process.argv[6]; | |
text = process.argv[7]; | |
cleanup = process.argv[8]; | |
//オプションを定義 | |
var options = { | |
url : slackurlFile, | |
method : 'POST', | |
formData: { | |
'token' :slackApiKey, | |
'channels' :'#'+channel, | |
'filename' :filename, | |
'file' :fs.createReadStream(filepath), | |
'title' :title, | |
'initial_comment' : text | |
} | |
} | |
//リクエスト送信 | |
console.log(options); | |
request(options, function (error, response, body) { | |
//コールバック | |
if (!error && response.statusCode == 200) { | |
// console.log(body); | |
var jbody = JSON.parse(body); | |
console.log(jbody); | |
if(cleanup.toLowerCase()=="true"){ | |
//ファイルを削除する | |
fs.unlinkSync(filepath); | |
} | |
}else{ | |
console.log('error: '+ response.statusCode); | |
} | |
}); | |
}else{ | |
console.log("引数が必要:channel,filename,filepath,title,text,cleanup"); | |
} | |
} | |
}else{ | |
console.log("err:引数が不足している"); | |
} |
/etc/rsyslog.d/Victrola4ZM.conf
sudo systemctl restart rsyslog
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
if ( $msg contains 'Monitor-2' ) and ( $msg contains 'alarm start' ) then action(type="omprog" binary="/usr/local/bin/Victrola4ZM.sh start") | |
if ( $msg contains 'Monitor-2' ) and ( $msg contains 'alarm end' ) then action(type="omprog" binary="/usr/local/bin/Victrola4ZM.sh end") |
usermod -aG audio syslog
5.実行結果