Raspberry PiでWebラジオのソフトウェアが何となく出来てきたので、そろそろパネルに固定してスタンドアロンのWebラジオに仕立てていこうと思っている。
スタンドアロンで動かすにあたって、問題になるのが、「どのように安全に電源を切るか」
なのである。
いきなり電源を切ると、以下のような不具合が有る、とChatGPTは言うのである。
① SDカードのファイル破損
Raspberry Pi の OS(Raspberry Pi OSなど)は Linux なので、内部で常にログやキャッュ、設定ファイルなどを書き込んでいます。
電源をいきなり切ると、書き込み中のデータが途中で途切れてしまい、
・OSのファイルシステム(ext4)の整合性が壊れる
・/home/pi/ などにあるデータファイルが破損する
最悪の場合、次回起動時にブートしなくなる(カーネルパニックや復旧モード)
といった症状が起こります。
② 長期的にはSDカードの寿命を縮める
書き込み途中で電源断が繰り返されると、SDカードのフラッシュメモリ内の管理情報が不整合になり、寿命が短くなります。
補足:SDカードの構成(通常のRaspberry Pi OSの場合)
SDカードをパソコンで見ると、最初の小さなパーティション(約256MB)は「boot」ですが、実際にはこうなっています:
| パーティション |
ファイルシステム |
内容 |
/boot |
FAT32 |
起動用ファイル(kernel、config.txt、cmdline.txtなど) |
/ (ルート) |
ext4 |
OS本体・アプリ・ログ・ユーザーデータなどすべて |
ext4はジャーナリングファイルシステムで、一応電源断に強い設計ですが、
・書き込み途中で電源が落ちる
・キャッシュがフラッシュされていない
といった状態だと、ファイルやディレクトリ構造が不整合を起こすことがあります。
最悪の場合、
「起動しなくなる」
「ファイルが消える・壊れる」
ということが起こります。
と言うのである。
なので、雑に扱っても安全に電源を落とせる(シャットダウン処理が完了してから電源が落ちる)ように考えないといけないのである。
じゃぁ、具体的にどうするか?
例えば、以下のプログラムを走らせて、GPIOでスイッチの状態を監視して、スイッチonでシャットダウンコマンドを実行させる、と良いらしい。
import RPi.GPIO as GPIO
import os
import time
BUTTON_PIN = 17
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
try:
while True:
if GPIO.input(BUTTON_PIN) == GPIO.LOW:
print("シャットダウンします...")
os.system("sudo shutdown -h now")
time.sleep(1)
time.sleep(0.1)
except KeyboardInterrupt:
GPIO.cleanup()
シャットダウンした後に信号を変化させるには、gpio-poweroff という仕組みを使うと良いらしい。これを /boot/firmware/config.txt に設定すると、シャットダウン(halt/poweroff)時に指定ピンをソフトウェア的に HIGH/LOW に駆動してくれるらしい。
・config.txtを編集
sudo nano /boot/firmware/config.txt
・最後に追記: GPIO26をシャットダウン後にLowに設定
dtoverlay=gpio-poweroff,gpiopin=26,active_low=1
以上を基に、電源制御回路を描いてみる。
トグルSWの状態をソフトで監視出来るようにして、シャットダウンを開始。GPIO26をpower off信号に使って、トグルSW OFF後、シャットダウン処理終了後にFTTがoffする。
ちなみに2SJ334を使った理由は、ON抵抗が約50mΩと低く、Vgsが-3Vで確実にonに出来るため。ただ、amazonで3個で850円と、ややお高い。探せばもっと安いものが見つかると思う。
暫定回路図
Raspberry Pi側: shut_down、Power off信号追加
次に、このコードをWebラジオのコードに追加して、シャットダウンできるか確認する。
GPIO17をshut_down_signalとして使用。
(この関数は定期的に呼び出し)
#==== シャットダウン要求チェック ===~
def power_off_check():
if GPIO.input(shut_down_signal) == GPIO.LOW:
print("シャットダウンします...")
draw.rectangle((0, 0, 320, 240), fill="black") #/display clear
draw.text((0, 50), "シャットダウン中", font=font28, fill="white")
draw.text((0, 100), "電源を抜かないでください", font=font24, fill="white")
device.display(image)
os.system("sudo shutdown -h now")
time.sleep(1)
GPIO17を試しにGNDに繋いでみると、このように表示した後にシャットダウンする。
GPIO26の挙動を見ると、config.txt修正前は電源投入後はGPIO26はLow(プルダウン状態)だったが、修正後はHighになり、シャットダウン後にLow(プルダウン状態)になる事が分かった。
これで、ちゃんと動きそうだ。
実際に仮配線して試してみる。
電源SW(左下トグルSW)をONにすると、電源が入る。次にWebラジオソフトを起動させる。
電源SWをOFFにすると、シャットダウン開始
シャットダウン開始から約10秒程度で自動的に電源OFF
(GUIが立ち上がってなければ2~3秒で電源off)
思った通りに動作した。
ついでに、電源を入れれば、Webラジオとして自動でPythonプログラムが立ち上がるようにする。
①/etc/rc.localを編集(または新規作成)
sudo nano /etc/rc.local
②PythonのWebラジオプログラムを起動するように、以下のように記述
python3 /home/nya/Documents/Web_Radio_V0_33.py &
exit 0
注)ファイルの場所、ファイル名等は、環境に応じて変更、 最後に&を入れておく
&:プログラムをバックグラウンドで実行(起動処理をブロックしない)
Pythonプログラムをバックグラウンドにせずに起動すると、
そのプロセスが終了するまで rc.local 全体が待ち続けてしまい、
システムの起動が完了しなくなる(ブートが止まる)ことがあるらしい。
③実行権限を付与
sudo chmod +x /etc/rc.local
④systemd に rc-local サービスを有効化
sudo systemctl enable rc-local
⑤手動テスト(エラー確認)
sudo /etc/rc.local
これでエラーが無ければOK
試してみると、電源を入れてしばらくすると、Webラジオプログラムが動き出す。
ちなみに電源onから音が鳴るまで40秒くらいかかる。
OSの起動だけで30秒くらいかかるので、まぁ仕方無い。
これでとりあえず、電源を入れれば勝手にWebラジオが立ち上がり、電源を切れば安全に電源が落ちるようになった。
簡単な仕組みだけど、ちゃんと動くと、なんかうれしいのである。
参考までに今回のプログラムを以下に置いておきます
そこそこちゃんと動くが、まだ少し動きが怪しいところが有るので、ちゃんとしたものが欲しい方は完成まで、もうしばらくお待ちを。
「そんなことくらいで喜んでるようじゃダメにゃ」
----------- 補足----------
なお、今回のコードを動かす前に以下作業も必要
●液晶を動かすためにLuma.lcdのインストール
sudo apt update
sudo apt install python3-luma.lcd python3-pil
●日本語対応フォントがインストールされていないので、noto-cjkをインストール。
sudo apt install fonts-noto-cjk
● rpi-lgpioにアップデート
sudo apt remove python3-rpi.gpio
sudo apt install python3-rpi-lgpio
● I2Sドライバを有効化
sudo nano /boot/firmware/config.txt
ファイルを開いたら以下を追加:
# PCM5102 用 I2S 設定
dtparam=i2s=on
dtoverlay=hifiberry-dac
●pigpioを自動起動に
電源投入時に自動で起動するように設定
sudo systemctl enable pigpiod
sudo systemctl start pigpiod
●pigpioがPCM用タイマを使っているので、PWMタイマーを使う設定にする
sudo mkdir -p /etc/systemd/system/pigpiod.service.d
sudo nano /etc/systemd/system/pigpiod.service.d/override.conf
エディタが開いたら以下を記入
[Service]
ExecStart=
ExecStart=/usr/bin/pigpiod -t 0 -l
保存してリブート
●Webラジオの再生ソフトのmpvをインストール
sudo apt install mpv