Raspberry Pi – przycisk zasilania dla malinki

Odkąd zacząłem używać malinki rzeczą której najbardziej mi brakowało (szczególnie, kiedy już odłączyłem się od SSH) był przycisk, którym mógłbym malinkę włączyć, wyłączyć lub zresetować. W dzisiejszym artykule dowiemy się jak w prosty sposób zrobić sobie taki elegancki guziczek :)

Robimy przycisk

Fizyczny przycisk postanowiłem zrobić z tact-switcha oraz 2 pinowego żeńskiego złącza goldpin.

Zaginamy piny przycisku do środka, a oba piny złącza goldpin w przeciwne strony:

Teraz wsuwamy piny złącza pomiędzy zagięte piny przycisku

a następnie używając nieco kalafonii lutujemy złącza ze sobą.

Ja postanowiłem obkurczyć jeszcze całość koszulką termokurczliwą w ten sposób:

Teraz nasz przycisk jest już gotowy. Możemy go nasunąć na trzecią parę pinów tak jak u mnie:

Skrypt pythona

Mózgiem naszego przesięwzięcia będzie python, który poczeka na wciśnięcie przycisku, a następnie poczeka na jego zwolnienie. Po tych dwóch zdarzeniach obliczy czas przez jaki przycisk był wciśnięty i na tej podstawie zadecyduje czy wydać polecenie restartu malinki, czy też wyłączenia.

Aby utworzyć skrypt przechodizmy do folderu /usr/local/bin/, następnie tworzymy w nim katalog o nazwie powerbtn, a w owym katalogu plik powerbtn.py i edytujemy go.

cd /usr/local/bin/
sudo mkdir powerbtn
cd powerbtn
sudo touch powerbtn.py
sudo nano powerbtn.py

Wpisujemy do niego następującą treść:

#!/usr/bin/env python

import RPi.GPIO as GPIO
import time
import subprocess

SHUTDOWN_PIN = 3
LONG_PRESS_TIME_IN_SECONDS = 2.0

GPIO.setmode(GPIO.BCM)
GPIO.setup(SHUTDOWN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)


GPIO.wait_for_edge(SHUTDOWN_PIN, GPIO.FALLING)
buttonPressStart = time.time()

GPIO.wait_for_edge(SHUTDOWN_PIN, GPIO.RISING)
buttonPressedTime = time.time() - buttonPressStart

GPIO.cleanup()

if LONG_PRESS_TIME_IN_SECONDS > buttonPressedTime:
  subprocess.call(["shutdown", "-h", "now"])
else:
  subprocess.call(["shutdown", "-r", "now"])

gdzie SHUTDOWN_PIN to numer pinu według numeracji na stronie https://pinout.xyz/ (numerki oznaczone BCM x). Polecam zostać przy pinue numer 3, gdyż jest on w pewnien sposób specjalny. Jeżeli zewrzemy go do masy kiedy Raspberry jest wyłączone, to spowoduje uruchomienie komputerka. Tym samym załątwimy sobie jednym przyciskiem 3 różne funkcje (wyłączenie, restart oraz włączenie).

LONG_PRESS_TIME_IN_SECONDS to jak sama nazwa wskazuje czas długiego wciśnięcia przycisku wyrażony w sekundach.  Jeżeli wciśnięcie przycisku będzie krótsze od tej wartości to malinka się wyłączy, a w przeciwnym wypadku zrestartuje.

Kiedy zapiszemy plik nadajemy jeszcze tylko uprawnienia do wykonywania:

sudo chmod +x powerbtn.py

Tworzymy serwis dla naszego skryptu

W poszukiwaniu informacji o tworzeniu własnego daemona natknąłem się na wpis, w którym autor przedstawił ciekawy wzór skryptu daemona:

http://blog.scphillips.com/posts/2013/07/getting-a-python-script-to-run-in-the-background-as-a-service-on-boot/

Na podstawie tego skryptu robimy nasz zmieniając kilka linijek.

Najpierw przechodzimy do /etc/init.d i tworzymy tam plik powerbtn.sh

cd /etc/init.d/
sudo touch powerbtn.sh
sudo nano powerbtn.sh

I wpisujemy do niego taką zawartość:

#!/bin/sh

### BEGIN INIT INFO
# Provides:          powerbtn
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Power button service
# Description:       Invokes system restart on long button press or system shutdown on short button press
### END INIT INFO

DIR=/usr/local/bin/powerbtn
DAEMON=$DIR/powerbtn.py
DAEMON_NAME=powerbtn

DAEMON_OPTS=""

DAEMON_USER=root

PIDFILE=/var/run/$DAEMON_NAME.pid

. /lib/lsb/init-functions

do_start () {
    log_daemon_msg "Starting system $DAEMON_NAME daemon"
    start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER --chuid $DAEMON_USER --startas $DAEMON -- $DAEMON_OPTS
    log_end_msg $?
}
do_stop () {
    log_daemon_msg "Stopping system $DAEMON_NAME daemon"
    start-stop-daemon --stop --pidfile $PIDFILE --retry 10
    log_end_msg $?
}

case "$1" in

    start|stop)
        do_${1}
        ;;

    restart|reload|force-reload)
        do_stop
        do_start
        ;;

    status)
        status_of_proc "$DAEMON_NAME" "$DAEMON" && exit 0 || exit $?
        ;;

    *)
        echo "Usage: /etc/init.d/$DAEMON_NAME {start|stop|restart|status}"
        exit 1
        ;;

esac
exit 0

Po czym ustawiamy chmoda:

sudo chmod +x powerbtn.sh

Usuwamy powroty karetek

Jeżeli edytowaliśmy nasze pliki na systmie Windows prawdopodobnie na końcu każdej linii są tam znaki \r\n. Niestety linux i windows mają nieco odmienne zdanie na temat kodowania końca linii i aby nasze pliki dało się uruchomić pod linuxem musimy usunąć znak powrotku karetki \r.

Robimy to za pomocą sed’a:

sudo sed -i -e 's/\r//g' /etc/init.d/powerbtn.sh
sudo sed -i -e 's/\r//g' /usr/local/bin/powerbtn/powerbtn.py

Uruchamiamy serwis

Teraz możemy ręcznie uruchomić serwis wpisując do wiersza poleceń następującą komendę:

sudo /etc/init.d/powerbtn.sh start

a także zakomunikować malince, aby uruchamiała serwis automatycznie po starcie systemu:

sudo update-rc.d powerbtn.sh defaults

i sprawdzamy czy wszystko działa przyciskając na krótko lub przytrzymując na dłużej nasz przycisk :)

Kiedy uruchomimy ponownie naszą malinkę serwis powinien wystartować automatycznie. Od teraz możemy cieszyć się eleganckim przyciskiem zasilania.