Prorgammstart/stop per Taster

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Moin,
    ich habe auf meinem Raspberry den mpd laufen und habe es so eingestellt, dass er automatisch die 1. Playliste abspielt, wenn er hochfährt.
    Da ich aber nicht immer den Stecker ziehen will, wäre es sinnig einen Schalter dafür einzubauen (will mich nicht per ssh oder ähnlichem verbinden) z.B. Morgens wenn ich aufstehe einfach den SCHALTER1 drücken - fertig.

    Außerdem habe ich noch UV4L laufen (was aber nicht immer aktiv sein soll) also auch hier einen Taster, bei dem ich sagen kann UV4L an (SCHALTER2) und vorher würde ich SCHALTER1 nochmals drücken um das Radio auszumachen.

    Also Theoretisch soll 1 Schalter 2 aufgaben erfüllen. Beim 1. Drücken an beim 2. Drücken aus.
    Ist sowas möglich? Wenn ja, wie? Hat da jemand eine "ähnliche" Anleitung zu?
    Also ich habe schon mal nach Anleitung LEDs per GPIO angesteuert (also keine wirkliche Erfahrung damit).
    Wie muss die Schaltung aussehen? Brauche ich Widerstände dazu?
    Vielen Dank schonmal und ein schönes Wochenende. :thumbs1:

  • Das herunterfahren wäre vielleicht noch zusätzlich was.
    Nein ich habe vor per Knopfdruck einen Skript laufen zu lassen, bzw 2 Skripte. Wenn der erste (das starten des Programms) durchgeführt wurde soll es beim 2. Tastendruck wieder gestoppt werden. (vielleicht geht das auch mit der IF abfrage? Wenn das Programm läuft springe in Teil B des Skripts und stoppe das Programm?!

  • Beim starten eine Variable schreiben nach dem motto "programm = läuft" und die immer abfragen.
    Wenn programm = läuft, dann programm schließen ;)

    EDIT: das hoch / Runterfahren wurde zB in dem Thread schon durchgekaut :)
    https://www.forum-raspberrypi.de/Thread-tutoria…45918#pid145918

  • Du möchtest also einen Taster mit dem du den PI einschalten und auch wieder ausschalten (herunterfahren) kannst? Dann guck mal hier: Hoch- und runterfahren mittels Taster (incl. Status-LED) wobei das Script im ersten Beitrag nicht so toll ist, besser wäre eins auf Basis von Interrupts. Siehe dazu Beitrag #210

    Für den 2.Taster um zwischen UV4L und mpd umzuschalten brauchst du nicht unbedingt einen extra/externen Widerstand (Pull Up/Down), das geht auch Softwareseitig. Den Taster schließt du dann zwischen den gewünschten GPIO und GND an und aktivierst den internen Pull-Down des GPIOs.

    Problematisch wirds dann nur den jeweiligen Zustand zu ermitteln - da ich kein UV4L habe weiß ich auch nicht ob dann ein Prozess läuft den man prüfen kann. Man könnte aber auch einfach nur auf den laufenden Prozess mpd prüfen und falls dieser nicht läuft annehmen das aktuell UV4L läuft ;)

    Du kannst das alles über nur ein Script realisieren sofern du Interrupts verwendest.

    Ich bin generell kein Freund vom mischen, also wenn man in einer bestimmten Programmiersprache schreibt sollte man möglichst viel nativ in dieser Sprache machen, ohne auf externe/andere Programme auszuweichen. Deshalb würde ich Abstand davon nehmen mithilfe subprocess (also ausführen eines Konsolen Befehls) zu prüfen ob der jeweilige Prozess läuft. Das geht eleganter und schöner mithilfe vom python Modul psutil.

    Vorbereitung:

    Code
    apt-get update
    apt-get install build-essential python-dev python-pip
    pip install psutil

    Prüfen ob ein Prozess läuft:
    [code=php]
    import psutil

    def check_proc_running(procname):
    found = False
    for proc in psutil.process_iter():
    if proc.name() == procname:
    found = True
    return found

    if check_proc_running('apache2'):
    print 'apache2 laeuft!'
    else:
    print 'apache2 laeuft nicht!'
    [/php]

    Diese Information kann man dann beim drücken des 2.Tasters prüfen und falls der Prozess von MPD läuft beendet man diesen (zB. indem man an alle PIDs ein SIGTERM signal schickt) und startet anschließend UV4L. Drückt man den 2.Taster erneut wird der selbe Code ausgeführt, der dann feststellt das MPD nicht läuft und nimmt dann an das UV4L läuft welches dann beendet und MPD gestartet wird...

  • um nochmal ressourcen bzw CPU last zu sparen könnte man nach dem

    Code
    found = True

    noch ein

    Code
    break

    einbauen.
    Dann muss die For schleife nicht noch weiter durchlaufen, obwohl der Prozess schon gefunden wurde

    Die Funktion sollte dann so aussehen (wenn ich mich nicht komplett täusche):

    Code
    def check_proc_running(procname):
        found = False
        for proc in psutil.process_iter():
            if proc.name() == procname:
                found = True
                break
        return found
  • Ja stimmt, wobei die paar Millisekunden hier vermutlich nicht so viel ausmachen - aber kleinvieh macht auch Mist :thumbs1:

    Analyse:

    Spoiler anzeigen


    Es gäbe auch eine weitere Möglichkeit:

    Aber das sind ja nur Feinheiten die man später auch noch optimieren kann.. Hauptsache der TE versteht was gemeint bzw gemacht wird und schafft es sein Vorhaben umzusetzen ;)

  • Moin,
    können wir das mal Schritt für schritt durchgehen?
    Ich habe jetzt einen (offenen) Taster zwischen GPIO 23 und GND gesteckt.
    Den Pullup setze ich dann in der /boot/config.txt

    Code
    dtoverlay=gpiopin=16,pullup=on


    Ist das richtig so? w1??
    EDIT: Wie schreibt man denn dass der pullup down ist?!

    In deinem Script steht "procname" als Variable.(?) Wo nimmt der sich den Namen her?

    Einmal editiert, zuletzt von LuxOculus (14. April 2015 um 12:03)

  • Ok :thumbs1:

    Wie mache ich die "Programmierung", ohne einen 10k Widerstand? (hab ich nämlich gerade nicht zu Hand)

    zu den GPIOS - ich habe absolut keine Ahnung was dieser Pullup Widerstand bringt?!

    Zitat

    Bei einem Ausgang liegen gegenüber GND 3,3 Volt an. Bei einem Eingang werden Spannungen unter 0,8 V als "LOW" erkannt, Spannungen über 1,3 V als "HIGH". Über sog. Pullup oder Pulldwon-Widerstände nimmst Du Einfluss darauf, dass Spannungen im nicht definierten Bereich in den definierten Bereich gezogen werden.


    Das heißt ?!

    Ich vermute mal, dass ich den GPIO als Eingang definieren muss.
    (GPIO 23)

    Code
    echo "16" > /sys/class/gpio/export
    echo "in" > /sys/class/gpio/gpio16/direction
    echo "0" > /sys/class/gpio/gpio16/value


    Wird "value" dann auf "1" gesetzt wenn ich den Taster drücke?

    Eines steht fest: Wenn ich das alleine hinbekommen will, kann ich es gleich lassen ;)

    Ich hoffe mir wird geholfen :blush:

    Einmal editiert, zuletzt von LuxOculus (14. April 2015 um 13:17)

    • Offizieller Beitrag

    Können wir uns erstmal auf eine Sprache einigen? Alle Beispiele bis jetzt waren in python, das ist bash. Bei python brauchst du diesen export kram nicht machen, dafür gibt es ein Modul.
    Einen Taster ohne Widerstand zu betreiben funktioniert, resultiert aber in einer unsauberen Erkennung.
    Das simpelste Beispiel für einen Knopdruck sieht ungefähr so aus
    [code=php]#!/usr/bin/python
    import RPi.GPIO as GPIO
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(16,GPIO.IN)
    while True:
    if GPIO.input(16):
    print "Knopf gedrueckt"
    else:
    print "Knopf nicht gedrueckt"
    time.sleep(0.1)
    GPIO.cleanup()
    [/php]

  • Einen Taster ohne Widerstand zu betreiben funktioniert, resultiert aber in einer unsauberen Erkennung.

    Jeder GPIO pin hat einen Internen Pull up/down Widerstand integriert, den man via Software aktivieren kann. Es spielt also im Prinzip keine Rolle ob man einen Externen (Hardware) Pull Up/Down verwendet oder den integrierten - nur vergisst man gerne mal diesen via Software zu aktivieren wohingegen man einen Extra Hardware-Widerstand nicht so einfach vergisst (optisch sichtbar) :fies:

    Verwendet man für einen Eingang gar keinen Widerstand, kann (muss nicht aber durchaus möglich) sich der Zustand willkürlich/unkontrolliert ändern. Deshalb ist es hierfür wichtig.

    Den internen Pull Up/Down aktiviert man mithilfe des RPi.GPIO Modules bei der Initialisierung des GPIO pins (setup).
    Also zunächst legt man fest ob man BOARD oder BCM Belegung nutzen möchte:
    [code=php]# to use RaspberryPi gpio# (BCM) or pin# (BOARD)
    GPIO.setmode(GPIO.BCM)
    #GPIO.setmode(GPIO.BOARD)
    [/php]

    Dann folgt das Setup:
    [code=php]GPIO.setup(17, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) #GPIO -> GND
    GPIO.setup(20, GPIO.IN, pull_up_down = GPIO.PUD_UP) #GPIO -> 3V3[/php]

    Das nächste wäre, das man für Eingänge und gerade bei Tastern am besten Interrupts verwendet. Das hat zum einen den Vorteil das keine Änderung des Pins verpasst wird, der Interrupt Handler in einem separaten Thread läuft und das ganze zudem auch weniger CPU Last erzeugt als das von dbv genannte Beispiel.

    Also das Script selbst läuft in einem Thread. Scripts werden generell von oben nach unten, Zeile für Zeile, abgearbeitet.
    Setzt man jetzt im Script irgendwo ein sleep wird das Script angehalten und blockiert. In der Zeit kann das Script auf nichts anderes reagieren.... Kann man sich so vorstellen als würdest du von oben nach unten, Zeile für Zeile, mit dem Finger an einem Text entlang zeigen und sobald du ein 'sleep' liest bleibt dein Finger für die entsprechende Zeit stehen.
    Da der Interrupt dann aber vom Script selbst quasi abgespalten wird und auf einem "eigenen Blatt" läuft, ist dieser davon unabhängig und kann nicht von einem 'sleep' im Script beeinflusst werden. Und das hat eben zur Folge das ein Interrupt nahezu in Echtzeit auf eine Pegeländerung (von LOW auf HIGH, oder von HIGH auf LOW - jenachdem wie mans konfiguriert hat) reagiert.

    Desweiteren muss man das Script daran hintern sich zu beenden wenn es am Dateiende angekommen ist. Der allgemein am meisten verbreitete Weg ist einfach über eine while Schleife die sich immer im Kreis dreht. Das kann aber wie gesagt zu Problemen führen wenn der sleep zu kurz gesetzt ist, indem dann zu viel Aufmerksamkeit von der CPU gefordert wird.
    Ich hab mir angewöhnt stattdessen eine Funktion des 'signal' Module's zu verwenden, was nebenbei auch noch weitere nette Möglichkeiten bietet - aber das wirst du hier erst mal nicht brauchen ;)

    Lange Rede, kein Sinn:

    Du möchtest jetzt 2 verschiedene Taster nutzen.
    - Ein Taster soll zum Ein- und Ausschalten des PI's genutzt werden.
    - Ein Taster soll zum wechseln zwischen 2 Programmen genutzt werden.

    Beide Taster kannst du zunächst identisch initialisieren. Je nachdem welcher Taster gedrückt wurde führt man dann aber eben unterschiedliche Aktionen bzw Funktionen aus. Das kann alles ein Interrupt_Event_Handler handhaben.

    Also erst mal die Basic's:

    [code=php]#!/usr/bin/python
    # -*- coding: utf-8 -*-
    import RPi.GPIO as GPIO
    import signal

    #------------------------------------------------------------------------

    shutdownPin = 5 # with GPIO.BOARD pin#5 is gpio3
    progswitchPin = 7 # with GPIO.BOARD pin#7 is gpio4

    # to use RaspberryPi gpio# (BCM) or pin# (BOARD)
    #GPIO.setmode(GPIO.BCM)
    GPIO.setmode(GPIO.BOARD)

    #------------------------------------------------------------------------

    GPIO.setup(shutdownPin, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) #GPIO -> GND
    GPIO.setup(progswitchPin, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) #GPIO -> GND
    [/php]

    Nun definieren wir eine standard Funktion für den Interrupt:

    [code=php]
    def interrupt_event(pin):
    if GPIO.input(pin): # if pin == 1 or True
    print "Rising edge detected on %s" % pin
    else:
    print "Falling edge detected on %s" % pin
    [/php]

    Und jetzt initialisieren wir den Interrupt für jeden Pin und aktivieren somit auch den einen separaten Thread. Desweiteren möchten wir das Script auch noch beenden können indem wir STRG+C drücken und möchten dieses Event ebenfalls Scriptseitig erkennen sowie danach die GPIO's zurücksetzen.

    [code=php]
    try:
    GPIO.add_event_detect(shutdownPin, GPIO.BOTH, callback=interrupt_event, bouncetime=150)
    GPIO.add_event_detect(progswitchPin, GPIO.BOTH, callback=interrupt_event, bouncetime=150)
    [/php]
    Die bouncetime legt außerdem eine Softwareseitige Entprellung in Millisekunden fest. Das heißt innerhalb 150ms wird ein weiteres auslösen bzw Pegeländerung des Pins ignoriert. Gerade bei Tastern ist das gut zu haben.
    Man kann das auch Hardwareseitig lösen indem man einen 100uF Kondensator direkt am Taster zwischen die beiden Pins anbringt.

    Jetzt hindern wir das Script noch daran sich nicht zu beenden - sowie besagtes drücken von STRG+C zu bemerken:

    [code=php]
    #keep script running
    signal.pause()
    except KeyboardInterrupt:
    print "\nQuit\n"
    GPIO.cleanup()
    [/php]

    Damit hätte man schon mal ein Script welches auf Tastendruck etwas auf der Konsole ausgibt. Drückt man den Taster wird ein RISING edge erkannt, also der Pegelwechsel von LOW auf HIGH. Wird der Taster los gelassen wird ein FALLING edge erkannt, also ein Pegelwechsel von HIGH auf LOW.
    Möchte man nur eins der beiden erkennen / beachten, kann man bei der Initialisierung des Interrupts GPIO.BOTH auf GPIO.RISING oder GPIO.FALLING ändern.

    Script zusammengefasst:

    Spoiler anzeigen

    [code=php]#!/usr/bin/python
    # -*- coding: utf-8 -*-
    import RPi.GPIO as GPIO
    import signal

    #------------------------------------------------------------------------

    shutdownPin = 5 # with GPIO.BOARD pin#5 is gpio3
    progswitchPin = 7 # with GPIO.BOARD pin#7 is gpio4

    # to use RaspberryPi gpio# (BCM) or pin# (BOARD)
    #GPIO.setmode(GPIO.BCM)
    GPIO.setmode(GPIO.BOARD)

    #------------------------------------------------------------------------

    GPIO.setup(shutdownPin, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) #GPIO -> GND
    GPIO.setup(progswitchPin, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) #GPIO -> GND

    def interrupt_event(pin):
    if GPIO.input(pin): # if pin == 1 or True
    print "Rising edge detected on %s" % pin
    else:
    print "Falling edge detected on %s" % pin

    try:
    GPIO.add_event_detect(shutdownPin, GPIO.BOTH, callback=interrupt_event, bouncetime=150)
    GPIO.add_event_detect(progswitchPin, GPIO.BOTH, callback=interrupt_event, bouncetime=150)
    #keep script running
    signal.pause()
    except KeyboardInterrupt:
    print "\nQuit\n"
    GPIO.cleanup()
    [/php]

    Wenn du das soweit verstanden hast können wir uns gerne um dein eigentliches Anliegen kümmern :)

  • Ja cool!
    Das hat funktioniert und ich denke auch verstanden zu haben, was die einzelnen Befehle tun.

    Manchmal erkennt er aber nicht, dass der Pegel wieder fällt. Hängt das mit der "Bounce-time" zusammen?
    Wenn ja, könnte ich ja jedem Knopf sagen: Wenn er kurz gedrückt wird: Programm - geh an - wenn lang gedrückt wird, geh aus.
    Wie schreibe ich denn in diesem Python-Skript, dass er ein Programm starten soll? Vielleicht mit

    Code
    [...]
    echo sudo services mpd start
    [...]


    und ersetze

    Code
    print "Rising edge detected on %s" % pin

    Sonst:
    Wie mache ich das, dass sich ein weiteres Script öffnet und ausführt? Das könnte ich dann ja immer entsprechend ändern!

    Wobei ich das mit dem echo ja schon mal testen kann. Aber wahrscheinlich habt ihr eine bessere Idee?!

    Okay hab jetzt ganz zu Anfang gesagt:

    Code
    import os


    und dann vor dem Print

    Code
    os.system("service mpd stop")

    man bin ich stolz :D

    Danke schon mal für eure Hilfe!!!
    Ich denke das Thema ist erst einmal erledigt !

    Noch eines:
    :blush:
    Im Moment passiert bei beiden Pins das gleiche... Kann ich mehrere "if's" hintereinander schreiben und da dann die Pin Nummer manuell eintragen?
    Oder wie würdet ihr das machen?
    Danke.


    EDIT:
    Das Einzige, was jetzt stört ist das Else. Ich müsste wissen, wie ich einem Knopf 2 Funktionen zuweisen kann.
    Wie würde ich schreiben:

    Wenn die "bouncetime" von Pin 7 über 200 ist, dann mache "dies und das"?
    Dann kann ich das Else weglassen.

    Danke !

    Einmal editiert, zuletzt von LuxOculus (16. April 2015 um 11:44)

  • Manchmal erkennt er aber nicht, dass der Pegel wieder fällt. Hängt das mit der "Bounce-time" zusammen?

    Wenn du den Taster quasi zu schnell wieder lös lässt, also innerhalb 150ms, dann ja.

    Wenn ja, könnte ich ja jedem Knopf sagen: Wenn er kurz gedrückt wird: Programm - geh an - wenn lang gedrückt wird, geh aus.

    Jein. Für die Dauer der bouncetime wird jegliche Pegeländerung ignoriert. Das was du jetzt aber möchtest wäre etwas anderes, aber auch dafür gibt es Lösungen ;)

    Wie schreibe ich denn in diesem Python-Skript, dass er ein Programm starten soll? Vielleicht mit

    Code
    [...]
    echo sudo services mpd start
    [...]


    und ersetze

    Code
    print "Rising edge detected on %s" % pin

    Nein, so wird das nichts. "echo" usw ist bash Code, das kannst du so nicht einfach in Python einfügen - wäre aber auch quatsch mit dem echo davor :fies:

    Sonst:
    Wie mache ich das, dass sich ein weiteres Script öffnet und ausführt? Das könnte ich dann ja immer entsprechend ändern!

    Auch das wäre eigentlich quatsch. Man kann alles direkt in dem einen Python Script regeln - dazu kommen wir gleich. Wollte nur nicht das dich der Beitrag erschlägt :D Wir gehen das Schritt für Schritt durch.


    Also, wir nehmen unser oben erstelltes Basis Script:

    Spoiler anzeigen

    [code=php]#!/usr/bin/python
    # -*- coding: utf-8 -*-
    import RPi.GPIO as GPIO
    import signal

    #------------------------------------------------------------------------

    shutdownPin = 5 # with GPIO.BOARD pin#5 is gpio3
    progswitchPin = 7 # with GPIO.BOARD pin#7 is gpio4

    # to use RaspberryPi gpio# (BCM) or pin# (BOARD)
    #GPIO.setmode(GPIO.BCM)
    GPIO.setmode(GPIO.BOARD)

    #------------------------------------------------------------------------

    GPIO.setup(shutdownPin, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) #GPIO -> GND
    GPIO.setup(progswitchPin, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) #GPIO -> GND

    def interrupt_event(pin):
    if GPIO.input(pin): # if pin == 1 or True
    print "Rising edge detected on %s" % pin
    else:
    print "Falling edge detected on %s" % pin

    try:
    GPIO.add_event_detect(shutdownPin, GPIO.BOTH, callback=interrupt_event, bouncetime=150)
    GPIO.add_event_detect(progswitchPin, GPIO.BOTH, callback=interrupt_event, bouncetime=150)
    #keep script running
    signal.pause()
    except KeyboardInterrupt:
    print "\nQuit\n"
    GPIO.cleanup()
    [/php]

    Nun erweitern wir erstmal dieses Script um die Möglichkeit etwas auszuführen, je nachdem welcher Taster gedrückt wurde.
    Zum einen stellen wir sicher das auch wirklich der erforderliche Taster gedrückt wurde, und zum anderen legen wir für diese Aktion eine eigene Funktion fest (das ist sauberer als alles in die interrupt_event zu klatschen).

    Desweiteren brauchen wir jetzt noch ein paar Module mehr die wir oben import'ieren müssten, zum einen wäre das von subprocess die call Funktion damit wir Shellbefehle ausführen können (shutdown), und zum anderen auch das time Module um alles relevante bezüglich Zeit ausgeben/verarbeiten zu können ;)

    [code=php]import time
    from subprocess import call[/php](der Übersicht halber ganz oben bei den anderen import's einfügen, aber spätestens dann wenn es benutzt wird.)

    Jetzt definieren wir erst mal eine Funktion die sich ums herunterfahren des PI's kümmert.
    Man muss generell Funktionen erst definieren bevor diese ausgeführt werden können. Also da diese Funktion erst in interrupt_event ausgeführt wird, muss diese neue da drüber platziert werden.

    [code=php]
    def shutdown():
    call('poweroff', shell=False)
    [/php]..hier steht jetzt zwar nicht so viel drin, aber wenn wenn man hier später mal was verändern möchte wie zB LEDs schalten oder weiteren Text ausgeben usw, brauch man nur diese Funktion ändern..

    Dann verändern wir die interrupt_event Funktion wie folgt:
    [code=php]
    def interrupt_event(pin):
    zeit = time.strftime("%d.%m.%Y %H:%M:%S")
    if GPIO.input(shutdownPin) == GPIO.HIGH:
    print "[{}] Shutdown Button {} pressed" . format(zeit, pin)
    shutdown()
    [/php]

    Damit wäre schon mal das herunterfahren des PI's gewährleistet - Voraussetzung ist aber natürlich dass das Script als root (mit sudo) ausgeführt wird, da nur dieser den Rechner neustarten/herunterfahren darf. Alle im Script befindlichen Befehle werden dann als root ausgeführt und somit spart man sich dann auch vor jeden Befehl noch mal extra sudo einfügen zu müssen.


    Jetzt kommen wir zu dem Teil mit dem Programm-Wechsel.

    Wir erinnern uns an die Funktion aus Beitrag#6 die wie folgt aussah:

    [code=php]def check_proc_running(procname):
    found = False
    for proc in psutil.process_iter():
    if proc.name() == procname:
    found = True
    break
    return found
    [/php]

    Das fügen wir wieder über die interrupt_event ein.

    Desweiteren wäre es gut eine weitere Funktion zum beenden des gewünschten Prozesses einzufügen - lieber eine Funktion mehr als alles irgendwie in eine zu quetschen.

    Zum beenden eines Prozesses gibt es (wie bei allem) mehrere Möglichkeiten. Da wir hier aber bereits das psutil eingefügt haben, können wir auch gleich dieses nutzen und können uns weitere import's sparen (um so mehr importiert wird, um so mehr Verzögerung gibts beim starten des Scripts und um so mehr Ram wird verbraucht).

    [code=php]
    def kill_proc(procname):
    done = False
    for proc in psutil.process_iter():
    process = psutil.Process(proc.pid)
    if process.name() == procname:
    try:
    process.terminate()
    process.wait(timeout=3)
    done = True
    except psutil.AccessDenied:
    print "Error: Access Denied to terminate %s" % procname
    except psutil.NoSuchProcess:
    print "Error: No such Process: %s" % procname
    except psutil.TimeoutExpired:
    print "Error: Terminating of %s took to long.." % procname
    #kill_proc(procname)
    break
    if done:
    print "%s terminated!" % procname
    [/php]

    An dieser Stelle sei noch mals erwähnt dass man das nicht unbedingt so machen muss... Wenn beide Programme ein init.d Script besitzen, also via 'service' ansprechbar, könnte man sich den psutil Teil auch sparen und zum stoppen den jeweiligen 'service' Befehl ausführen... Da ich das aber nicht 100% weiß, hab ich mich für diesen Weg entschieden.

    Da du anscheint zumindest ein Dienst via 'service' starten kannst, könn wir auch dafür eine Funktion definieren:

    [code=php]
    def start_service(name):
    command = ['/usr/sbin/service', name, 'start'];
    try:
    call(command, shell=False)
    print "%s started!" % name
    except Exception, error:
    print "Error: %s" % error
    [/php]

    Dann erweitern wird die interrupt_event um den 2. Taster - darüber soll dann ja das eine Programm beendet und das andere gestartet werden...

    [code=php]
    def interrupt_event(pin):
    zeit = time.strftime("%d.%m.%Y %H:%M:%S")
    if GPIO.input(shutdownPin) == GPIO.HIGH:
    print "[{}] Shutdown Button {} pressed" . format(zeit, pin)
    shutdown()
    if GPIO.input(progswitchPin) == GPIO.HIGH:
    print "[{}] Program Switch Button {} pressed" . format(zeit, pin)
    if check_proc_running('mpd'):
    kill_proc('mpd')
    start_service('uv4l')
    elif check_proc_running('uv4l'):
    kill_proc('uv4l')
    start_service('mpd')
    else:
    print "None of the two Programs run!"
    [/php]

    Durch die Auslagerung einzelner Funktionen ist die interrupt_event schön übersichtlich und leicht zu lesen - so soll es sein ;)

    ...Soweit sollte es das eigentlich gewesen sein - sofern ich keine Fehler gemacht habe :daumendreh2:

    Das komplette Script sollte also dann wie folgt aussehen:

    "switch_prog.py"

    [code=php]#!/usr/bin/python
    # -*- coding: utf-8 -*-
    #
    # prog switch v0.1 - by meigrafd
    #
    import RPi.GPIO as GPIO
    import signal, time, psutil
    from subprocess import call

    #------------------------------------------------------------------------

    shutdownPin = 5 # with GPIO.BOARD pin#5 is gpio3
    progswitchPin = 7 # with GPIO.BOARD pin#7 is gpio4

    # to use RaspberryPi gpio# (BCM) or pin# (BOARD)
    #GPIO.setmode(GPIO.BCM)
    GPIO.setmode(GPIO.BOARD)

    #------------------------------------------------------------------------

    GPIO.setup(shutdownPin, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) #GPIO -> GND
    GPIO.setup(progswitchPin, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) #GPIO -> GND

    def check_proc_running(procname):
    found = False
    for proc in psutil.process_iter():
    if proc.name() == procname:
    found = True
    break
    return found

    def kill_proc(procname):
    done = False
    for proc in psutil.process_iter():
    process = psutil.Process(proc.pid)
    if process.name() == procname:
    try:
    process.terminate()
    process.wait(timeout=3)
    done = True
    except psutil.AccessDenied:
    print "Error: Access Denied to terminate %s" % procname
    except psutil.NoSuchProcess:
    print "Error: No such Process: %s" % procname
    except psutil.TimeoutExpired:
    print "Error: Terminating of %s took to long.." % procname
    #kill_proc(procname)
    break
    if done:
    print "%s terminated!" % procname

    def start_service(name):
    command = ['/usr/sbin/service', name, 'start'];
    try:
    call(command, shell=False)
    print "%s started!" % name
    except Exception, error:
    print "Error: %s" % error

    def shutdown():
    call('poweroff', shell=False)

    def interrupt_event(pin):
    zeit = time.strftime("%d.%m.%Y %H:%M:%S")
    if GPIO.input(shutdownPin) == GPIO.HIGH:
    print "[{}] Shutdown Button {} pressed" . format(zeit, pin)
    shutdown()
    if GPIO.input(progswitchPin) == GPIO.HIGH:
    print "[{}] Program Switch Button {} pressed" . format(zeit, pin)
    if check_proc_running('mpd'):
    kill_proc('mpd')
    start_service('uv4l')
    elif check_proc_running('uv4l'):
    kill_proc('uv4l')
    start_service('mpd')
    else:
    print "None of the two Programs run!"

    try:
    GPIO.add_event_detect(shutdownPin, GPIO.BOTH, callback=interrupt_event, bouncetime=150)
    GPIO.add_event_detect(progswitchPin, GPIO.BOTH, callback=interrupt_event, bouncetime=150)
    #keep script running
    signal.pause()
    except KeyboardInterrupt:
    print "\nQuit\n"
    GPIO.cleanup()
    [/php]

    Du müsstest dann eben nur noch die jeweiligen Programm-Namen sowie start Befehle in der interrupt_event anpassen - da weiß ich zZt nicht wie das exakt aussehen müsste.


    Wie man das ganze mit nur einem einzigen Taster realisieren kann, erklär ich im nächsten Schritt, nachdem sichergestellt ist das du das hier soweit verstanden und keine Fragen mehr hast :angel:

  • Moin!
    Danke für die ausfürliche Hilfe.
    Ich habe das schon mehr oder weniger gelöst. Ich muss mich da aber noch mal mit beschäftigen. Deins ist mit Sicherheit die bessere Lösung ;) aber ich werde meine hier bei Gelegenheit auch noch mal zeigen. Hatte da auch irgendwie einen Fehler was die Pin-Bezeichnungen angeht und die "Weiterleitung" des Pinwertes. Das mit der Vorstellung kann aber noch etwas dauern, weiß nicht wie ich Zeit habe.

    Vielen, vielen Dank an alle Helfer!!!
    Und viele Grüße von
    LuxOculus

  • Mega! Danke an meigrafd :)

    Kleine Anmerkung zu der Callback-Funktion: Die braucht nämlich immer ein Argument, an das immer der Pin übermittelt mit, auf dem der Interrupt kam. Wenn man das Argument weglässt, gibt's einen Fehler.

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!