Anfänger: While Schleife neustarten

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo,
    ich habe eine While-Schleife für ein Display, das funktioniert auch einwandfrei.

    Er nimmt sich die Kommando Ausgabe von "mpc current" und gibt die auf ein Display aus, ist der Text länger als 16 Zeichen läuft er durch, dann wartet er 1s und aktualisiert dann.

    Nun möchte ich diese Schleife allerdings neustarten/unterbrechen bei einem Tastendruck.
    Der Taster ist schon programmiert und führt "mpc next" aus.

    Kann mir jmd einen Tipp geben, wie ich da rangehen soll?
    Meine Idee wäre, dass er neben "mpc next" dann auch das Script "Display.py" neu ausführt, aber allein von der Überlegung klingt das nach keiner sauberen Lösung :D

    Kann ich das mit "expect" machen?

  • Hi,

    am besten postest du mal deinen bereits bestehenden Code, dann wird ersichtlicher was du meinst. Was allerdings "expect" sein soll, ist mir schleierhaft. Meinst du "except"?

    Mfg

    “Don’t comment bad code - rewrite it.”

    Brian Kernighan

  • Gut die 150 Zeilen wollte ich euch ersparen :D

    Momentan sind die 2 Codes noch in unterschiedlichen Dateien.

    Die Initialisierung des Displays habe ich rausgelassen. Hier der Code für das Display

    Hier der Code für die Taster


    Bei GPIO 7 -> Low schaltet er z.B. einen Titel weiter.
    Nun geht es darum, dass er dann auch die While-Schleife des Displays unterbricht und neustartet, so dass der richtige Titel angezeigt wird.

  • Denkbar wären 2 verschachtelte Schleifen..

    Ich appelliere aber noch mals an dich das spezielle Python Module für mpd zu verwenden - konsolen befehle auszuführen bremst ungemein aus und die Handhabung is umständlicher: https://github.com/Mic92/python-mpd2

  • Stimmt danke.
    Kommt auf die Liste. Ich hab jetzt seit Dezember keine Zeit gehabt zum weiterprogrammieren und da gings dann unter :/
    Das könnte auch schon des Rätsels Lösung sein, da ich über das MPD-Script abfragen kann, wenn sich etwas ändert und er dann das Display aktualisiert. Ich schaue morgen mal in die Documentation.

    Einmal editiert, zuletzt von elkloso (8. März 2016 um 22:31)

  • Ich bin jetzt soweit, dass die Taster erkannt werden und er nach dem Tastendruck auch den Befehl ausführt und das Display aktualisiert.
    ABER: Er macht das erst, nachdem der Teil "scroll" durchgelaufen ist. Da dort aber der titel in einer while Schleife läuft, macht er es natürlich nie.

    Wenn ich mich nicht irre muss ich jetzt ein Interrupt einbauen, dass die While-Schleife bei Tastendruck unterbricht und dann den "scroll" Teil wieder startet oder?
    Meine Überlegung wäre als 2. Prozess das Script für die Taster laufen zu lassen. Ich kann per "if client.idle(['playlist']):" eine Veränderung im MPD abfragen und darüber könnte ich doch dann den "scroll" Teil unterbrechen oder?
    Also wenn es eine Änderung gibt, dann unterbreche "scroll" und führe es neu aus. Wäre das soweit richtig?

    Anmerkung: Ich weiß, dass ich den Titel immer noch per "os.popen" abfrage, ansonsten bekomme ich jedoch bei einem leeren Titel einen Abbruch. Das ist ein Problem, um das ich mich später noch kümmere.

  • Deine "scroll" Funktion blockiert das Script.

    Stell dir das einfach so vor dass das Script selbst ein Thread ist. Wird in dem Thread dann eine while ausgeführt gilt die komplette Aufmerksamkeit dieser Schleife und es kann nichts anderes parallel beachtet werden, was zur Folge hat das der Thread blockiert wird.

    Wenn du also willst das "scroll" permanent läuft und das Script auch noch was anderes machen soll, brauchst du einen weiteren Thread. Da du aber eigentlich nur auf drücken von Tastern reagieren willst, gibt es einen Vorteil: Interrupts. Würdest du mithilfe des RPi.GPIO Modules Interrupts nutzen, würde diese Interrupt-Steuerung automatisch in einem separaten Thread ausgeführt werden. Siehe dazu FAQ --> Nützliche Links / Linksammlung --> Interrupt
    Es würde dann also schon reichen wenn du vor dem ausführen von scroll() einen interrupt Callback definierst und für die Taster nutzt. Dann kann das Script die while von scroll() bearbeiten und wenn du eine Taste drückst führt die Callback andere Funktionen deines Scripts aus.

  • Zitat

    Deine "scroll" Funktion blockiert das Script.


    Das weiß ich. Vllt hab ich das oben etwas falsch geschrieben, aber deswegen will ich die Schleife ja abbrechen.

    Einen Interrupt würde mir zwar soviel bringen, dass der andere Thread ausgeführt wird, aber die while Schleife läuft dann weiter.
    Da sich aber mit dem Drücken des Tasters/Interrupt auch der Inhalt von "scroll" ändert müsste dieses Script ja abgebrochen und neugestartet werden und da liegt mein Problem.

    Im Prinzip müsste das Interrupt beinhalten:
    "if client.idle(['playlist']):"
    -> Scroll abbrechen
    -> Scroll wieder starten (damit er sich die neue Version von "title" nimmt, wenn z.B. der Song wechselt)

  • Nein da haste mich nicht verstanden ;) Also noch mal:

    Du hast einen Taster und erstellst dafür eine Interrupt Callback, in der du die Taster behandelst bzw je nach dem welcher Taster gedrückt wurde eine Aktion durchführst. Dann hast du eine scroll Funktion die den Titel von rechts nach Links durchscrollen soll - hierzu hast du eine Schleife in der erst der Titel ausgelesen und geprüft wird wie lang der Text ist sowie dann Zeichen für Zeichen zur Seite wandert.

    Was bei Dir aber auch immer noch das Problem ist: Du nutzt weiterhin den Konsolen Befehl um mit mpd zu interagieren - das bremst aus... Deshalb zeige ich dir jetzt mal Code mit dem auf "os" oder "subprocess" verzichtet werden kann ;)

    Beispiel: http://codepad.org/EgflTKzJ

    Spoiler anzeigen

    [code=php]
    #!/usr/bin/python
    from __future__ import print_function
    from functools import partial
    import RPi.GPIO as GPIO
    import time
    import mpd
    import sys

    #GPIO, Taster
    T_PREV = 7
    T_NEXT = 13
    T_PLAY = 15

    MPD_HOST = "localhost"
    MPD_PORT = 6600
    MPD_PASSWORD = False # optional password to connect to MPD

    sys.setdefaultencoding("utf-8")

    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(T_PREV, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    GPIO.setup(T_NEXT, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    GPIO.setup(T_PLAY, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

    dictionary={}
    #dictionary['song_title']=' '
    dictionary['Volume']=70
    dictionary['pause']=0

    def interrupt_event(client, pin):
    if GPIO.input(T_NEXT):
    client.next()
    print("next")
    elif GPIO.input(T_PREV):
    client.previous()
    print("prev")
    elif GPIO.input(T_PLAY):
    if dictionary['pause'] == 1:
    dictionary['pause']=0
    client.pause(0)
    print("resume")
    else:
    dictionary['pause']=1
    client.pause(1)
    print("pause")

    def connectMPD(client):
    try:
    client.timeout=10
    client.idletimeout=None
    client.connect(MPD_HOST, MPD_PORT)
    except mpd.ConnectionError, err:
    if "Already connected" in err:
    print(err)
    return True, None
    else:
    return False, err
    if MPD_PASSWORD:
    try:
    client.password=MPD_PASSWORD
    except mpd.CommandError, err:
    disconnectMPD(client)
    return False, err
    return True, None

    def disconnectMPD(client):
    try:
    client.close()
    client.disconnect()
    except mpd.ConnectionError:
    pass

    def get_songtitle(client):
    try:
    PlayCurrent = client.currentsong()
    except mpd.ConnectionError, e:
    print('Connection Error: ' + str(e))
    connected = connectMPD(client)
    PlayCurrent = client.currentsong()
    try: title_name = PlayCurrent['title']
    except: title_name = None
    #dictionary['song_title']=title_name
    return title_name

    def get_station(client):
    try:
    PlayCurrent = client.currentsong()
    except mpd.ConnectionError, e:
    print('Connection Error: ' + str(e))
    connected = connectMPD(client)
    PlayCurrent = client.currentsong()
    try: station_name = PlayCurrent['name']
    except: station_name = None
    if not station_name:
    try: station_name = PlayCurrent['album']
    except: station_name = None
    if not station_name:
    station_name = None
    return station_name


    def scroll(client):
    title = get_songtitle(client).decode('utf-8', errors='ignore')
    #sender = get_station(client).decode('utf-8', errors='ignore')
    if title and len(title) > 16:
    for i in range (0, len(title)):
    lcd(1, title[i:(i+15)])
    time.sleep(0.4)


    if __name__ == '__main__':
    try:
    client = mpd.MPDClient()
    connected = connectMPD(client)
    client.setvol(dictionary['Volume'])
    GPIO.add_event_detect(T_PREV, GPIO.RISING, callback=partial(interrupt_event, client), bouncetime=200)
    GPIO.add_event_detect(T_NEXT, GPIO.RISING, callback=partial(interrupt_event, client), bouncetime=200)
    GPIO.add_event_detect(T_PLAY, GPIO.RISING, callback=partial(interrupt_event, client), bouncetime=200)
    print("Ready!")
    while True:
    scroll(client)
    except (KeyboardInterrupt, SystemExit):
    print("\nQuit\n")
    GPIO.cleanup()
    [/php]kann sein das du GPIO.RISING auf GPIO.FALLING ändern musst, oder GPIO.PUD_DOWN auf GPIO.PUD_UP ...

    Was also gemacht wird ist grob: eine while Schleife ruft kontinuierlich scroll() auf, in der wiederum jedes mal der Titel ausgelesen wird und falls länger als 16 Zeichen dann wird der Titel gescrollt... Wobei ich jetzt natürlich den "lcd" Kram absichtlich weggelassen habe und du das natürlich noch einfügen müsstest.
    Drückt man auf einen Taster wird das unabhängig davon behandelt weil "interrupt_event" in einem eigenen Thread läuft. Eine kleine Besonderheit habe ich hier aber angewendet: partial. Damit modifiziere ich die an die Callback zu übergebenen Parameter und erweitere "pin" noch durch "client", weil ich explizites setzen von "global" mittlerweile nicht mehr mag ;) wobei ich da mit "dictionary" auch ein bisschen schummle aber das is grad egal :D
    Wenn gerade nichts abgespielt wird, wird auch nichts versucht zu scrollen da "get_station" in dem Fall "None" zurückgeben würde worauf wiederum "scroll" Rücksicht nimmt.

    Über diese Weise könntest du nach dem Aufruf von "scroll" in der while auch noch was anderes abhandeln, dann halt nacheinander.

    Eine andere Möglichkeit wäre btw für die scroll Funktion einen eigenen Thread bzw Process zu erstellen, aber ich glaub das wär zu viel des guten.

Jetzt mitmachen!

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