ぼくの技術日誌

日誌って銘打っていますが、更新頻度が…

Raspberry Piに電源スイッチを付けたくてシェルクスリプトについて少し調べた話

はじめに

タイトル通りです。
Raspberry Piブログ : [コラム] 第8回『ボタン長押しでシャットダウンする電源ボタンを作ろう』を見つけました。
載っていたスクリプトをコピー・ペーストすればできるのですが、スクリプト内容がわからないのがどうにも落ち着かなくてまずはシェルスクリプトについて調べてみることにしました。
今回はシェルスクリプトについて調べた内容を忘備のためにまとめておきます。

スクリプトの内容

さて、元の記事に載っているスクリプトは以下の通りです。

shutdown-daemon.sh

#!/bin/sh
GPIO=22     #使用するGPIOポート
PUSHTIME=5  #押す秒数

#初期設定
echo "$GPIO" > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio$GPIO/direction
echo "low" > /sys/class/gpio/gpio$GPIO/direction

#5秒間押されるまで待つ
cnt=0
while [ $cnt -lt $PUSHTIME ] ; do
  data=`cat /sys/class/gpio/gpio$GPIO/value`
  if [ "$data" -eq "1" ] ; then
    cnt=`expr $cnt + 1`
  else
    cnt=0
  fi
  sleep 1
done

#シャットダウンの実行
shutdown -h now

最近のエントリRaspberry Piブログ : [コラム] 『ボタン長押しでシャットダウンする電源ボタンを作ろう 2』で内容が更新されていましたが、行数が少なかったこちらをまずみることにしました。


1行目:シェルで処理する宣言。
2~3行目:変数宣言。
5~8行目:GPIO初期化(GPIOを使用するにはGPIOの仮想ファイルシステム/sys/class/gpio/exportに使用するGPIOの番号をセット、directionにGPIOの制御方向、出力値を設定)。「$」は変数の中身を参照する時に付ける。
12行目:変数cntを宣言し、0で初期化。変数と値の「=」の間にスペースを入れるとスクリプトとして認識されないので注意。
13~21行目:while文。「[ ]」は戻り値判定。が真の間、do-doneの中を繰り返す。[変数1 -lt 変数2]は変数1 < 変数2なら真、でなければ偽を返す(この場合cntの中身がPUSHTIMEの中身、つまり5未満かを判定)。「;」は複数行を1行で書く際に使用する。
14行目:「`」バッククォートは囲った中身をコマンドとして処理して結果を出力する(この場合、変数dataへcatした内容を入れる)。
15~20行目:if-else文。「
」内部の「"」ダブルクォートは囲った変数の中身を文字列として出力する(この場合、変数dataの中身を文字列として出力する)。「変数1 -eq 変数2」は変数1 == 変数2なら真、でなければ偽を返す(この場合、"$data"で出力される文字と"文字「1」を比較する。比較結果でifの下かelseの下のコマンドを実行する)。
16行目;整数演算。`expr 数値1 + 数値2`は数値1に数値2を足して結果を代入する。
24行目:shutdownコマンドの実行(この場合、cnt < 5の間はここに到達しない)。

手書きメモ

スクリプトの内容を憶えるために手書きしていました。折角なので、写真を張っておきます。

まとめ
f:id:yosuke_kirihata:20150309145320j:plain

フローチャート
f:id:yosuke_kirihata:20150309145439j:plain

スクリプトの起動登録と実行確認

参考記事に従って、/etc/rc.localに以下の追記を行います。
/etc/rc.localはシステム起動直後に実行されるファイルであり、ここにはシェルスクリプトを書くことができます。

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

su -c /home/pi/shutdown-daemon.sh #追加
exit 0

suコマンドはユーザー権限を切り替えるコマンドで、-cを付けると続く内容をユーザー切り替え後に実行します。
切り替えユーザーを指定しない今回のような場合は管理者権限へ切り替えるので、このrc.localの追加内容は「管理者権限でshutdown-daemon.shを実行する」となります。
なお、スクリプトが正常に読み込まれて実行されれば、プロセス一覧をpsコマンドで表示してその中にshutdown-daemon.shを見つけることができます。

スクリプト内容とその実行に関しては以上です。
しかし、実際には電源スイッチとしてRaspberry PiのI/O端子にスイッチを接続しなければなりません。
私は下記のスイッチとピンソケットを組み合わせてI/Oに刺す形の電源スイッチを作成しました。

スイッチ
表面実装用タクトスイッチ SKRPACE010(5個入): パーツ一般 秋月電子通商 電子部品 ネット通販
ピンソケット(実際に私が使ったのはL字でない足が長い1x2Pピンソケットで自分でスイッチ底面の長さ分曲げました)
【共立エレショップ】>> L型ヘッダーソケット 1列2P: 【能動・受動・機構パーツ】 << 電子部品,半導体,キットの通販

スイッチ底面がピンソケット間にぴったり収まるので、スイッチ底面の4隅で半田付けが可能です。
f:id:yosuke_kirihata:20150309161639j:plain

これで+3.3Vをスイッチを間に挟んでI/O端子と接続する形となります。シェルスクリプトで行った設定(スクリプト8行目)によって、SoC内臓のプルダウン抵抗を有効にしています。

配線図
f:id:yosuke_kirihata:20150309163300j:plain

これでRaspberry PiのP15とP17にスイッチを接続した状態でRaspberry Piの電源をON、スイッチを5秒間押し続けることでRaspberry Piが終了することを確認できました!

さいごに

今回は、シェルスクリプトについて、後から見返してもわかるよう丁寧にを心がけてまとめてみました。
でも自分で何か書かないと憶えられない気がする…