Python gpiozero button.when_pressed - Parameter übergeben

dooz

Lt. Junior Grade
Registriert
Feb. 2007
Beiträge
386
Hallo zusammen,

schon mal sorry falls ich manche Begriffe eventuell nicht ganz korrekt benutze, bin nicht sonderlich erfahren in Programmierung.


Ich möchte ein recht simples Programm mit einem Raspberry Pi und Python basteln.
Es sind 3 Buttons am Pi angeschlossen, wenn ein Button gedrückt wird, soll ein Video abgespielt werden.

Ich habe dazu eine Methode, welche per Durck auf den Button aufgerufen wird um ein entsprechendes Video abzuspielen.
Dazu nutze ich "when_pressed" und möchte der Methode einen Parameter übergeben um ein bestimmtes Video aufzurufen. Jeder Button soll ein anderes Video abspielen können.


Hier mal auszugsweise der Code:
Python:
def get_video(vidnum):
    videopath = "/home/pi/Videos/"
 
    video = {}
    video[0] = "Video_1.mp4"
    video[1] = "Video_2.mp4"
    video[2] = "Video_3.mp4"
 
    return videopath + video[vidnum]

def video_start(vidnum):
    #player = OMXPlayer(Path(get_video(vidnum)))
    #player.load
    #sleep(player.duration()+ 0.3)
    print ('Video '+str(vidnum)+' wird abgespielt')
 

btn1.when_pressed = video_start(0)
btn2.when_pressed = video_start(1)
btn3.when_pressed = video_start(2)

Jetzt habe ich allerdings ein Problem mit dem "btn1.when_pressed = video_start(1)". Die Methode wird sofort nach Programmstart aufgerufen und es wird nicht auf die Eingabe über den Butting gewartet. Soweit ich das gesehen habe ist dieses Verhalten wohl auch normal.

Ich weiß allerdings nicht, wie ich sonst über "when_pressed" einen Parameter übergeben soll. Ich könnte es vermutlich über if-abfragen umsetzen, allerdings wollte ich den Code versuchen so schlank wie möglich zu bekommen und ich bin mir sicher, dass es eine ganz leichte und elegante Lösung für mein kleines Problemchen gibt.


---------------
edit
---------------

Video 0 wird abgespielt
/usr/lib/python3/dist-packages/gpiozero/mixins.py:250: CallbackSetToNone: The callback was set to None. This may have been unintentional e.g. btn.when_pressed = pressed() instead of btn.when_pressed = pressed
warnings.warn(CallbackSetToNone(callback_warning))

------
Das ist die Ausgabe die ich beim Programmstart erhalte. Es wird also der Parameter an die Methode übergeben, allerdings ausgeführt, ohne den Button zu betätigen.

Wenn ich keinen Übergabeparameter angebe, dann wird folgendes ausgegeben wenn ich den Button drücke:
"btn1.when_pressed = video_start"

>> Video <gpiozero.Button object on pin GPIO2, pull_up=True, is_active=True> wird abgespielt
 
Zuletzt bearbeitet:
Ohne mich großartig in Python auszukennen: Spendiere jedem Button eine eigene Funktion, die dann wiederum die parametrierte StartVideo-Funktion aufruft.

Code:
def video_start(vidnum):
    #player = OMXPlayer(Path(get_video(vidnum)))
    #player.load
    #sleep(player.duration()+ 0.3)
    print ('Video '+str(vidnum)+' wird abgespielt')

def button1_pressed():
   video_start(0)

def button2_pressed():
   video_start(1)

def button3_pressed():
   video_start(2)

btn1.when_pressed = button1_pressed()
btn2.when_pressed = button2_pressed()
btn3.when_pressed = button3_pressed()

Code bitte selbst auf Korrektheit überprüfen, ich bin absolut nicht firm in python. Hintergrund der obigen Variante ist die, dass Event-Funktionen in der Regel fest definiert sind. Bei C# wird beispielsweise immer ein object sender und ein event-spezifisches Parameterobjekt übergeben. Da kann man nicht nach Geschmack an den Parametern rumschrauben, sondern muss diese dann in einer separaten Funktion auslagern. Jeder Button bekommt bei C# auch eine eigene Event-Funktion, wobei man durchaus auch mehreren Buttons dieselbe Funktion verpassen kann. Bei python ist das evtl. ähnlich, ich lasse mich aber gerne eines besseren belehren, weil ich wie gesagt ein python-noob bin.
 
Soll btn1.when_pressed eine callback Funktion sein?

Mit
Code:
btn1.when_pressed = video_start(0)
weist du nämlich deiner Variable den Rückgabewert der Funktion zu, den es garnicht gibt und natürlich wird die Funktion dadurch auch erstmal aufgerufen.

Edit: Da wäre der Ansatz von @Raijin gut geeignet, bei der Zuweisung der Callback muss aber meines Wissens die Klammer weg, sonst wird auch hier die Funktion aufgerufen - also
Code:
btn1.when_pressed = button1_pressed
 
Zuletzt bearbeitet:
Erstmal vielen Dank für eure Antworten!

@Raijin
Alles klar, dein Gedanke dahinter reicht mir völlig, den korrekten code werde ich mir zusammensuchen müssen.
Werde es dann auch erstmal so umsetzen.
Ich hatte allerdings ein bisschen die Hoffnung mir diesen Weg ersparen zu können.

@Revan1710

Ok, ich muss wohl noch einiges lernen. Was meinst du mit Callback?

Mit der (0) bei
Code:
btn1.when_pressed = video_start(0)
wollte ich lediglich die Variable "0" an die Funktion übergeben, damit von der Funktion das richtige, zum Button zugehörige Video ausgewählt wird.

Revan1710 schrieb:
Mit
Code:
btn1.when_pressed = video_start(0)
weist du nämlich deiner Variable den Rückgabewert der Funktion zu, den es garnicht gibt und natürlich wird die Funktion dadurch auch erstmal aufgerufen.
Bei diesem Teil deiner Antwort stehe ich glaub etwas auf die Schlauch.
Also wird meine Variable "0" durch einen Rückgabewert der Funktion "video_start" ersetzt? Und um diesen Rückgabewert zu erhalten wird erstmal die Funktion ausgeführt, ohne das der Button gedrückt wird.
Aber warum wir dann die "0" erstmal korrekt an die Funktion übergeben?

Was ich dazu nur gelesen habe ist, dass
Code:
btn1.when_pressed = video_start(0)
nicht die Funktion "video_start" ausführt, sondern eine Referenz davon erstellt. Das habe ich allerdings auch noch nicht so richtig verstanden.


----- edit ------

@w0nd4bra
Die heißt gpiozero. Basiert auf RPi.GPIO und soll einem das Leben etwas leichter machen, deswegen will ich damit arbeiten :D
 
Was @Revan1710 damit sagen wollte ist, dass man bei einem Callback nur den Namen der Funktion angibt. Das ist kein Funktionsaufruf und somit findet auch keine (explizite) Parameterübergabe statt, sondern nur eine Information "Wenn du ne Funktion willst, nimm die, die blabla_func heißt". Die Signatur einer Callback-Funktion ist in der Regel fest vorgegeben, sei es mit spezifischen Parametern oder komplett ohne.
 
dooz schrieb:
Bei diesem Teil deiner Antwort stehe ich glaub etwas auf die Schlauch.
Also wird meine Variable "0" durch einen Rückgabewert der Funktion "video_start" ersetzt? Und um diesen Rückgabewert zu erhalten wird erstmal die Funktion ausgeführt, ohne das der Button gedrückt wird.
Aber warum wir dann die "0" erstmal korrekt an die Funktion übergeben?
Deine Variable btn1.when_pressed ersetzt du mit dem Rückgabewert des Funktionsaufrufs video_start(0) und da letztere eben keinen Rückgabeswert hat, ist dieser None

Hier mal ein einfaches Beispiel

Code:
def func(val):
    return val+1
  
f = func
a = func(1)
b = f(42)

print (f)
print (a)
print (b)

Wenn du das ausführst, siehst du dass f ein Zeiger auf deine Funktion func ist und a sowie b die entsprechenden Ergebnisse des Funktionsaufrufs.

Daher auch die Frage, was btn1.when_pressed ist - Wenn das ein Funktionszeiger sein soll, müsste man diese mit einer entsprechenden Funktion verknüpfen wie in der Antwort von @Raijin und dann auch entsprechend aufrufen:
Code:
btn1.when_pressed = button1_pressed
btn1.when_pressed()

Ist das allerding einfach ein Flag, das bspw. mit 0 oder 1 gesetzt ist, kommst du nicht um eine Abfrage herum:
Code:
if btn1.when_pressed == 1:
    video(0)
 

Ähnliche Themen

Zurück
Oben