10: Raspberry Pi3 で Push Switch で shutdown / boot する


# はじめに
こちらは
[Arduino と Raspberry Pi の違いのまとめ](https://qiita.com/KZ2/items/5e0e79f84e4dd26bd373)
の個別記事で、Raspberry Pi3 で Push switch　の長押しで shutdown　し、その後、再度 Switch を押すと起動する。(のつもりだったが、事情により、shutdownとbootのswitchは別々とした)

# 目的
Raspeberry Pi3 で shutdown を行う際には、GUI でメニューから操作したり、console から command を入力する必要がある。これは少々面倒であるし、HDMI 入力の Display が不要な場合でも、Display と USB Mouse の接続が必要であり運用上好ましくない。また shutdown 後に再度電源を入れるためには、AC Adapter の On/Off をACタップの独立スイッチで操作するか、Raspberry Pi3 に接続している電源用の USBケーブルを挿抜しなければならない。USBケーブルにスイッチがついたものなどもあるが。

つまり、問題は次の二つである。
-【問題】: shutdown の操作の手間と、shtudown 後の再起動の手間
-【原因】: この問題の原因は、Raspberry Pi3 に通常のPCのように電源Onのスイッチがないからである。電源を供給入れるとすぐ起動する仕組みになっている。また利用用途によっては、頻繁に On / Off を行うが、外部Display を持たない利用方法の時に安全に shutdown する方法が提供されていないためである。いきなり電源を切ると Micro SDカード上の File System が破壊されることが容易に想像される。
-【解決方法】: そこで、指定のボタン一つで shutdown と boot を簡単に操作できるようにする。こうしておけば HDMI 入力の Display がなくても shutdown を簡単に安全に実現できる。また、shutdown 後の再起動でも、電源の USB ケーブルを挿抜したり、AC アダプタの電源を On/Off する必要がなくなる。
Raspberry Pi に最初から備えて欲しい機能ではある。

安全のため長押しで shutdown となり、ちょっと短く押すだけでは何もしない仕様である。

# Shutdown ボタン

## 配線
Push Switch を好きなGPIOと3.3Vに接続する。これは、Pull downするため。ここでの codeは、pull down向けである。Pull upがいい人はGPIOとGNDを接続し、codeは適当に書き換える必要がある。

```shell

3.3V --- (Push SW) -- GPIO21 —--— [Internal Pull down Register] --- GND
```

まずはシンプルに試してみる。

## code

```python
pi-shutdown.py 

#!/usr/bin/python 
# coding:utf-8 
import time
import RPi.GPIO as GPIO
import os

SHUTDOWN_GPIO = 21

GPIO.setmode(GPIO.BCM)
GPIO.setup(SHUTDOWN_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

while True:
    state = GPIO.input(SHUTDOWN_GPIO)
    print('state = ' + str(state))
    if state == True:
        print('Button pressed.  Pi will go shutdown now.')
        os.system("sudo shutdown -h now")
    else:
        print("Not pressred.")
    time.sleep(0.2)
```

## scriptを実行可能に変更する
```shell

pi@rp:~ $ sudo chmod 755 pi-shutdown.py 
```


## 単体テスト
```shell

pi@rp:~ $ ./pi-shutdown.py 
```

で起動する。

しかし、これだと間違ってちょっとボタンを押しただけで shutdown してしまので、少し長く押さないと shutdown しないようにした。

```python

#!/usr/bin/python 
# coding:utf-8 
import time
import RPi.GPIO as GPIO
import os

SHUTDOWN_GPIO = 21

GPIO.setmode(GPIO.BCM)
GPIO.setup(SHUTDOWN_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

counter = 0

while True:
    state = GPIO.input(SHUTDOWN_GPIO)
    print('state = ' + str(state))
    if state == True:
        counter += 1
        if counter > 100:
            print('Button pressed.  Pi will go shutdown now.')
            os.system("sudo shutdown -h now")
            break
        else:
            print("Not pressed for long enough.")
    time.sleep(0.01)
```

state を間違って逆にしてしまうと、何もボタンを押さなくても shutdown するシステムになってしまい、起動と自動shutdown を繰り返してしまうことになるので注意。(やってしまった...)

os.systemのところをコメントアウトして、十分にテストしてからserviceに登録した方がよさそう。

しかし、起動が面倒くさい。

## 自動起動の設定

それはさておき、まずは自動起動を設定する。
systemdという仕組みで、Unitというサービスを作る。

```shell　/usr/lib/systemd/system/shutdownd.service

[Unit]
Description=Shutdown Daemon

[Service]
ExecStart =/home/pi/py-shutdown.py
Restart=always
Type=simple

[Install]
WantedBy=multi-user.target
```

次にサービスを自動起動するように設定する。

```shell

pi@rp:~ $ sudo systemctl enable shutdownd.service 
```

ここで Raspberry Pi を**再起動**して、service のstatus を確認すると登録されていることが分かる。

```shell

pi@rp:~ $ sudo systemctl status shutdownd.service 
● shutdownd.service - My Shutdown Daemon, May 2, 2018
   Loaded: loaded (/usr/lib/systemd/system/shutdownd.service; enabled; vendor preset: enabled)
   Active: active (running) since Tue 2018-05-01 19:52:53 UTC; 1min 22s ago
 Main PID: 336 (pi-shutdown.py)
   CGroup: /system.slice/shutdownd.service
           └─336 /usr/bin/python /home/pi/pi-shutdown.py

May 01 19:52:53 rp systemd[1]: Started My Shutdown Daemon, May 2, 2018.
```

ちなみに、この enable コマンドでは再起動時に自動起動するが、今サービスを起動するわけではない。すぐに有効にするには、start を使う。同様に disable ではすぐは停止しない。再起動が必要である。

今すぐ起動したり、停止したりするには、start あるいは stop を利用する。

```shell

pi@rp:~ $ sudo systemctl start shutdownd.service
```

```shell

pi@rp:~ $ sudo systemctl stop shutdownd.service
```

サービスとして登録されているかを見るには次のようにするとよいだろう。 grepしなければずらずらっとたくさんのサービスが表示される。

```shell

$ sudo systemctl list-unit-files --type=service | grep shutdown
shutdownd.service                      disabled
```

あるいは

```shell-session
$ sudo systemctl list-unit-files --type=service | grep shutdownd
shutdownd.service                      enabled  
```

まとめると、以下のようになる。

## systemctl オプション一覧

一部のみであるが、まとめてみる

| やりたいこと    |  command          |
|---------------|-------------------------|
| 自動起動を有効  | systemctl **enable** your_service_name    |
| 自動起動を無効  | systemctl **disable** your_service_name   |
| 起動           | systemctl start your_service_name     |
| 停止           | systemctl stop your_service_name   |
| ステータス表示   | systemctl **status** your_service_name |


## テスト
電源投入時からの Push Button の長押しで shutdown が確認できた。動作ok.


# 起動ボタン
次に起動を簡単にする。

## 配線
Raspberry Pi3 には、GPIO#3 と GND をショートすると、再起動する仕組みがある。
shutdown と boot とそれぞれ Push Switch を独立して取り付けてもよいが下記のように配線して、一つで済ますようにする。

```shell

GPIO3   —--— + --- (Push SW) --- GND
GPIO21  ---- +
```

あ、shutdown switch を pull up しておけばスイッチ一つですんだのに...

## 操作方法
起動中：SW の長押しで shutdown し、短押しでは何もしない
shutdown後：押すと起動する


つまり、shtudown後は、halt しているだけらしく、short させるだけで起動する。

## 統合テスト
電源投入時からの Push Button の長押しで shutdown および boot が確認できた。動作ok.


参考
https://elinux.org/RPI_safe_mode

# 親記事
[Arduino と Raspberry Pi の違い](https://qiita.com/KZ2/items/5e0e79f84e4dd26bd373)