2014年4月27日日曜日

Raspberry Piにshutdownスイッチ追加

 去年の暮れに、常時稼動させている家鯖をShuttle XS35からRaspberry Piに交替しました。Raspberry Piには電源スイッチがありません。通電すると即起動し、電源を切る前にはログインしてshutdownコマンドを実行します。電源OFFがちょっと面倒です。
 もっと手軽に電源を落とせるように、少々工作して、 GPIOとGNDの間に押しボタンスイッチを接続しました。プルアップしておいたGPIOのエッジ割り込みを監視し、GNDに落ちて5秒継続したらshutdownが走ります。参考になったのは、こちら↓。

 「Raspberry Pi にシャットダウンボタンをつける」
   http://d.hatena.ne.jp/penkoba/20130925/1380129824 

今は、このようなスクリプトでシャットダウンの指令を監視しています。
#!/usr/bin/env python2.7

import RPi.GPIO as GPIO
import time
import syslog
import os

# use GPIO 27 as shutdown button
WatchGpioNo = 27
LEDGpioNo = 4
SleepStepSec = 0.1

def KeepWatchForSeconds(seconds):
    GoFlag = True
    LEDState = False
    if seconds < 1:
        seconds = 1
    while seconds > 0:
        LEDState = not LEDState
        GPIO.output(LEDGpioNo, LEDState)
        time.sleep(SleepStepSec)
        seconds -= SleepStepSec
        if (GPIO.input(WatchGpioNo) == True):
            GoFlag = False
            break
    return GoFlag

def CallShutdown():
    syslog.syslog(syslog.LOG_NOTICE, "Going shutdown by GPIO.")
    os.system("/sbin/shutdown -h now 'Poweroff by GPIO'")

def SlowBlink(seconds):
    for i in range(int(seconds)):
        GPIO.output(LEDGpioNo, GPIO.LOW)
        time.sleep(0.5)
        GPIO.output(LEDGpioNo, GPIO.HIGH)
        time.sleep(0.5)
    GPIO.output(LEDGpioNo, GPIO.LOW)

if __name__ == '__main__':

    GPIO.setmode(GPIO.BCM)

    # GPIO 27 set up as input. It is pulled up to stop false signals
    GPIO.setup(WatchGpioNo, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    # GPIO 4 set up as output.
    GPIO.setup(LEDGpioNo, GPIO.OUT)

    try:
        SlowBlink(5)
        while True:
            GPIO.output(LEDGpioNo, GPIO.LOW)
            syslog.syslog(syslog.LOG_INFO, "Waiting for falling edge on port %d" % WatchGpioNo)
            GPIO.wait_for_edge(WatchGpioNo, GPIO.FALLING)
            syslog.syslog(syslog.LOG_INFO, "Falling edge detected.")
            if KeepWatchForSeconds(5):
                SlowBlink(5)
                CallShutdown()
                break
        GPIO.cleanup()           # clean up GPIO on normal exit
    except KeyboardInterrupt:
            GPIO.cleanup()       # clean up GPIO on CTRL+C exit


 単にスイッチを監視しているだけでは、スイッチを「ちょん」と押しただけでシャットダウンが走ります。自分の感覚としては、PC並みに数秒間押し続けてからシャットダウンしたほうが安心なので、ある程度の時間継続してスイッチが押されたことを見届けてからshutdownが走るようにしました。
 また、スイッチだけで表示が無いと、シャットダウンが受け付けられたか否かがしばらく待たないとわかりません。GPIO4にLEDを接続して、点滅動作で受付状況がわかるようにしました。

 試運転中の動画は、こちら。