読者です 読者をやめる 読者になる 読者になる

Raspberry Pi 3 にシャットダウン/リブート/再開ボタンを追加する

f:id:hammm:20161114224346j:plain:w200

概要

Raspberry Pi 3にシャットダウン、およびその他のボタンを追加してみました。 この記事での自動起動の設定方法は、Ubuntu MATE16.04およびRaspbian Jessie(要はsystemdのある環境)に対応しています。それより以前のバージョンのOSであれば、rc.local という設定ファイルを使う手法のほうが有効かとおもいます。なお、pythonスクリプトそのものは他のバージョンにも対応すると思います。

※自分はUbuntu MATEで試しています。Raspbian Jessieについては未確認でして、動作しない場合はお知らせください。

twitter.com

https://twitter.com/hammmm/status/797662568697344000

なぜシャットダウンボタンが必要なのか?

Raspberry Piを外に持ち出して使おうと思ったときの1つの問題点として、「シャットダウンできない」という問題があります。

いきなり電源ケーブル(マイクロUSB)を抜けば良くない?

ラズパイをシャットダウンせずに電源を抜くと、SDカードが壊れて動かなくなる可能性が一定(利用状況にもよりますが数%程度)あります。 ラズパイのOSであるLinuxは絶えずファイルシステムにデータを読み書きしており、特に書き込みが中途半端な状態で突然電源が切れると、SDカードのデータの状態そのものが不安定となり、読み込みできない状態になってしまうことがあります。

なお、いきなり電源ケーブルを抜いても問題ないようにする方法が一応あり、それはファイルシステムをREAD ONLY(書き込み不可)にするというものです。書き込みできなければ破壊も起こりません。場合によってはそれもアリですが、そうすると後から編集等もしづらくなりますので、良し悪しかと思います。

一般的なシャットダウン方法について

一般的に、シャットダウンする方法は以下の方法があります。

方法 説明 接続するもの 重量
GUI マウス操作でGUIメニューから HDMIモニタ,USBマウス/キーボード 1kg
CUI ターミナルで sudo shutdown -h now等 HDMIモニタ,USBキーボード 800g
ssh ネットでつないでsudo shutdown -h now 等 wifiアクセスポイント(テザリング等)、ノートPC 1.5kg

重さもありますが、いろいろ接続したり準備も必要です。 そこで、今回の方法ならほとんど重さの追加もなく、ボタン一発で簡単にシャットダウンできるようになります!

今回のシャットダウンボタンの実装方法について

Raspberry Piには、「GPIO」という、電気工作などに使える汎用の入力ピンがありますが、ここにボタンなどを接続すると、プログラムからボタンのON/OFFを読み取ることができます。 そこで、常時実行しているプログラムで、ボタンの状態を監視してあげて、ボタンが押されたらシャットダウンコマンドを発行するようにしてあげます。

再開ボタンについて

シャットダウンボタンと再開ボタンは全く異なる仕組みで動作します。

http://elinux.org/RPI_safe_mode によれば、GPIO3をGNDに落とすと(GPIO3とGNDを一時的に接続すると)、シャットダウン後の状態から再起動させることができるそうですので、これを利用してみます。

ただし、注意として、GPIO3はデバイスとのI2C通信に利用するピンと同じピンなので、I2Cデバイスと共存させたい場合は分岐させるなど工夫が必要と思います。

なお、シャットダウンボタンと違い、再開ボタンについては、動作のためにソフトウェアのインストールは不要です。

材料

  • Raspberry Pi 3 (2やタイプBなどでもいけると思いますが、未テストです)
  • ボタン: aitendoの薄膜スイッチ 3ボタンタイプ www.aitendo.com
  • ケーブル: aitendoのオス-メス ジャンパワイヤ 4本分 www.aitendo.com
  • OS: Ubuntu MATE (16.04) または Raspbian Jessie

ワイヤ接続

各ボタンの役割は以下のように割り当てました。

  • 赤: シャットダウン
  • 黄: リセット
  • 緑: 再開

そこで、以下のようにつなぎます。

  • GNDをボタンの共通ピン(1)に接続
  • GPIO3に再開ボタン(2)をつなぐ
  • GPIO19にリセットボタン(3)をつなぐ
  • GPIO26にシャットダウンボタン(4)をつなぐ

f:id:hammm:20161114021702j:plain

Raspberry PiのGPIOピンの役割はこれを見ると良いです。

https://www.element14.com/community/servlet/JiveServlet/showImage/102-78055-1-227625/1.jpg

コード

監視スクリプト

nano ~/shutdown_by_button.py
または
vi ~/shutdown_by_button.py

ファイルの内容は以下のようにします。

#!/usr/bin/env python

import RPi.GPIO as GPIO
import os, time

GPIO.setmode(GPIO.BCM)

# GPIO19 : reset button
GPIO.setup(19, GPIO.IN, pull_up_down = GPIO.PUD_UP)
# GPIO26 : shutdown button
GPIO.setup(26, GPIO.IN, pull_up_down = GPIO.PUD_UP)

def shutdown(channel):
  os.system("sudo shutdown -h now")

def reboot(channel):
  os.system("sudo reboot")

GPIO.add_event_detect(26, GPIO.FALLING, callback = shutdown, bouncetime = 2000)
GPIO.add_event_detect(19, GPIO.FALLING, callback = reboot, bouncetime = 2000)

while 1:
  time.sleep(100)
$ chmod 755 ~/shutdown_by_button.py
  • 実行してみる
$ ~/shutdown_by_button.py

ここで、ボタンを押して、動作を確認してみてください。

動かない場合は結線など確認してみてください。 たとえばPythonスクリプト内(GPIO.setmodeより後の行)で print GPIO.input(26) とすればGPIO26の状態(1か0)を出力できるので、ボタンの状態を取得できているかどうか調べてみてください。

上記スクリプト自動起動するための方法

ユーザー名が pi という名前になっているケースになります。他のユーザー名の場合は、 /home/pi となっているところを /home/ユーザー名 と読み替えてください。

  • 設定ファイルを追加する
# 設定ファイルのディレクトリを作成 (※既にあればcannot create directory等と出ると思いますが気にしなくて良いです)
$ sudo mkdir /usr/lib/systemd/system```

# ファイル編集
$ sudo nano /usr/lib/systemd/system/shutdown_by_button.service
または
$ sudo vi /usr/lib/systemd/system/shutdown_by_button.service

ファイルの内容は以下のようにします。

[Unit]
Description=Shutdown/Reboot raspberry pi by GPIO button input
Wants=network.target

[Service]
ExecStart=/home/pi/shutdown_by_button.py
Restart=on-failure
RestartSec=10s

[Install]
WantedBy=multi-user.target
  • 設定を反映する
# 上記設定ファイルを反映します
sudo systemctl daemon-reload
# スクリプトを開始します
sudo systemctl start shutdown_by_button
# スクリプトをLinux開始時に自動起動するようにします
sudo systemctl enable shutdown_by_button
  • サービスの状態を調べる
sudo systemctl status shutdown_by_button

f:id:hammm:20161114230814p:plain

実行結果のところに緑の丸がついていない場合は、なにか問題が発生していることになります。 最新のログも一緒に出るので参考にしてください。

※Terminalの文字色が出ていない場合は、 Active: active (running) となっているかどうかで判断してください。

参考