物理ボタンを付けてRaspberry Piを安全にシャットダウンする方法
Raspberry Piの電源をオフする場合にUSB電源コードをそのまま引っこ抜くと、運が悪い場合はSDカード内のOSが壊れる可能性があります(私もその経験あります)。かと言って、SSHでログインして $ sudo shutdown -h now を毎回実行するのも非常に面倒です。 そこでRaspberry Piに物理ボタンを外付けして、安全にシャットダウンする方法をご紹介します。
はじめに
ここで紹介する手順は次のとおりです。
- Raspberry PiのGPIOピンに物理ボタンを設置
- ボタンを監視するPythonコードを作成
- ②をシステムサービスへ登録
記事の後半ではさらにLEDも追加して、Raspberry Piの電源オンオフ状態を分かりやすく工夫しました!ぜひ最後までご覧ください。
Raspberry PiのGPIOピンに物理ボタンを設置
押している間だけ導通するモーメンタリー型のスイッチを使用しました。
このスイッチをRaspberry PiのGPIO27(物理番号13)とGround(物理番号14)に繋ぎます。
ボタンを監視するPythonコード
次に、適当な場所に shutdown_by_button.py としてボタンを監視するPythonコードを作成します。
#!/usr/bin/env python
import RPi.GPIO as GPIO
import os, time
GPIO.setmode(GPIO.BCM)
GPIO.setup(27, GPIO.IN, pull_up_down = GPIO.PUD_UP) # GPIO27--Button--GND
def shutdown(channel):
os.system("sudo shutdown -h now")
GPIO.add_event_detect(27, GPIO.FALLING, callback = shutdown, bouncetime = 3000)
while 1:
time.sleep(100)
上記プログラムの内容はGPIO.add_event_detect でGPIOのイベントを検知し、shutdown 関数を呼び出して sudo shutdown -h now を実行させています。
解説
このスクリプトは、Raspberry Pi上で動作し、物理ボタンの入力を使用してRaspberry Piを安全にシャットダウンするためのものです。以下、簡単な解説です。
GPIOモードの設定
GPIO.setmode(GPIO.BCM)は、GPIOピンを指定するための番号体系をBCM (Broadcom) ピン番号に設定しています。この設定により、プログラム内でGPIOピンを指定する際に、物理ピン番号ではなくBCM番号を使用します。GPIOピンの設定
GPIO.setup(27, GPIO.IN, pull_up_down = GPIO.PUD_UP)は、BCM番号27のGPIOピンを入力モードに設定し、内部でプルアップ抵抗を有効にしています。プルアップ抵抗を有効にすることで、物理的なボタンが接続されていない時にピンが高電圧 (HIGH) 状態に保たれます。シャットダウン関数の定義
shutdown関数は、GPIOピンからの入力信号を受け取り、システムコマンドsudo shutdown -h nowを実行してRaspberry Piをシャットダウンします。イベント検出の設定
GPIO.add_event_detect(27, GPIO.FALLING, callback = shutdown, bouncetime = 3000)は、BCM番号27のGPIOピンに対するイベント検出を設定しています。GPIO.FALLINGは、ピンの状態がHIGHからLOWに変化する(つまり、ボタンが押される)ことを検出するためのトリガーです。callback = shutdownは、指定されたイベントが検出された際に実行される関数を指定しています。bouncetime = 3000は、連続してイベントが検出されることを防ぐためのデバウンス時間(ミリ秒)を設定しています。無限ループ
最後のwhile 1:ループとtime.sleep(100)により、スクリプトは無限に実行され続け、この間ずっとGPIOピンの状態を監視します。time.sleep(100)はCPUの無駄な使用を避けるために追加されていますが、実際にはGPIOイベントによるコールバック関数の呼び出しで主な処理が行われるため、このスリープはそれほど重要ではありません。
このスクリプトを実行することで、物理ボタンを押すだけでRaspberry Piを安全にシャットダウンできます。これは、Raspberry Piをヘッドレス(モニターやキーボードなし)で運用する際に特に便利です。
スクリプトの権限変更
さて、 shutdown_by_button.py の権限を変更して、rootユーザーがスクリプトを実行可能なようにしておきます。
chmod 755 shutdown_by_button.py
プログラムをシステムサービスへ登録
先ほど作った shutdown_by_button.py をシステムサービスへ登録してデーモンとして実行させます。
$ sudo vi /usr/lib/systemd/system/shutdown_by_button.service を実行し、下記の内容を書き込みます。ExecStart=/home/pi/batch/shutdown_by_button.py の部分はプログラムが置いてあるパスに変更してください。[Unit]
Description=Shutdown/Reboot raspberry pi by GPIO button input
Wants=network.target
[Service]
ExecStart=/home/pi/batch/shutdown_by_button.py
Restart=on-failure
RestartSec=10s
[Install]
WantedBy=multi-user.target
続いてこの設定ファイルを反映させます。
sudo systemctl daemon-reload
スクリプトを開始させます。
sudo systemctl start shutdown_by_button
Raspberry Piの起動時にスクリプトが自動起動するように設定します。
$ sudo systemctl enable shutdown_by_button
こちらのコマンドでサービスの状態が問題ないか調べておきます。active となっていれば正常です。
$ sudo systemctl status shutdown_by_button
● shutdown_by_button.service - Shutdown/Reboot raspberry pi by GPIO button input
Loaded: loaded (/lib/systemd/system/shutdown_by_button.service; enabled; v>
Active: active (running) since Thu 2023-07-20 14:56:26 JST; 57s ago
...
これでサービスに登録されていることが確認できました。この画面は control + c で終了できます。以上ですべての設定が終わりました。
【発展】LEDも付けてみる
Raspberry Piの基板に実装されている2つのLEDだけですと、電源が入っているのかどうか判断しずらいです。そこでGPIOを使ってLEDを取り付けてみました。Raspberry Piが起動するとLEDが点灯し、シャットダウンさせるとLEDが消灯します。先ほど作った shutdown_by_button.py に追記する形で簡単に実現できました。
下図のようにLEDを追加して配線します。電流制御用の抵抗は1kΩを使いました。
shutdown_by_button.py を次のように修正します。#!/usr/bin/env python
import RPi.GPIO as GPIO
import os, time
# Select BCM(GPIO Number)
GPIO.setmode(GPIO.BCM)
GPIO.setup(27, GPIO.IN, pull_up_down = GPIO.PUD_UP) # GPIO27--Button--GND
# LED Blink
GPIO.setup(17, GPIO.OUT)
GPIO.output(17, 1)
def shutdown(channel):
os.system("sudo shutdown -h now")
GPIO.add_event_detect(27, GPIO.FALLING, callback = shutdown, bouncetime = 3000)
while 1:
time.sleep(100)
こちらの動画のように、電源オンオフが目視で非常に分かりやすくなりました!とても便利なので、皆さんもぜひまねしてみてください。