Tastendruck an subprozess weiter geben

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo zusammen,

    in meinem Projekt spiele ich in einem Subprozess per mpg123 mp3-Dateien ab. Das habe ich über folgenden Code umgesetzt:

    Code
    mp3prozess = Popen(['mpg123', '-C', param[0], param[1], param[2]], stdin=PIPE, stdout=PIPE, stderr=PIPE)
    
    
    stdout, stderr = mp3prozess.communicate()

    Nun war die Idee von mir die Wiedergabe mittels Druck auf einen Taster zu pausieren und bei einem erneuten Tastendruck fortzusetzen. Das Abspielen der MP3s sowie das Abfangen des Tastendrucks klappt soweit prima. um im Terminal wie Wiedergabe von mpg123 zu pausieren und dann wieder fortzusetzen genügt jeweils ein Druck auf die Taste [s]. Um dies im Skript zu realisieren wollte ich den Buchstaben s per STDIN in den Subprozess schreiben und hatte das so formuliert:

    Code
    mp3prozess.stdin.write("s")

    Der Praxistest liefert mir aber bei einem beherzten Tastendruck die folgende Fehlermeldung:

    Code
    Traceback (most recent call last):
    File "./openNFCPlayer.py", line 42, in pause_an
       mp3prozess.stdin.write("s")
    TypeError: 'str' does not support the buffer interface

    Meine bisherige Recherche hat ergeben, dass das Problem wohl an der Art liegt, wie bzw. mit welchem Typ der Subprozess gestartet wird und man da nicht Daten eines beliebigen anderen Typs, hier also einen String, hineinstopfen kann. Die Ursache habe ich also schon mal gefunden, jedoch habe ich trotz langer Suche nicht herausfinden können, wie man den Code so schreiben muss, dass der Subprozess die Eingabe akzeptiert und im Idealfall auch umsetzt, sprich die Wiedergabe pausiert bzw. fortsetzt.

    Kann mir hier jemand auf die Sprünge helfen? Danke schon mal im Voraus.

    Gruß
    A-M

  • Hallo A-M,

    unabhängig davon, dass man sicherlich auch die Aufrufkonventionen recherchieren könnte, würde ich mal den Datentyp ändern.

    Wenn der Datentyp String nicht geht, dann mal char oder byte. Oder mal den ASCII-Code des Zeichens 's' übertragen. Dazu stellen die meisten Programmiersprachen die Funktion ord() bereit.


    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • FAQ => Nützliche Links / Linksammlung => Interrupt => #8

    Wozu "mp3prozess.communicate()" ?

    Du startest es vermutlich über Python3? Sieht man leider nicht weil du uns das Script verheimlichst...
    Bei python3 wird das anders/echter verarbeitet und die Fehlermeldung ist wörtlich zu nehmen. stdin ist in diesem Fall das buffer interface und kann nicht mit str umgehen. In Python3 ist string nicht der selbe type als in Python2. Mit python3 muss man damit "wie in echt" umgehen, sprich, serialize bzw encode... In den meisten Fällen reicht es aber den "mode" zu ändern

    Aber ich finde es immer wieder schade das "jemand" nicht die Python Module verwendet sondern dirty mit subprocess/os.system rum hantiert... Warum muss es denn unbedingt das Konsolen Programm mpg123 sein?

  • Danke schon mal für die Rückmeldungen.

    Naja, ich programmiere eben so, wie ich es aktuell verstanden habe und mir ist durchaus bewusst, dass ich hier noch einen weiten Weg vor mir habe, bis ich auch anspruchsvollen Kennern halbwegs gerecht werden kann. Momentan läuft das bei mir eher so, dass ich ein Problem habe und dann nach einer entsprechenden Lösung sehe, die zu verstehen versuche und so einbaue, dass das Gewünschte am Ende heraus kommt. Lösungsorientiertes Arbeiten halt. Als berufstätiger Vater von zwei Kindern hat man nach 8 Stunden Büro, 1,5 Stunden Pendelverkehr und rund vier Stunden mit den Kleinen nicht mehr viel Hirnmasse zwischen den Ohren und schon gleich gar nicht die Zeit sich anspruchsvolle Softwareentwicklung im Selbststudium beizubringen. Bei bestenfalls täglich 2 Stunden echter Freizeit ist es nicht immer einfach auch den eigenen Ansprüchen gerecht zu werden. Wenn ich dann auch noch mal mit einem der Projekte irgendwann fertig werden will, dann muss man auch mal nehmen was man kriegt und das Ganze dann eben später verbessern, wenn man mehr verstanden hat.

    Genug gejammert, hier mein Projekt ...

    Ich habe für meine Kids einen kindertauglichen Medienplayer gebaut. In einer Kiste steckt ein Pi B+, mit einen Wlan-Stöpsel und einem USB-Stick. Mit dem Pi ist noch ein RFID-Lesegerät angeschlossen sowie zwischen der Klingenbuchse und zwei Lautsprechern noch ein kleiner 2W- Verstärker geklemmt. Außen an der Kiste ist aktuell nur ein Wippschalter zum Ein- und Ausschalten sowie zwei Status-LED verbaut. Eine zur Anzeige für den Bootvorgang und eine zweite für den erfolgreichen Skript-Start. Das saubere Booten und Runterfahren habe ich über den HAT Powerblock von petrockblock.com realisiert. So gibt es nur einen Schalter mit dem auch ein dreijähriges Mädchen klar kommt. Nun habe ich mir einen Stapel NFC-Chip-Aufkleber besorgt, die hinten auf einen Pappendeckel geklebt und vorn einen Aufkleber mit einem Bild vom jeweiligen Hörbuch oder Lied drauf gemacht. Das Kind schnappt sich nun die Karte seiner Wahl, Schaltet den Kasten ein und wartet erst mal bis die eine LED aufhört zu blinken, stetig leuchtet (Bootvorgang abgeschlossen) und auch die zweite LED angegangen ist (Skript läuft), dann legt es die Karte mit dem NFC-Chip auf den KIstendeckel und das Hörbuch geht los. Dabei liest der Pi die NFC-ID vom Chip aus und vergleicht diese mit den IDs in einer Datei. Darin liegt ein Dictionary mit einer Zuordnung von Chip-IDs zu den Mediendateien. Wird eine gültige Kombi gefunden, spielt der Pi sie ab und das Kind ist glücklich. Wird die Karte mit dem Chip herunter genommen, bricht der Pi den Abspielvorgang ab und wartet nach einer kurzen Pause auf die nächste Karte. Soweit funktionierte die Sache schon mal tadellos, völlig störungsfrei und das nun schon seit einem halben Jahr.

    Das Problem war nun, das auch Kinderhörbücher mit unter länger als nur 5 Minuten dauern und wenn die lieben Kleinen zwischendurch mal aufs Klo müssen oder die Alten etwas wollen, konnte das Hörbuch nicht pausiert werden. Es ging nur laufen lassen oder abbrechen und neu starten. Daher die Idee der Pausentaste mit LED-Anzeige. Wenn dem Kind also danach ist, drückt es den Taster, die Pausen-LED geht an und der Pi pausiert die Wiedergabe. Wenn der Spross dann wieder zurück ist, wird erneut gedrückt, die LED geht aus und die Wiedergabe läuft nahtlos weiter.

    Auch wenn jetzt einige die Hände über dem Kopf zusammenschlagen werden, hier noch der komplette aktuelle Code, bei der zwar die Pausen-LED an- und ausgeht, wenn man die Taste drückt, jedoch das Weitergeben des Signals an den Subprozess mit einer Fehlermeldung quittiert wird. Wie gesagt, ich habe aktuell so weit und so gut programmiert wie ich es verstanden habe, also seit bitte gnädig mit mir. Mir ist durchaus sehr bewusst, dass dies nicht der Weißheit letzter Schluss ist ...

    Ich bin der Letzte der einen guten Rat ausschlägt und prinzipiell dankbar für jeden Tipp, der mich ein wenig mehr in die richtige Richtung schubbst, momentan suche ich erst einmal nach einer Lösung für mein Problem (Lösungsorientiert). Wenn ich dann das nächste Mal wieder Zeit übrig habe stecke ich die Nase wieder in die Bücher, Foren und Tutorials und verbessere mein Skript.

  • Erstmal:
    Super das du dir die Zeit genommen hast dein Vorhaben usw genauer zu beschreiben - sowas ist leider sehr selten! :thumbs1:

    Vorschlag:

    Zitat von "A-M" pid='294502' dateline='1502136663'


    Das Problem war nun, das auch Kinderhörbücher mit unter länger als nur 5 Minuten dauern und wenn die lieben Kleinen zwischendurch mal aufs Klo müssen oder die Alten etwas wollen, konnte das Hörbuch nicht pausiert werden. Es ging nur laufen lassen oder abbrechen und neu starten. Daher die Idee der Pausentaste mit LED-Anzeige. Wenn dem Kind also danach ist, drückt es den Taster, die Pausen-LED geht an und der Pi pausiert die Wiedergabe. Wenn der Spross dann wieder zurück ist, wird erneut gedrückt, die LED geht aus und die Wiedergabe läuft nahtlos weiter.

    Spontan hätte ich hier gesagt: Wäre es nicht einfacher, den NFC Chip vom Gehäuse runter schupsen führt zum Pausieren?
    Wird dann ein anderer NFC Chip drauf gelegt muss halt die aktuelle Wiedergabe gestoppt und eine neue gestartet werden - sollte aber nicht weiter schwierig sein :s

    Zitat von "A-M" pid='294502' dateline='1502136663'

    Auch wenn jetzt einige die Hände über dem Kopf zusammenschlagen werden, hier noch der komplette aktuelle Code, bei der zwar die Pausen-LED an- und ausgeht, wenn man die Taste drückt, jedoch das Weitergeben des Signals an den Subprozess mit einer Fehlermeldung quittiert wird. Wie gesagt, ich habe aktuell so weit und so gut programmiert wie ich es verstanden habe, also seit bitte gnädig mit mir. Mir ist durchaus sehr bewusst, dass dies nicht der Weißheit letzter Schluss ist ...

    Wie gesagt würde ich, auch wenn das etwas Aufwand wäre, statt Konsolen Befehl mpg123 zu verwenden lieber zu zum Beispiel MPD tendieren und dann das entsprechende Python Module nutzen (bzw mpd2).
    Möglicherweise ließe sich auch omxplayer oder vlc dazu verwenden, auch dafür gibt es native Python Module... Wie gesagt würde ich sowas immer vor "subprocess & Co" bevorzugen.


    Bei deinem Code fallen mir einige Dinge auf...
    - Du verwendest ziemlich viel "global", was aber vermieden werden sollte.
    - Du hast 2 Interrupt-Callback's: pause_an , schalterIn. Aber eigentlich bedarf es nur einer.
    -- Zu den ersten zwei Punkten empfehle ich stattdessen besagten Link in der Linksammlung mal durchzulesen.

    ...ich fände jetzt bestimmt nach weitere, aber in Anbetracht deiner geringen Freizeit spring ich über meinen Schatten :daumendreh2:

    Das sollte man nicht mehr verwenden:

    Code
    mp3prozess.stdin.write(...)

    Versuch es mal damit:

    Code
    mp3prozess.communicate(input=b's')

    das "b" ist Absicht und macht daraus Bytes. Wie gesagt, Python3 erfordert sowas..

    Ansonsten wie bereits erwähnt: encode

    Code
    mp3prozess.communicate(input='s'.encode())

    Es könnte auch sein das es erforderlich ist sozusagen die Eingabe auch via Enter (linebreak/newline) abzusehenden:

    Code
    mp3prozess.communicate(input=b's\n')
    
    
    mp3prozess.communicate(input='s\n'.encode())

    Und last but not least kann es helfen den Popen Befehl zu erweitern damit serialize bzw encode nicht erforderlich wird:

    Code
    mp3prozess = Popen(['mpg123', '-C', param[0], param[1], param[2]], stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True)

    Wenn das gesetzt wird kann "string" gesendet werden, ansonsten muss es "bytes" sein. Das wäre ByTheWay besagter "mode" ;)
    Das wäre vermutlich die einfachste Möglichkeit für dich, denn dann funktioniert auch:

    Code
    mp3prozess.communicate(input='s')
    Zitat


    If universal_newlines is True, the file objects stdin, stdout and stderr will be opened as text streams in universal newlines mode using the encoding returned by locale.getpreferredencoding(). For stdin, line ending characters '\n' in the input will be converted to the default line separator os.linesep. For stdout and stderr, all line endings in the output will be converted to '\n'. For more information see the documentation of the io.TextIOWrapper class when the newline argument to its constructor is None.

    Note The newlines attribute of the file objects Popen.stdin, Popen.stdout and Popen.stderr are not updated by the Popen.communicate() method.

    Quelle: https://docs.python.org/3.2/library/su…-used-arguments

  • Spitzenmäßig! So etwas habe ich gesucht.

    Ich werde erst mal eine der Quick-and-Dirty-Lösungen probieren und mir dann in der nächsten Zukunft die Module ansehen ... versprochen.

    Danke für die Codebeispiele und die nützlichen Tipps, sowie das Drumherum ... auch ich baue nur sehr ungern Sachen ein, die ich nicht verstanden habe.

    Gruß
    A-M

  • So endlich komme ich mal dazu die Beispiele anzusehen und etwas über den Tellerrand zu gucken ...

    Zitat

    Du hast 2 Interrupt-Callback's: pause_an , schalterIn. Aber eigentlich bedarf es nur einer.

    Eigentlich ist es ja auch nur ein Callback:

    Code
    GPIO.add_event_detect(schalterIn, GPIO.FALLING, bouncetime=500)
    GPIO.add_event_callback(schalterIn, pause_an)

    schalterIn ist ja nur eine Variable, welche die Pin-Nummer vom RasPi enthält der überwacht werden soll, in diesem Fall die 35. Bitte berichtigt mich wenn ich falsch liege, aber wenn ich den Syntax richtig verstanden habe wird hier damit Pin 35 auf Änderungen überwacht und wenn das der Fall ist die Funktion pause_an aufgerufen. Das müsste dann eigentlich passen.


    Zitat

    Du verwendest ziemlich viel "global", was aber vermieden werden sollte.


    Ja, ok, da muss ich wohl noch mal ran und mehr mit direkten Wertübergaben arbeiten, statt alles pauschal zu globalisieren. Ich geb ja zu, hier war ich tatsächlich ein klein wenig faul.

    Dann habe ich mich an das Ausprobieren der Lösungsvorschläge für den Subprozess gemacht. Alle drei liefern ein ähnliches Ergebnis. Beim Tastendruck wird nun zwar versucht das [s] in mp3prozess hineinzustopfen, jedoch weigert sich Python das durchzuziehen und meldet frech ...

    Code
    Traceback (most recent call last):
     File "./openNFCPlayer.py", line 42, in pause_an
       mp3prozess.communicate(input='s')
     File "/usr/lib/python3.4/subprocess.py", line 960, in communicate
       stdout, stderr = self._communicate(input, endtime, timeout)
     File "/usr/lib/python3.4/subprocess.py", line 1579, in _communicate
       self.stdin.flush()
    ValueError: I/O operation on closed file.

    Der mp3prozess dudelt aber noch fleissig das Hörbuch, wie kann dann die Sache schon geschlossen sein?

  • Nach einiger Recherche zu diesem Thema und vielen Versuchen habe ich es erst einmal aufgegeben mpg123 über Subprozesse zu steuern. Das einfache Abspielen funktioniert zwar, will man jedoch weitere steuernde Elemente nutzen, sind anscheinend tiefere Kenntnisse erforderlich, die sich mir im Moment jedenfalls noch nicht erschließen. Von daher habe ich mich erst einmal dazu entschlossen als nächstes mein Glück mit dem VLC zu versuchen, mal sehen, ob es damit besser klappt.

    Trotzdem danke für die Hilfe.

    Gruß
    A-M

Jetzt mitmachen!

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