Ausschalter für Raspberry Pi

(siehe: Setup des RPi)
Wenn man den Raspberry Pi als Server (d.h. ohne Tastatur, Maus oder Monitor) betreibt, ist man darauf angewiesen, sich per SSH einzuloggen. Wenn aber der SSH-Dienst abstürzt, ist man sozusagen ausgesperrt und man kann den RPi nicht mehr ordentlich herunterfahren. (Ein einfaches Ausstecken kann u.U. zu Datenverlust führen!)
Daher kann man sich einfach mit einem Mikrotaster und einem kleinen Script einen simplen Ausschalter bauen, der den RPi regulär herunterfährt.

Anschlüsse des Raspberry Pi

Der RPi besitzt sogenannte GPIO-Pins, dies ist die Abkürzung für General Purpose Input Output. Man bezeichnet damit programmierbare Ein- und Ausgänge für allgemeine Zwecke. Diese GPIOs sind bei RPi v3 als Stiftleiste verbaut und dienen als Schnittstelle zu anderen Systemen oder Schaltungen. Dabei können je nach Programmierung digitale Signale von außen angenommen (Input) oder abgegeben (Output) werden. Neben den typischen Ein- und Ausgängen haben einige Pins auch eine Doppelfunktion für I²C, SPI und eine serielle Schnittstelle.

Anschlüsse des Raspberry Pi 3+
Abb.: Anschlüsse des Raspberry Pi 3+ (Quelle/Copyright: raspberrypi.org)

Verwendete Bauteile

Aufbau

In diesem Beispiel nehmen wir den Pin #13 (GPIO 27) und den gegenüber liegenden Pin #14 (GND).

Aufbau der Schaltung: Mikrotaster am Raspberry Pi

Es gibt jedoch noch eine einfachere Möglichkeit: Man verwendet statt dem Mikrotaster einen 2,54 mm Jumper (=Steckbrücke) zum Überbrücken der GPIOs. Beim Herausnehmen des Jumpers soll dann der RPi heruntergefahren werden.

2,54 mm Standard Jumper
Abb.: 2,54 mm Standard Jumper
Jumper auf den GPIOs des Raspberry Pi
Abb.: Jumper auf den GPIOs des Raspberry Pi

Code

Python

#! /usr/bin/env python
import os
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
# GPIO27 (pin 13) set up as input. It is pulled up to stop false signals
GPIO.setup(27, GPIO.IN, pull_up_down=GPIO.PUD_UP)

try:
    while True:
        # wait for the pin to be sorted with GND and, if so, halt the system
        GPIO.wait_for_edge(27, GPIO.FALLING)
        print ("Shutting down...")
        os.system("/sbin/shutdown -h now")
except:
        GPIO.cleanup()

Das obige Python-Script wird in einer Datei gespeichert (z.B. "/home/pi/shutdown_btn.py") und dann ausgeführt:
sudo python /home/pi/shutdown_btn.py
Sobald jetzt der Taster gedrückt wird (oder im alternativen Fall: der Jumper entfernt wird), fährt der RPi sofort herunter und kann wenige Sekunden später vom Strom getrennt werden.

Soll dieses Verhalten permanent zur Verfügung stehen, dann muss das Script per crontab beim Start des RPi ausgeführt werden:
sudo nano /etc/crontab
Nun wird folgende Zeile eingefügt und gespeichert:
@reboot root /usr/bin/python /home/pi/shutdown_btn.py
Das gewünschte Verhalten ist nun bei jedem Start vorhanden.

C/C++

Der folgende Code besitzt Dasselbe Verhalten wie der obige Python-Code, ist aber in diesem Fall nach der Kompilierung nicht auf einen Interpreter angewiesen und dadurch etwas resourcensparender. Um in C auf die GPIOs des RPi zugreifen zu können wird hier die Library wiringPi verwendet. (Installation siehe: Download and Install)

#include <stdlib.h>
#include <wiringPi.h>

#define PIN_BUTTON 29 // = Pin #40

int main(void)
{
    wiringPiSetup();
    pinMode(PIN_BUTTON, INPUT);
    pullUpDnControl (PIN_BUTTON, PUD_UP);

    while(1) {
        delay(1000);
        if (digitalRead(PIN_BUTTON) == 1) {
            system ("sudo shutdown -h now");
        }
    }
}

Zum Kompilieren des Codes wird dieser in eine Datei gespeichert (hier: shutdown.c) und folgende Befehlszeile ausgeführt:
gcc -o check-shutdown check-shutdown.c -l wiringPi
Dann kann das Programm mit $ ./check-shutdown ausgeführt werden. Entfernt man nun den Jumper vom GPIO, wird der RPi heruntergefahren.

Um diese Logik auch nach jedem Reboot zur Verfügung zu haben, kann man einen Service anlegen, der permanent den obigen Pin überwacht. Zunächst wird die kompilierte Datei check-shutdown nach /usr/bin/ kopiert.
Im Ordner /lib/systemd/system wird nun eine neue Datei (z.B. check-shutdown.service) mit folgendem Inhalt angelegt:
[Unit]
Description=Monitoring GPIO pin for shutdown RPi
[Service]
ExecStart=/usr/bin/check-shutdown
ExecStop=/bin/systemctl kill check-shutdown
[Install]
WantedBy=multi-user.target

Nun wird im Ordner /lib/systemd/system der Service aktiviert:
systemctl enable check-shutdown.service
Nach dem Reboot des RPi wird nun der GPIO 40 automatisch überwacht.

zurück