Raspberry Pi Zero 2 Wは 4コアなので、並列処理した方が速くなる為、本体プログラムと bluetooth のチェックを分けた。
【メイン処理】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
#!/bin/bash export PATH=/home/noizumi/bin:$PATH GPIO=26 GPIO_DIR=/sys/class/gpio MOTION_MOVIE_DIR=/ramdisk/motion/detected MOTION_PID=/ramdisk/motion/motion.pid MOTION_STOP=/ramdisk/motion.stop GPS_BASE=/ramdisk/gps_base GPS_LATLON=/home/noizumi/bin/gpslatlon.sh GPS_LIMIT=100 initialize(){ # GPIO26を有効化。プルアップ抵抗ON echo $GPIO >${GPIO_DIR}/export sleep 0.1 echo in >${GPIO_DIR}/gpio${GPIO}/direction sleep 0.1 echo high >${GPIO_DIR}/gpio${GPIO}/direction } shutdown_handler(){ # GPIOクリーンアップ echo $GPIO >$GPIO_DIR/unexport if [ "${BT_CHECK_PID}" != "" ]; then kill -TERM ${BT_CHECK_PID} fi motion_stop exit 0 } # 車載警報装置が発報したら、メールで通知する mail_send(){ cat << _EOD_|/usr/sbin/sendmail -t -f yuji@noizumi.org From: yuji@noizumi.org To: yuji@noizumi.org Subject: Car Security alert $1 Car Security alarm was $1 at `date +"%Y/%m/%d %H:%M:%S"` $2 _EOD_ } # 車載警報装置が発報したら、twilio で携帯電話にSMSを送る sms_send(){ # 通常のSMS送信は、電話番号を購入して月額約164円払わねばならないが、 # Verify だと電話番号買わなくていいので、固定費が発生しない。 # # 通知内容は「あなたの車載警報装置 認証コード:123456」みたいな内容だが # 警報が発報した事が分かればよい。 curl -X POST \ https://verify.twilio.com/v2/Services/[twilio Service SID]/Verifications \ --data-urlencode "To=[わしの電話番号]" \ --data-urlencode "Channel=sms" \ -u [twilio Account SID]:[twilio Auth Token] } # 車載警報装置は、発報するとイヤホンマイクスイッチをONにする # イヤホンマイク信号を GPIO 26で検知して、発報時の処理 button_pushed(){ motion_start mail_send activated sms_send activated # ボタンが押されている間、ループ while [ "`cat ${GPIO_DIR}/gpio${GPIO}/value`" = "0" ]; do sleep 1 done mail_send stopped sms_send stopped } # 動体検知スタート motion_start(){ MOTION_STATUS=`curl -s http://localhost:8080/0/detection/status |grep "Detection status"` PATTERN=".*Detection status PAUSE" if [[ $MOTION_STATUS =~ $PATTERN ]]; then curl -s http://localhost:8080/0/detection/start >/dev/null 2>&1 fi if [ ! -e ${GPS_BASE} ]; then GPS_NOW=`${GPS_LATLON}` if [ "${GPS_NOW}" != "" ]; then echo "${GPS_NOW}" > ${GPS_BASE} GPS_SAVE=${GPS_NOW} fi fi } # 動体検知ストップ motion_stop(){ MOTION_STATUS=`curl -s http://localhost:8080/0/detection/status |grep "Detection status"` PATTERN=".*Detection status ACTIVE" if [[ $MOTION_STATUS =~ $PATTERN ]]; then curl -s http://localhost:8080/0/detection/pause >/dev/null 2>&1 fi if [ -e ${GPS_BASE} ]; then rm -f ${GPS_BASE} || true fi } # bluetooth チェックは別処理にし、ファイルの有無で状態を判断する bluetooth_check(){ # bluetooth 接続状態確認 if [ -e ${MOTION_STOP} ]; then # 接続してたら、動体検知止める motion_stop else # 接続してなかったら、動体検知スタート motion_start fi } # GPSで移動距離チェック # 警戒モードONの時、GPSの位置を gps_base ファイルに記録し、 # 以後、100m以上移動毎に現在位置をメール送信 gps_check(){ if [ "`ls /dev/gps* 2>/dev/null`" != "" ]; then if [ -e ${GPS_BASE} ]; then GPS_NOW=`${GPS_LATLON}` if [ "${GPS_NOW}" != "" ] && [ "${GPS_SAVE}" != "" ]; then DISTANCE=`distance.sh ${GPS_SAVE} ${GPS_NOW}` if [ "`echo \"${DISTANCE}>${GPS_LIMIT}\"|bc`" = "1" ]; then GPS_BASE_VALUE=`cat ${GPS_BASE}` TOTAL_DISTANCE=`distance.sh ${GPS_BASE_VALUE} ${GPS_NOW}` mail_send "GPS Warning! ${TOTAL_DISTANCE}m moved." "https://maps.google.com/maps?q=${GPS_NOW}" fi fi GPS_SAVE=${GPS_NOW} else GPS_LIMIT=100 fi fi } # メイン処理スタート initialize trap shutdown_handler 1 2 3 15 bt_check.sh & BT_CHECK_PID=$! # motion を daemon モードで起動 if [ ! -e ${MOTION_PID} ]; then mkdir -p ${MOTION_MOVIE_DIR} motion -b fi # pulseaudo 起動確認 if [ "`ps ux|grep -e \"${USER}.*pulseaudio\"|grep -v grep`" = "" ]; then pulseaudio --start sudo systemctl restart bluetooth.service fi while :; do bluetooth_check # 車載警報装置が発報した時 if [ "`cat ${GPIO_DIR}/gpio${GPIO}/value`" = "0" ]; then button_pushed fi gps_check sleep 1 done |
【bluetoothチェック処理】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
#!/bin/bash # bluetooth 接続による動体検知OFF用 BTMAC=XX:XX:XX:XX:XX:XX # OpenRun Pro by Shokz BTKEY=XX:XX:XX:XX:XX:XX # AB Shutter3 FILE_MOTION_STOP=/ramdisk/motion.stop BTKEY_ACTIVATE=0 # bluetoothテザリング用 BTPAN=XX:XX:XX:XX:XX:XX # ASUS_X01BDA # bluetooth テザリングしてなかったらnmcliで接続する function bt_tethering_check(){ # bluetooth 接続状態確認 PATTERN="[\s\S]*?${BTPAN}" if [[ ! $CONNECTED =~ $PATTERN ]]; then sudo nmcli dev connect ${BTPAN} fi } # bluetooth ヘッドフォンが接続してたら、警戒モードOFF function bt_headphone_check(){ # bluetooth 接続状態確認 PATTERN="[\s\S]*?${BTMAC}" if [[ $CONNECTED =~ $PATTERN ]]; then if [ ! -e ${FILE_MOTION_STOP} ]; then # 接続してたら、動体検知止める touch ${FILE_MOTION_STOP} fi else # 接続してなかったら、動体検知スタート rm -f ${FILE_MOTION_STOP} fi } # AB Shutter3 接続状態確認 # triggerhappy に本体再起動、本体電源OFFを定義してある function bt_abshutter_check(){ # 接続してたら triggerhappy再起動 PATTERN="[\s\S]*?${BTKEY}" if [[ $CONNECTED =~ $PATTERN ]]; then if [ "${BTKEY_ACTIVATE}" != "1" ]; then BTKEY_ACTIVATE=1 sudo systemctl restart triggerhappy.service fi else BTKEY_ACTIVATE=0 fi } # bluetoothの接続は並列でチェック # 同じ処理を複数実行しても意味が無いので、各処理終了を待つ。 function bluetooth_connect(){ declare -a pids=() bt_tethering_check & pids+=($!) bt_headphone_check & pids+=($!) bt_abshutter_check & pids+=($!) for pid in ${pids[@]}; do wait $pid done } while :; do # bluetooth 接続状態を取得 CONNECTED=`hcitool con` bluetooth_connect sleep 1 done |
【GPS関連処理】
1 2 3 |
#!/bin/sh # gpspipe で位置情報行を抜き出して、「[緯度],[経度]」で出力する timeout 2 /usr/bin/gpspipe -w -n 10 | /bin/grep -E "\"TPV\",.*\"lat\":.*\"lon\":" | /bin/sed -r 's/.*"lat":([^"]*),"lon":([^"]*),.*/\1,\2/' | /usr/bin/head -1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#!/bin/bash # 2つの緯度経度情報からメートル単位の距離を算出する。 START=(${1//,/ }) END=(${2//,/ }) cat << _EOD_|bc -l scale=20 pole_radius=6356752.314245 /* 極半径 */ equator_radius=6378137.0 /* 赤道半径 */ pi=4*a(1)/180 start_lat=${START[0]}*pi start_lon=${START[1]}*pi end_lat=${END[0]}*pi end_lon=${END[1]}*pi diff_lat=start_lat-end_lat diff_lon=start_lon-end_lon avg_lat=(start_lat+end_lat)/2 /* 平均緯度 */ e2=(equator_radius^2-pole_radius^2)/equator_radius^2 /* 第一離心率^2 */ w=sqrt(1-e2*(s(avg_lat)^2)) m=equator_radius*(1-e2)/(w^3) n=equator_radius/w distance=sqrt((m*diff_lat)^2+(n*diff_lon*c(avg_lat))^2) scale=2 distance/1 _EOD_ |
今までは USBテザリングで通信していたが、セキュリティの為か、携帯電話の画面ロックを解除した状態にしないと接続できなかった。
しかし、bluetooth テザリングは、一度ペアリングすれば、接続要求によって簡単に繋がるので、画面ロック解除しなくても良くなった。
以前試行した時は、bluetooth テザリングに、 bt-pan というプログラム使ってたけど、接続できなくて sleep 1 で回してても負荷が無茶苦茶高かった記憶がある。
問題は最大3Mbps程度の通信スピードになるが、povo 2.0 の非課金速度が128kbps なので、ボトルネックになる事は無い。
今は、NetworkManagerを導入したおかげで、sudo nmcli dev connect [MACアドレス] で接続できるので、負荷が非常に低く、load avarage も
1 2 |
root@rx7pi:~# uptime 11:02:49 up 15:13, 2 users, load average: 0.10, 0.14, 0.16 |
こんな感じで非常に低負荷で済んでいる。