Raspberry Pi mittels “Hardware-Taster” hoch und herunterfahren!

Hintergrund:

Der Raspberry verfügt leider über keinen richtigen Ein-/Ausschalter, was zum (sicheren) Herunterfahren meist eine ssh-Verbindung oder einen angeschlossensen Monitor incl. Maus nötig macht. Allerdings gibt es auch geschicktere Wege, von denen ich euch hier einen beschreiben will.

Wenn der Raspberry-Pi über “shutdown -h now” abgeschaltet wurde, kann er mittes eines zeitlich begrenzten (ca. 0,5 sec) Kurzschlusses zwischen GPIO3 und GND wieder “geweckt” werden, ohne dass man ihm den Netzstecker ziehen und wieder einstecken muss.

Mittels eines zusätzlichen Scriptes, kann man nun dafür sorgen, dass sich der Pi auch genau so wieder ausschalten lässt.

Hochfahren mittels Taster

Hardware-Seitig installiert man einen alten Power-/Reset-Taster aus einem ausrangierten PC zwischen GPIO3 und GND:

Sobal der Taster installiert ist, könnt ihr das hochfahren mittels Taster gleich mal testen! Meldet euch dafür wie gewohnt an eurem Pi an, und fahrt ihn herunter. Dies geht entweder über die GUI (Desktopoberfläche) oder mittels ssh und dem Befehl:

sudo shutdown -h now

Sobald der Pi heruntergefahren ist, brennt nur noch das rote Status-LED und das grüne Status-LED hat aufgehört zu flackern. Sobald ihr nun den Taster kurz drückt, müsste das grüne LED erneut zu blinken beginnen. Euer Raspberry fährt nun hoch!

Herunterfahren mittels Taster

Zum Herunterfahren ist etwas mehr Arbeit notwendig… zum einen benötigt ihr eine Shutdown-Script, welches ich in Python geschrieben habe.

import RPi.GPIO as GPIO
import subprocess as sp
import time
import sys

timeToExit = False

def shutdown(GPIO_CHANNEL):
       global timeToExit
        if not timeToExit:
              timeToExit = True
              systemCall("wall 'Power-Switch was pressed, Shutdown now. See you later!'")
              systemCall("sudo shutdown -h now")

def systemCall(command):
       return_value = sp.Popen(command, shell=True, stdout=sp.PIPE).stdout.read()
       return return_value

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD) #setup GPIO using Board numbering (pins, not GPIOs)
GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(5, GPIO.FALLING, callback=shutdown, bouncetime=100)

# wait ...
while True:
       try:
              time.sleep(1)
              if timeToExit:
                     break
       except KeyboardInterrupt:
              GPIO.remove_event_detect(5)
              GPIO.cleanup() # clean up GPIO on CTRL+C exit
              sys.exit(1) # exit with status 1
GPIO.remove_event_detect(5)
GPIO.cleanup() # clean up GPIO on CTRL+C exit
sys.exit(0) # exit with status 0

shutdown_daemon.py herunterladen
oder weitere Varianten aus meiner Dropbox

Zum Betrieb, ist eine zusätzliche Python Lib notwendig, welche nicht von Anfang an installiert ist. Um diese nach zu installieren, einfach in einem Terminal auf dem Pi:

sudo apt-get install python-rpi.gpio

Am besten ihr kopiert das Script direkt in euer Home-Verzeichnis (/home/pi/). Sobald ihr das geschafft habt, könnt ihr das Script einfach testen:

python ~/shutdown_daemon.py

Im Anschluss daran seht ihr erst einmal nichts (auch keine Fehlermeldungen… sonst ist etwas schief gelaufen! In manchen Fällen kann es sein, dass eine Warnung angezeigt wird:“RuntimeWarning: A physical pull up resistor is fitted on this channel!”, welche jedoch völlig normal ist). Allerdings mit einem erneuten Druck auf euren kürzlich installierten Taster, solltet ihr eine Meldung erhalten, dass der Pi nun Heruntergefahren wird. Kurz darauf, sollte das grüne Licht auf eurem Pi wieder sein Flackern einstellen und Ruhe einkehren…

Um nun das Script nicht immer von Hand aufrufen zu müssen, tragen wir die Ausführung dieses Scripts in die rc.local ein:

sudo nano /etc/rc.local

Öffnet die Datei mittels dem Editor “nano”. Ihr tragt vor dem “exit 0” in der rc.local nun folgenden Befehl ein:

/usr/bin/python /home/pi/shutdown_daemon.py &

Wichtig: Das “&” am Ende der Zeile, sorgt dafür, dass der Prozess im Hintergrund ausgeführt wird und den Boot nicht blockiert!

Anschließend sollte eure rc.local in etwa so aussehen:

#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi

# CUSTOM: Start a service in background, monitoring GPIO3 as an
# on /off swith:

/usr/bin/python /home/pi/shutdown_daemon.py &

exit 0

Mittels eines STRG+o (= Speichern) und eines STRG+x (= Beenden) schließt ihr den Editor wieder.

Anschließend noch ein Reboot, um das Script automatisch starten zu lassen und dessen Funktion zu testen.

sudo reboot

Sobald euer Pi wieder gestartet ist, müsste das Script im Hintergrund laufen und ihr solltet im Stande sein, mit einem kurzen Druck auf euren Taster, den Pi nun auch wieder herunter zu fahren…

Geschaft!

Damit könnt ihr nun euren Pi jederzeit herunter oder hochfahren, einfach mit einem klick auf den Taster!

Mittlerweile gibt es hierzu euch eine Video-Anleitung auf YouTube:

Viel Erfolg!

18 Kommentare

  1. Ich bekomme beim Testen des scripts “python ~/shutdown_daemon.py” immer die Fehlermeldung:
    File “/home/pi/shutdown_daemon.py”, line 9
    global timeToExit

    IndentationError: expected an indented block

    Woran könnte das liegen?

    1. Hallo Steve,

      du hast anscheinend das den Code direkt von der Homepage “kopiert”, da “global timeToExit” eigentlich in Zeile 24 stehen würde und nicht in Zeile 9 🙂 -> Wenn du es über den Link unter dem Text heruntergeladen hättest).
      Höchstwarscheinlich ist beim copy/paste, abhängig von deinem Browser und dem verwendeten Text-editor ein Problem mit dem “einrücken” bekommen (keine Tabulatorensprünge sondern 4 aueinanderfolgende Leerzeichen verwenden!). Das macht einen Unterschied.

      Schau dir die Formatierung dahingehend nochmal an… lösche jede Leerzeichenfolge am Zeilenanfang wenn es sein muss und ersetze sie mit je 4 Leerzeichen pro Einrückungsebene. Alternativ, versuch mal das File direkt über den Link herunter zu laden und aus zu führen. Hierbei solltest du keinen Fehler bekommen.

      Empfehlung: Nimm anstatt den “ganz normalen” Shutdown_daemon lieber den “shutdown_daemon_interference_secure” wie im Readme File in meiner Dropbox beschrieben.
      Dieser ist “sicherer” und kann auch die ein oder andere Spannungsschwankung während den normalen Bastlereien ganz gut ab 😉

      Viel Spass beim Basteln !

  2. Ich plane bei meinem Aufbau den Einsatz einer Hiffiberry Amp+, der wie ich gelesen habe, gpio 2-3 und 18-21 einnimmt. Gibt es für den Einsatz des tasters die Möglichkeit noch andere gpio zu verwenden?

    1. Hallo Christian, zum “Ausschalten/Herunterfahren” kannst du jeden freien GPIO verwenden. Allerdings funktioniert das “Aufwecken” aus einem Halt-Zustand leider nur über Pin5, da dieser mit dem Interrupt des µC verbunden ist (soweit zumindest mein Wissensstand). Um die volle Funktionalität eines Ein-/Ausschalters zu bekommen, bis du also leider an den Pin5 gebunden. Gruß Matthias

  3. Hallo matthias,
    ich habe das Script installiert und alles funktioniert soweit. Leider kann ich den Raspberry nur mittels Schalter einschalten. Ein shutdown über den Taster klappt nicht. Hast Du eine Idee?
    Grüße
    Ulli

    1. Hallo Ulli, es scheint das Script nicht automatisch gestartet zu werden… hast du schon mal probiert, das Script direkt aus zu führen (sudo python /home/pi/shutdown_daemon.py) damit siehst du auch was genau passiert, wenn du den Taster drückst. Je nach Variante die du verwendest, kann es sein, dass du 2-3 Sek halten musst.
      Wenn es auf dem manuellen weg klappt, kann es nur noch an deinem Eintrag in der rc.local liegen.

      Gruß
      Matthias

  4. Hallo Matthias,
    erst einmal vielen Dank für das Skript! Das Herunterfahren funktioniert wunderbar solang keine Anwendung, in meinem Fall ist es Kodi, läuft. Hast du irgendeine Idee warum? Kodi lasse ich beim Systemstart automatisch starten.

    Gruß
    Denny

    1. Hallo Denny, zufälliger Weise hatte ich die selbe Konstellation auch schon mal am Laufen und kann daher bestätigen, dass “andere” Programme keinen Einfluss auf die Reaktion des Scripts haben! Ich gehe davon aus, dass du das Script auf einen Weise startest, die von “dem anderen Programm” (in deinem Fall, Kodi) unterbunden wird. Startest du das Script genau so, wie ich es im Artikel gemacht habe (über rc.local)? Wie startest du Kodi? Viele Grüße, Matthias

  5. Hat super funktioniert , leider war dann der Ton aus beim Hifiberry amp2. Habe dann nachgelesen:
    GPIO2-3 (pins 3 and 5) are used by our products for configuration. If you are experienced with I2C, you might add other slave devices. If you a a novice, we don’t recommend this at all.
    GPIOs 18-21 (pins 12, 35, 38 and 40) are used for the sound interface. You can’t use these for any other purpose.
    GPIO4 is used to control the MUTE function of the power stage. Pulling it to low will mute the output.
    Gibt es einen alternativen Pin?

    1. Hallo Stefan, meines Wissens gibt es leider keinen Alternativen Pin… Sorry. Anscheinend ist diese Lösung nicht für Hifiberrys geeignet 😉 MFG Matthias

  6. Ist das Script nicht für den Pi 4 geeignet?
    Bei meinem ersten Versuch startete mein Pi 4 nicht mehr.
    Habe dann die Speicherkarte formatiert und Raspbian neu aufgespielt.

    1. Hallo Thomas,
      ich wüsste nicht, wieso das Script nicht auch auf dem Raspi4 laufen sollte… Allerdings habe ich das noch nie getestet, da ich noch keinen so neuen Pi besitze 🙂
      Mein Tipp ist eher, dass sich ein Fehler im Befehl in der rc.local eingeschlichen hat.
      Kann das sein?

      Matthias

  7. Hallo,
    Danke für Skript und Beschreibung.
    Es funktioniert leider nicht wenn ich den Befehl “wall” nicht auskommentiere.
    –>
    systemCall(“wall ‘Power-Switch was pressed, Shutdown now. See you later!'”)

    Ich bekomme sonst folgende Meldung:
    cannot get tty name sys.excepthook is missing

    Ohne diese Zeile funktioniert wie es sein soll.

    ami

    1. Hallo ami, diese Fehlermeldung deutet darauf hin, dass der Benutzer der das Script ausgeführt hat, scheinbar kein TTY besitzt bzw. keine Rechte dazu. Wie startest du das Script? Über die rc.local? Oder vielleicht mit einem Cron-Job?
      Gruß
      Matthias

      1. Hallo,

        Danke für schnelle Antwort.
        ich starte über rc.lokal, wo es nicht geht.
        /usr/bin/python /home/pi/shutdown_daemon.py &

        Es geht wenn ich den Skript manuell starte:
        python /home/pi/shutdown_daemon.py &

        Ami

        1. Hm, das sollte eigentlich dennoch funktionieren. Was ich mir vorstellen könnte ist, dass es ab einer Debian-Version bei dem Systemd die “rc.local” abgelöst hat (die tatsächliche rc.local, wird ja mittlerweile durch einen speziellen Systemd-Service ausgeführt…) zu oben genannten Rechteproblem kommt. Wenn du noch Elan genug hast, kannst du vielleicht mal den Debian-Installer aus diesem Beitrag probieren. Hierin ist ein Systemd-Service enthalten, der das Script ausführt…
          Ansonsten muss ich in das Python-Script selbst mal ein try/except einbauen.
          Ich muss das demnächst mal nochmal mit einem aktuellen Raspbian Buster testen 😉

Schreibe einen Kommentar zu Ulli Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.