SSブログ

Raspberry Piにリブート/シャットダウンスイッチをつける [Raspberry Pi]

Raspberry Pi B+/Pi 2 B用のリブート/シャットダウンスイッチを作ってみました。

まずは、Raspberry Piに取りつけるリブート/シャットダウンボタンを製作します。

resetbutton1.jpg
▲秋月で購入した2ピンタクトスイッチと、好みの長さに切断できる分割ロングピンソケットで、リセット/シャットダウンスイッチを作ります。RasPi内蔵プルアップ抵抗を使うので、外付け抵抗は不要です。

resetbutton2.jpg
▲タクトスイッチを、Pin39(GND)-Pin40(GPIO21)間に挿します。

電子工作はこれだけ。超カンタン。


続いて、リブート/シャットダウンスクリプトを作成。あらかじめ、Python(Python3) GPIOモジュールもインストールしておきましょう。
$ sudo aptitude install python-rpi.gpio pyhton3-rpi.gpio


スクリプトの仕様と、動作シーケンスは以下のとおりです。

(1) リブート/シャットダウンスクリプトが起動すると、オンボードPower LEDが点滅します(2秒毎に0.1秒間消灯)。
(2) タクトスイッチを1秒以上押し続けると、LEDがゆっくり点滅(3秒間)。この間にスイッチを離すとリブートします。
(3) さらにタクトスイッチを押し続けると、LEDが速く点滅(3秒間)。この間にスイッチを離すとシャットダウンします。
(4) さらにタクトスイッチを押し続けると、リブート/シャットダウン処理をキャンセルできます。
(1)へ戻る

リセットボタンを押したあとに「いかん! 編集中のデータをまだ保存してなかった!」的な事態に陥っても、ボタンを長押ししつづければ危機回避が可能な仕様となっております。


$ sudo vi /usr/local/bin/resetbutton.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#
# REBOOT & SHUTDOWN Button
# for Raspberry Pi B+ / Pi 2 B
# Written by gaecen ueno
# [Dec.24,2015]
#
#===================================================================
#
# GPIO Connection
# S=TACT SW (GPIO 21) / G=GND
#
# 3 3 3 3 3 2 2 2 2 2 1 1 1 1 1 0 0 0 0 0
# 9 7 5 3 1 9 7 5 3 1 9 7 5 3 1 9 7 5 3 1
# G - - - - - - G - - - - - - - G - - - -
# S - - - - - - - - - G - - G - - - - - -
# 4 3 3 3 3 3 2 2 2 2 2 1 1 1 1 1 0 0 0 0
# 0 8 6 4 2 0 8 6 4 2 0 8 6 4 2 0 8 6 4 2
#
# Holding down the button(tact switch)
#   | [1second]
#   | [3seconds](LED blink slowly)  Release the button -> Reboot
#   V [3seconds](LED blink faster)  Release the button -> Shutdown
# Abort Reboot and Shutdown

GPIO_BUTTON = 21  # GPIO 21(pin40) -> TACT SW -> GND
GPIO_LED = 35     # GPIO 35 is On-Board PWR LED(/sys/class/leds/led1)

LED_BLINK_TIME = [
  [1.9, 0.1],    # default  on=1.9sec off=0.1sec
  [0.5, 0.5],    # reboot   on=0.5sec off=0.5sec
  [0.1, 0.1]     # shutdown on=0.1sec off=0.1sec
]

#===================================================================

import  RPi.GPIO as GPIO
import  time
import  os

SHUTDOWN_NONE = 0
SHUTDOWN_REBOOT = 1
SHUTDOWN_HALT = 2


def getButtonState(io):
  cnt = 0
  prev_btn = not GPIO.input(io)

  while cnt < 3:
    time.sleep(0.01)
    btn = not GPIO.input(io)
    if prev_btn == btn:
      cnt += 1
    else:
      prev_btn = btn
      cnt = 0

  return btn


def callback(ch):
  global  shutdown_mode
  global  do_shutdown

  # Waiting for holding down the button.(1sec)
  for i in range(10):
    btn = getButtonState(GPIO_BUTTON)
    if btn == False:
      break
    time.sleep(0.1)

  # [REBOOT] Release the button when the LED is blinking slowly.(3sec)
  else:
    shutdown_mode = SHUTDOWN_REBOOT
    for i in range(30):
      btn = getButtonState(GPIO_BUTTON)
      if btn == False:
        do_shutdown = True
        break
      time.sleep(0.1)

    # [SHUTDOWN] Release the button when the LED is blinking faster.(3sec)
    else:
      shutdown_mode = SHUTDOWN_HALT
      for i in range(30):
        btn = getButtonState(GPIO_BUTTON)
        if btn == False:
          do_shutdown = True
          break
        time.sleep(0.1)

  if do_shutdown == False:
    shutdown_mode = SHUTDOWN_NONE

  return

#===================================================================

if __name__ == '__main__':
  GPIO.setwarnings(False)
  GPIO.setmode(GPIO.BCM)
  GPIO.setup(GPIO_LED, GPIO.OUT, initial=GPIO.HIGH)
  GPIO.setup(GPIO_BUTTON, GPIO.IN, pull_up_down=GPIO.PUD_UP)

  shutdown_mode = SHUTDOWN_NONE
  do_shutdown = False

  GPIO.add_event_detect(GPIO_BUTTON, GPIO.FALLING, callback=callback)

  try:
    while do_shutdown == False:
        GPIO.output(GPIO_LED, GPIO.HIGH)
        time.sleep(LED_BLINK_TIME[shutdown_mode][0])
        GPIO.output(GPIO_LED, GPIO.LOW)
        time.sleep(LED_BLINK_TIME[shutdown_mode][1])

    if shutdown_mode == SHUTDOWN_REBOOT:
      os.system("sudo shutdown -r now > /dev/null 2>&1")
    elif shutdown_mode == SHUTDOWN_HALT:
      os.system("sudo shutdown -h now > /dev/null 2>&1")

  except KeyboardInterrupt:
    pass

  finally:
    GPIO.cleanup(GPIO_LED)
    GPIO.cleanup(GPIO_BUTTON)


スクリプトを起動し、動作確認を行います。
$ sudo chmod 755 /usr/local/bin/resetbutton.py
$ sudo /usr/local/bin/resetbutton.py

リブート、シャットダウンともに正しく動作することを確認できたら、/etc/rc.localの最終行(exit 0)の前の行に /usr/local/bin/resetbutton.py & を追加し、リブートしましょう(※1)。Raspberry Pi起動時に、リブート/シャットダウンスクリプトを自動起動することができます。

※1
/etc/rc.localを書き換えて自動起動させた場合、スクリプトの入力ミスやタクトスイッチに不具合があると、最悪の場合リブートをくり返す可能性があります。Win32DiskImagerなどを使って、事前にシステムのバックアップをとっておきましょう。


※2
拙宅のB+/2 Bでは正しく作動しましたが、古いB+だとエラーが出たり、オンボード Power LEDが点滅しないかもしれません。sudo rpi-updateでファームウェアを更新したり、aptitudeやapt-getで導入済みパッケージの更新を行ってみてください。



入門 Python 3

入門 Python 3

  • 作者: Bill Lubanovic
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2015/12/01
  • メディア: 単行本(ソフトカバー)



実践 Python 3

実践 Python 3

  • 作者: Mark Summerfield
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2015/12/01
  • メディア: 単行本(ソフトカバー)






Sponsored Link


nice!(0)  コメント(1)  トラックバック(0) 
共通テーマ:パソコン・インターネット

nice! 0

コメント 1

Austin

とても丁寧で参考になりました。ありがとう御座います。このようなページを作って頂き、感謝致します。

1点、最後の箇所で上手くいかない点がありましたので、コメント致しました。

> /rc.localの最終行(exit 0)の前の行に /usr/local
> /bin/resetbutton.py & を追加し、リブートしましょう(※1)。
▲こちらの local が不要でした。
見ればすぐ分かるのでアレですが。。。
コピペ初学者の為に、触れさせて頂きました。


by Austin (2016-11-04 12:28) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。