Python Skript reagiert nach einigen Minuten / Nicht-Verwenden nicht mehr

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
MickelF
User
Beiträge: 2
Registriert: Dienstag 3. März 2020, 12:48

Hallo zusammen,
ich hab bei GitHub ein Projekt gefunden, welches einen One-Button-Audioplayer darstellt.

https://github.com/exitnode/theonebuttonaudiobookplayer

Es funktioniert alles nachdem ich den Pi gestartet habe und den Knopf zum Abspielen oder Pausieren der Audio Datei in kurzen Abständen betätige.
Betätige ich aber den Kopf länger nicht, reagiert der Pi nicht mehr auf die Knopfbetätigung für das unten dargestellte Skript.

Ich hab schon versucht das Skript einfach immer wieder automatisiert in festen Zeitabständen neu ausführen zu lassen, dass sorgt aber für neue Probleme.
Der eigentliche Fehler im Skript oder die Ursache, dass es nicht mehr reagiert ist ja immer noch da.

Leider bin ich mit meinem Wissen (das ist minimal und schlecht) am Ende.

Meine Hoffnung ist, dass ich hier jemanden finde der mir helfen kann und vielleicht das Problem kennt.


Vielen Dank und Grüße
Michael

Code: Alles auswählen

#!/usr/bin/env python

#  Copyright (C) 2012 Michael Clemens

#

#  This program is free software: you can redistribute it and/or modify

#  it under the terms of the GNU General Public License as published by

#  the Free Software Foundation, either version 3 of the License, or

#  (at your option) any later version.

#

#  This program is distributed in the hope that it will be useful,

#  but WITHOUT ANY WARRANTY; without even the implied warranty of

#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

#  GNU General Public License for more details.

#

#  You should have received a copy of the GNU General Public License

#  along with this program.  If not, see <http://www.gnu.org/licenses/>.



import RPi.GPIO as GPIO

import os

import pyudev



from mpd import (MPDClient, CommandError)

from socket import error as SocketError

from time import sleep



# Configure MPD connection settings

HOST = 'localhost'

PORT = '6600'

CON_ID = {'host':HOST, 'port':PORT}



# Configure IO ports

BUTTON = 17

LED = 24

GPIO.setmode(GPIO.BCM)

GPIO.setup(BUTTON, GPIO.IN)

GPIO.setup(LED, GPIO.OUT)



## Some functions

def mpdConnect(client, con_id):

        """

        Simple wrapper to connect MPD.

        """

        try:

                client.connect(**con_id)

        except SocketError:

                return False

        return True



def loadMusic(client, con_id, device):

        os.system("mount "+device+" /music/usb")

        os.system("/etc/init.d/mpd stop")

        os.system("rm /music/mp3/*")

        os.system("cp /music/usb/* /music/mp3/")

        os.system("umount /music/usb")

        os.system("rm /music/mpd/tag_cache")

        os.system("/etc/init.d/mpd start")

        os.system("mpc clear")

        os.system("mpc ls | mpc add")

        os.system("/etc/init.d/mpd restart")



def flashLED(speed, time):

        for x in range(0, time):

                GPIO.output(LED, GPIO.LOW)

                sleep(speed)

                GPIO.output(LED, GPIO.HIGH)

                sleep(speed)



def updateLED(client):

        # adjust LED to actual state

        if client.status()["state"] == "play":

                GPIO.output(LED, GPIO.LOW)

        else:

                GPIO.output(LED, GPIO.HIGH)



def checkForUSBDevice(name):

        res = ""

        context = pyudev.Context()

        for device in context.list_devices(subsystem='block', DEVTYPE='partition'):

                if device.get('ID_FS_LABEL') == name:

                        res = device.device_node

        return res



def main():

        ## MPD object instance

        client = MPDClient()

        mpdConnect(client, CON_ID)



        status = client.status()

        print status



        timebuttonisstillpressed = 0



        flashLED(0.1, 5)

        updateLED(client)



        while True:

                device = checkForUSBDevice("1GB") # 1GB is the name of my thumb drive

                if device != "":

                        # USB thumb drive has been inserted, new music will be copied

                        flashLED(0.1, 5)

                        client.disconnect()

                        loadMusic(client, CON_ID, device)

                        mpdConnect(client, CON_ID)

                        print client.status()

                        flashLED(0.1, 5)

                        # wait until thumb drive is umplugged again

                        while checkForUSBDevice("1GB") == device:

                                sleep(1.0)

                        flashLED(0.1, 5)

                if GPIO.input(BUTTON) == True:

                        if timebuttonisstillpressed == 0:

                                # button has been pressed, pause or unpause now

                                if client.status()["state"] == "stop":

                                        client.play()

                                else:

                                        client.pause()

                                updateLED(client)

                        elif timebuttonisstillpressed > 4:

                                # go back one track if button is pressed > 4 secs

                                client.previous()

                                flashLED(0.1, 5)

                                timebuttonisstillpressed = 0

                        timebuttonisstillpressed = timebuttonisstillpressed + 0.1

                else:

                        timebuttonisstillpressed = 0



                sleep(0.1)



# Script starts here

if __name__ == "__main__":

    main()
Benutzeravatar
__blackjack__
User
Beiträge: 13938
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@MickelF: Warum sind da so viele Leerzeilen drin? Die sind im Original nicht vorhanden.

Gibt es irgendwelche Fehlermeldungen?

Ansonsten müsstest Du ein paar Loggingausgaben einbauen damit Du siehst wo das vielleicht hängt.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
MickelF
User
Beiträge: 2
Registriert: Dienstag 3. März 2020, 12:48

So sieht der Code vom Skript auf meinem Pi aus:

Code: Alles auswählen

#!/usr/bin/env python
#  Copyright (C) 2012 Michael Clemens
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.

import RPi.GPIO as GPIO
import os
import pyudev

from mpd import (MPDClient, CommandError)
from socket import error as SocketError
from time import sleep

# Configure MPD connection settings
HOST = 'localhost'
PORT = '6600'
CON_ID = {'host':HOST, 'port':PORT}

# Configure IO ports
BUTTON = 17
LED = 24
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON, GPIO.IN)
GPIO.setup(LED, GPIO.OUT)

## Some functions
def mpdConnect(client, con_id):
        """
        Simple wrapper to connect MPD.
        """
        try:
                client.connect(**con_id)
        except SocketError:
                return False
        return True

def loadMusic(client, con_id, device):
        os.system("mount "+device+" /music/usb")
        os.system("/etc/init.d/mpd stop")
        os.system("rm /music/mp3/*")
        os.system("cp /music/usb/* /music/mp3/")
        os.system("umount /music/usb")
        os.system("rm /music/mpd/tag_cache")
        os.system("/etc/init.d/mpd start")
        os.system("mpc clear")
        os.system("mpc ls | mpc add")
        os.system("/etc/init.d/mpd restart")

def flashLED(speed, time):
        for x in range(0, time):
                GPIO.output(LED, GPIO.LOW)
                sleep(speed)
                GPIO.output(LED, GPIO.HIGH)
                sleep(speed)

def updateLED(client):
        # adjust LED to actual state
        if client.status()["state"] == "play":
                GPIO.output(LED, GPIO.LOW)
        else:
                GPIO.output(LED, GPIO.HIGH)

def checkForUSBDevice(name):
        res = ""
        context = pyudev.Context()
        for device in context.list_devices(subsystem='block', DEVTYPE='partition'):
                if device.get('ID_FS_LABEL') == name:
                        res = device.device_node
        return res

def main():
        ## MPD object instance
        client = MPDClient()
        mpdConnect(client, CON_ID)

        status = client.status()
        print status

        timebuttonisstillpressed = 0

        flashLED(0.1, 5)
        updateLED(client)

        while True:
                device = checkForUSBDevice("1GB") # 1GB is the name of my thumb drive
                if device != "":
                        # USB thumb drive has been inserted, new music will be copied
                        flashLED(0.1, 5)
                        client.disconnect()
                        loadMusic(client, CON_ID, device)
                        mpdConnect(client, CON_ID)
                        print client.status()
                        flashLED(0.1, 5)
                        # wait until thumb drive is umplugged again
                        while checkForUSBDevice("1GB") == device:
                                sleep(1.0)
                        flashLED(0.1, 5)
                if GPIO.input(BUTTON) == True:
                        if timebuttonisstillpressed == 0:
                                # button has been pressed, pause or unpause now
                                if client.status()["state"] == "stop":
                                        client.play()
                                else:
                                        client.pause()
                                updateLED(client)
                        elif timebuttonisstillpressed > 4:
                                # go back one track if button is pressed > 4 secs
                                client.previous()
                                flashLED(0.1, 5)
                                timebuttonisstillpressed = 0
                        timebuttonisstillpressed = timebuttonisstillpressed + 0.1
                else:
                        timebuttonisstillpressed = 0

                sleep(0.1)

# Script starts here
if __name__ == "__main__":
    main()

Ich hab das Skript manuell ausgeführt und wenn ich nach einer Minute den Knopf drücke erhalte ich folgendes und die Funktion des Skriptes ist nicht mehr gegeben:

Code: Alles auswählen

pi@onebuttonplayer:~ $ sudo python /home/pi/tobabp.py 
/home/pi/tobabp.py:35: RuntimeWarning: This channel is already in use, continuing anyway.  Use GPIO.setwarnings(False) to disable warnings.
  GPIO.setup(LED, GPIO.OUT)
{'songid': '1', 'playlistlength': '1', 'playlist': '2', 'repeat': '0', 'consume': '0', 'mixrampdb': '0.000000', 'random': '0', 'state': 'pause', 'elapsed': '1340.030', 'volume': '40', 'single': '0', 'time': '1340:1772', 'duration': '1771.990', 'song': '0', 'audio': '44100:24:2', 'bitrate': '160'}
Traceback (most recent call last):
  File "/home/pi/tobabp.py", line 130, in <module>
    main()
  File "/home/pi/tobabp.py", line 112, in main
    if client.status()["state"] == "stop":
  File "/usr/lib/python2.7/dist-packages/mpd/base.py", line 381, in mpd_command
    return wrapper(self, name, args, callback)
  File "/usr/lib/python2.7/dist-packages/mpd/base.py", line 473, in _execute
    return retval()
  File "/usr/lib/python2.7/dist-packages/mpd/base.py", line 368, in command_callback
    res = function(self, self._read_lines())
  File "/usr/lib/python2.7/dist-packages/mpd/base.py", line 317, in _parse_object
    objs = list(self._parse_objects(lines))
  File "/usr/lib/python2.7/dist-packages/mpd/base.py", line 224, in _parse_objects
    for key, value in self._parse_pairs(lines):
  File "/usr/lib/python2.7/dist-packages/mpd/base.py", line 219, in _parse_pairs
    for line in lines:
  File "/usr/lib/python2.7/dist-packages/mpd/base.py", line 538, in _read_lines
    line = self._read_line()
  File "/usr/lib/python2.7/dist-packages/mpd/base.py", line 523, in _read_line
    raise ConnectionError("Connection lost while reading line")
mpd.base.ConnectionError: Connection lost while reading line
pi@onebuttonplayer:~ $ 
Mit der Meldung ...
mpd.base.ConnectionError: Connection lost while reading line
... konnte ich herausfinden, dass der mpd-daemon die Verbindung zum Client trennt wenn dieser 1 Minute (by default) inaktiv ist.

In der Config-Datei des mpd (/etc/mpd.conf) habe ich folgende Zeile hinzugefügt (gab es zuvor nicht) ...

Code: Alles auswählen

connection_timeout	"2000000"
... dies gibt an nach wie viel Sekunden Inaktivität die Verbindung getrennt wird, bei mir gibt es die Zeile nicht.

Wenn ich die Zeile manuell einfüge hat dies leider keine Auswirkungen, auch nicht nach einem reboot.
Benutzeravatar
__blackjack__
User
Beiträge: 13938
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Dir bliebe natürlich immer noch die Möglichkeit beispielsweise alle x Sekunden ein "ping"-Kommando abzusetzen damit der Server nicht denkt da kommt nix mehr von Deinem Client.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
Benutzeravatar
__blackjack__
User
Beiträge: 13938
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Noch eine Anmerkung zur Zukunftssicherheit: Das Programm ist für Python 2.7 das seit Anfang des Jahres nicht mehr supported wird und in den nächsten Jahren deshalb sehr wahrscheinlich aus den Linuxdistributionen verschwinden wird. Das Programm selbst ist von 2012 und die `mpd`-Bibliothek die da benutzt wird, wurde 2010 das letzte mal aktualisiert. Die in Package Index und in der Dokumentation angegebene Homepage gibt es nicht mehr und die Bibliothek ist nur für Python 2. Es gibt einen Fork (python-mpd2) der weiterentwickelt wurde und auch nach Python 3 portiert ist.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
Antworten