#1.はじめに
RaspberryPiのGPIO端子に信号が入力されると、シャットダウンする機能について解説します。既にいろいろなサンプルがありますが、ここでは、systemdからスクリプトを起動して、定期的にGPIOを監視する方法を説明します。
※本記事は、下名がはてなブログで公開している内容を元に、一部内容を訂正したものになります。(十分試用して、問題無いようですのでこちらに転載しました)
##環境
- Raspberry Pi シリーズ (1, 2, 3, 3+)
- OS
- Raspbian
- Ubuntu Linux 18.04 (ラズパイ版 32/64bit)
#2.つくりかた
##(1)ファイル構成
本記事では、下記のファイルを作成します。
ファイル名 | 機能 |
---|---|
setPowerWatcher.sh | GPIO入力ピンの状態監視とシャットダウン処理 |
setPowerWatcher.service | systemdのサービスファイル |
最後に、systemdにサービスとして登録します。
##(2)シェルスクリプト
「定数」の所は、環境に合わせて修正してください。
定数 | 機能 |
---|---|
SET_WATCH_PORT | GPIOピンにシャットダウン信号を入れる番号を指定 |
SET_TRIGGER | 信号の立ち上がり・立ち下がりどちらで反応するかを設定 |
SET_WATCH_INTERVAL | 指定した秒数ごとに、シャットダウン信号の状態を監視 |
ソース中の所々の[INSTALL DIR]は、お使いの環境に合わせて書き換えてください。
#!/bin/bash
#--------------------------------------------------------------------
# UPSの信号監視とシャットダウン
# 2019 by myasu
# MIT Licence
#--------------------------------------------------------------------
#
#install:
# $ sudo ln -s /home/pi/[INSTALL DIR]/setPowerWatcher.service /etc/systemd/system
# $ sudo systemctl enable setPowerWatcher.service
# $ sudo systemctl start setPowerWatcher.service
#--------------------------------------------------------------------
#ref:
#
# ※必ずbashを使うこと。shを使うと関数の宣言でエラーが出ます
# https://yatta47.hateblo.jp/entry/2014/04/20/222707
#
#----------------------------------
#定数
#----------------------------------
#監視するポート(BMC番号で指定)
SET_WATCH_PORT=4
#監視モード
# 1:ダウンパルス、0:アップパルス
SET_TRIGGER=1
#監視ループの間隔(sec)
SET_WATCH_INTERVAL=1
#----------------------------------
#関数
#----------------------------------
#シャットダウンの開始処理
function ShutdownGoProc ( ) {
#シャットダウン信号を検出したメッセージを表示
echo " ! Shutdown signal detected. ${MESSAGE}"
#シャットダウン処理を開始
if [ ! "$MODE_TEST" = 1 ]; then
#瞬停防止のため2秒だけshutdownを待つ(-t 2)
/sbin/shutdown -P -t 2
fi
}
#シャットダウンの停止処理
function ShutdownStopProc ( ) {
#シャットダウン信号を検出したメッセージを表示
echo " + Shutdown signal disappeared. ${MESSAGE}"
#シャットダウン処理を中止
if [ ! "$MODE_TEST" = 1 ]; then
/sbin/shutdown -c
fi
#すぐにループ処理に戻らないよう、ウェイト
sleep 1
}
#----------------------------------
#メイン処理
#----------------------------------
#実行中ユーザをチェック
if [ `/usr/bin/id -u` != "0" ]; then
#rootでなければ異常終了
echo " ! Please run as root."
exit 1
fi
#主要コマンドの存在をチェック
if [ ! -x /usr/bin/gpio ]; then
#見つからなければ異常終了
echo " ! No 'gpio' Command."
exit 1
fi
#自身のコマンド名を変数に入れる。usage用
CMDNAME=`basename $0`
#引数のチェックと動作フラグの生成
#https://shellscript.sunone.me/parameter.html
while getopts vt OPT
do
case $OPT in
"v" )
#verboseモード
MODE_VERBOSE=1 ;;
"t" )
#テストモード(シャットダウンはしない)
MODE_TEST=1 ;;
* )
#それ以外の指定は、usageを表示
echo "Usage: $CMDNAME [-v] [-t]" 1>&2
exit 1 ;;
esac
done
#動作モードのメッセージ
if [ ${SET_TRIGGER} -eq 1 ]; then
MESSAGE="(MODE: Down trigger)"
else
MESSAGE="(MODE: Up trigger)"
fi
#起動メッセージ
if [ "$MODE_VERBOSE" = 1 ]; then
#メッセージ
echo " * Monitor the GPIO signal and shutdown * ${MESSAGE}"
#テストモードのメッセージ表示
if [ "$MODE_TEST" = 1 ]; then
echo ' - test mode (no shutdown)'
fi
fi
#ポートの初期化
`/usr/bin/gpio -g mode ${SET_WATCH_PORT} in`
#監視ポートの状態変数の初期化と問い合わせ
STAT_PORT_PREV=`/usr/bin/gpio -g read ${SET_WATCH_PORT}`
#監視ループ
while :
do
#監視ポートの状態を問い合わせ
STAT_PORT_NOW=`/usr/bin/gpio -g read ${SET_WATCH_PORT}`
if [ ${SET_TRIGGER} -eq 1 -a ${STAT_PORT_PREV} = "1" -a ${STAT_PORT_NOW} = "0" ]; then
#ダウントリガで検知
ShutdownGoProc
elif [ ${SET_TRIGGER} -eq 0 -a ${STAT_PORT_PREV} = "0" -a ${STAT_PORT_NOW} = "1" ]; then
#アップトリガで検知
ShutdownGoProc
elif [ ${SET_TRIGGER} -eq 1 -a ${STAT_PORT_PREV} = "0" -a ${STAT_PORT_NOW} = "1" ]; then
#アップトリガで検知
ShutdownStopProc
elif [ ${SET_TRIGGER} -eq 0 -a ${STAT_PORT_PREV} = "1" -a ${STAT_PORT_NOW} = "0" ]; then
#ダウントリガで検知
ShutdownStopProc
fi
#監視ポートの状態変数に、現在の状態を代入
STAT_PORT_PREV=${STAT_PORT_NOW}
#ウェイト
sleep ${SET_WATCH_INTERVAL}
done
exit 0
##(3)systemdに登録するserviceファイル
[Unit]
Description=Monitor the GPIO signal and shutdown
After=local-fs.target
ConditionPathExists=/home/pi/[INSTALL DIR]
[Service]
ExecStart=/home/pi/[INSTALL DIR]/setPowerWatcher.sh
ExecStop=/bin/kill ${MAINPID}
Restart=on-failure
StartLimitInterval=60
StartLimitBurst=3
KillMode=mixed
Type=simple
User=root
Group=root
[Install]
WantedBy=multi-user.target
##(4)配線
前述(3)のプログラムにならって、GPIO4にリセットボタンを繋ぎます。
#2.セットアップ手順
##(1)systemdへ登録
systemdに登録して、サービスを起動します。
$ sudo ln -s /home/pi/[INSTALL DIR]/setPowerWatcher.service /etc/systemd/system
$ sudo systemctl enable /home/pi/[INSTALL DIR]/setPowerWatcher.service
##(2)serviceファイルを修正した時
下記のリロード操作をします。
$ sudo systemctl daemon-reload
##(3)状態を確認
systemctl statusコマンドで、状態を確認します。
まだ起動していません
$ systemctl status setPowerWatcher.service
● setPowerWatcher.service - Monitor the GPIO signal and shutdown
Loaded: loaded (/home/pi/[INSTALL DIR]/setPowerWatcher.service; linked; vendor preset: enabled)
Active: inactive (dead)
##(4)起動
$ sudo systemctl start setPowerWatcher.service
##(5)状態を確認
左上の●が緑色になっていれば、正常に起動しています。
$ systemctl status setPowerWatcher.service
● setPowerWatcher.service - Monitor the GPIO signal and shutdown
Loaded: loaded (/home/pi/[INSTALL DIR]/setPowerWatcher.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2019-03-09 15:47:22 JST; 9s ago
Main PID: 537 (setPowerWatcher)
CGroup: /system.slice/setPowerWatcher.service
tq537 /bin/bash /home/pi/[INSTALL DIR]/setPowerWatcher.sh
mq564 sleep 1
Mar 09 15:47:22 raspizwh systemd[1]: Started Monitor the GPIO signal and shutdown.
##(6)動作確認
GPIOに信号を入れると、間もなくシャットダウンします
その際syslogには、下記のメッセージが残ります。
Mar 9 15:58:13 raspizwh setPowerWatcher.sh[537]: ! Shutdown signal detected. (MODE: Down trigger)
#おわりに
こんな感じで、外部信号からシャットダウンできるようになりました。
ご参考頂けると幸いです。