RPi3 - Python 3 Uart Fehler nach zufälliger Zeit - UnicodeDecodeError: 'ascii'

  • Hallo Zusammen,

    ich habe nun seit ca. einen Monat n' Problem mit meiner Programmierung bezüglich Python...

    Das Forum und auch Google konnte mir leider nicht weiterhelfen..


    Zum Hintergrund:

    Ich habe ein Steca Tarom Laderegler, welcher mir Daten über eine offene Uart 3.3V Schnittstelle schickt.

    Diese möchte ich mit meinem Rpi3 auslesen.

    Die Daten werden werden jede Minute ASCII Codiert geschickt und sehen ca so aus:

    1;2019/08/05;19:32;12.7;13.4;#;99.0;#;1.2;2.1;#;2.1;1.2;0.8;0.8;33.8;0;F;1;1;0;89.6;43069.2;13.0;5504.1;0;85FD

    Am Ende der Datenausgabe wird immer CR + LF ausgegeben.

    Soweit so gut.

    Nun habe ich in Python folgendermaßen gelöst:

    Das Funktioniert auch soweit und ich kriege auch immer die Aussage, dass er die Daten empfangen hat.

    Nun kommen wir zu dem Problem:

    Nach einer zufälligen Zeit stützt der Thread zusammen und empfängt auch keine Daten mehr. Lustigerweise ist dies immer unterschiedlich. Mal nach 1 Minute, mal nach 1 Std und manchmal läuft dieser auch 5 Tage durch, bis ich wieder den kompletten rpi neustarten muss um wieder eine ausgabe zu erhalten.

    Das Python script läuft über ein Service, sodass dieser automatisch gestartet wird.

    Laut Log erhalte ich immer diese Fehlermeldung:


    Der Fehler mit der Loging info ist mir bekannt, allerdings wenn ich nach dem UART Fehler google, bekomme ich lösungen präsentiert, die meist nur für csv Datein zuständig sind. Wenn ich das .decode weglasse, bekomme ich sofort eine andere Fehlermeldung "TypeError: a bytes-like object is required, not 'str'"


    Vielleicht habt ihr eine Idee woran es liegt.

    Ich bin momentan echt am Verzweifeln und sitze an dieser Fehlermeldung schon > 1 Monat dran, aber nichts bringt mich zu dem gewünschten Ergebnis :wallbash:


    Für jede Hilfe, wäre ich euch dankbar! :danke_ATDE:

    Edited once, last by xMicha (August 5, 2019 at 8:01 PM).

  • RPi3 - Python 3 Uart Fehler nach zufälliger Zeit - UnicodeDecodeError: 'ascii'? Schau mal ob du hier fündig wirst!

  • Ich mein aber nicht den Massage error sondern mir geht es um den UnicodeDecodeError: 'ascii'

    Kann schon sein, dass da ab und zu mal Mist gelesen wird. Gibt dir halt den Bytestring vorm dekodieren mal aus und schaue nach, ob das nur Kauderwelsch ist. Die Info, ob es jedes mal "0xa7 in position 34" ist, hast du ja nicht gegeben.

  • Das ist unterschiedlich mal erhalte ich auch folgendes:

    UnicodeDecodeError: 'ascii' codec can't decode byte 0xa4 in position 36: ordinal not in range(128)

    oder

    UnicodeDecodeError: 'ascii' codec can't decode byte 0xbf in position 43: ordinal not in range(128)

    Der Letzte Datenbit (getrennt durch die Semikolons) entspricht laut Steca einer Checksumme

    Auszug aus der Doku:

    Quote

    Es wird ein CRC 16 gebildet. Name: „CRC-16-CCITT/openUART“ Width: 16 Direction: right shift Polynom: 0x8408 CCITT reversed,

    2Byte Länge, Highbyte, Lowbyte gebildet. Mit Semikolon und ohne CR + LF wird der CRC berechnet.

    Aber mal abgesehen davon sollte durch das Try innerhalb der While-Schleife doch solche Fehler übersprungen werden oder nicht?

    Sprich er hat was falsches eingelesen -> kann dieses nicht codieren -> überspringt das.

    Bei der nächsten Übertragung erhält er dann wieder den String.

    Aber in diesem Fall beendet er den kompletten Thread?!

  • Aber in diesem Fall beendet er den kompletten Thread?!

    Ja, weil eine Exception (AttributeError) geworfen wird, während du eine andere Exception (UnicodeDecodeError) abfängst. Also eine unabgefangene Exception, und das beendet dann den Hauptthread. Ist ja aber

    nur eine Sache nebenbei, die aber aktuell keine Prio für mich hat

    :dau2:

  • Ah ok verstehe.

    Bin ein wenig zu sehr von anderen Programmiersprachen verwöhnt ^^

    Ich hab nun mal die Exception angepasst:

    Code
                    except Exception as e:
                            if hasattr(e, 'message'):
                                    logging.info("---- UART: Unexpected error: {0}".format(e.message))
                            else:
                                    logging.info("---- UART: Unexpected error: {0}".format(e))

    Desweiteren habe ich auf stackoverflow noch was anderes gefunden:

    In Python 3 sollte mal lieber die .decode("ascii") leer lassen sprich -> .decode()


    Danke dir jedenfalls schon einmal für die Hilfe!

  • Als Notmassnahme: die ganze Response mit and 0x7F auf den Ascii-Bereich begrenzen.

    Als naechstes mal die Schnittstellenparameter genauer ansehen:

    * 7Bit oder 8Bit Chars?

    * Parity?

    * ich glaube man kann den Terminaldriver so einstellen dass er das High-Bit ignoriert

    Das Problem ist halt dabei, dass es mal Tagelang Funktioniert und dann plötzlich wieder nur mal 1-5 Minuten... Also immer unterschiedlich

    Schnittstellenparameter passen überein:

    Baud: 4800

    Datenbits: 8

    Parität Keine

    Stoppbits: 1

    Flusssteuerung: Keine

    Übertragungsinterfall : 60+- 1

    Sonstiges:

    - Daten werden in einer festen, nicht änderbaren Reihenfolge ausgegeben.

    - Es wird keine Bezeichnung der Einheit angegeben, wie z. B. V, A, °C, Ah.

    - Die Werte werden als ASCI-Zeichen übertragen.

    - Die Nachkommastelle wird mit Punkt getrennt. Es wird max. 1 Nachkommastelle angezeigt.

    - Als Trennung wird nach jedem Wert ein Semikolon { ; } ausgegeben.

    - Liegt für eine Information kein Wert vor, so wird {#} ausgegeben. Am Ende der Datenausgabe wird CR + LF ausgegeben.

  • Hallo,

    Quote

    Bin ein wenig zu sehr von anderen Programmiersprachen verwöhnt

    Warum nimmst du dann nicht eine andere Programmiersprache?

    Zu deinem Code:

    _thread ist die low-level Schnittstelle, die man _nicht_ benutzen möchte, die möchtest das `threading` Modul nutzen.

    Die massive Verwendung von `global`zeigt, dass du einen Fehler im Programmentwurf hast. Die Verwendung von `global` ist in 99,9% der Fälle falsch.

    Anstatt einer Liste mit 20+ Einträgen solltest du vielleicht über ein Dict oder NamedTuple nachdenken.

    Gruß, noisefloor

  • xMicha Ui toll, Python-Code. 😀

    Das Problem mit dem _thread-Modul und dem global wurde ja bereits angesprochen.

    solar sollte sowieso nicht ausserhalb sichtbar sein wenn die ganzen variablen mit den gleichen Daten ebenfalls sichtbar sind. Dann gibt es da ja keine einzelne Quelle der Wahrheit mehr weil Liste uns Einzelvariablen die gleichen Daten enthalten sollten das aber nicht zu jedem Zeitpunkt tatsächlich tun. So etwas ist bei nebenläufigen Programmen so gar keine gute Idee. Andere Threads können bei den ganzen Einzelvariablen auch nicht sicher sein, dass die alle zusammengehören und nicht welche noch alte Werte und andere schon neue Werte enthalten.

    Serial-Objekte sind Kontextmanager die kann und sollte man also mit der with-Anweisung verwenden.

    Die veraltete API von serial sollte man nicht mehr verwenden, also insbesondere alle Methoden und Attribute, die nicht der bei Python üblichen Namenskonvention entsprechen. Also beispielsweise reset_input_buffer() anstatt flushInput().

    solar.clear() ist an der Stelle sinnfrei. Die Liste wird geleert und dann durch eine neue Liste ersetzt. Den Schritt die alte Liste zu leeren kann man sich sparen.

    Wenn laut Beschreibung in den Daten eine zwei Byte lange Prüfsumme enthalten ist, dann ist ASCII natürlich falsch, denn ASCII kennt nur die Bytewerte 0 bis 127. Einfach nichts beim decode() anzugeben ist aber auch falsch, denn dann wird UTF-8 verwendet, was zwingend erwartet, dass die Bytes eben als solches dekodiert werden können. Das trifft aber nicht auf beliebige Bytefolgen zu, das heisst auch da wird die Prüfsumme Werte annehmen können die zu einem UnicodeDecodeError führen werden.

    Wenn man beliebige Bytedaten als Text dekodieren möchte geht das immer sicher beispielsweise mit ISO-8859-1, weil da jedem Byte von 0 bis 255 ein Zeichen zugeordnet ist. ASCII ist eine Untermenge und Bytewerte ausserhalb von ASCII werden dann halt Zeichen zugeordnet, die hier eh nicht interessieren.

    Sauberer wäre es natürlich die Bytes an den Semikolons zu trennen und dann erst die teile mit den Texten zu dekodieren. Und dann natürlich auch die Prüfsumme tatsächlich nachzurechnen und zu schauen ob die zum Rest der Nachricht passt. Denn nur dass man keinen Dekodierungsfehler bekommt, heisst ja noch nicht, dass die Daten valide sind.

    Bei den logging-Aufrufen sollte man Werte nicht in Zeichenketten formatieren, sondern die Zeichenkette mit Platzhaltern und die Werte getrennt übergeben.

    Die Funktion sollte das HTTPServer-Objekt als Argument bekommen und die Daten darauf setzen. Denn der HTTPHandler später kann auf den Server zugreifen und dort das Objekt lesen. Und zwar das Objekt als ganzes an einen lokalen Namen binden und nicht die Einzelwerte immer über den Weg über das Server-Objekt, denn sonst hat man wieder das Problem, dass die Werte nicht zu einem empfangenen Datensatz gehören müssen.

    „Info“ ist nicht wirklich die richtige Logging-Stufe für unerwartete Ausnahmen. Da würde man eher „Error“ nehmen und das über logging.exception() machen um noch zusätzliche Informationen zur Ausnahme im Protokoll zu haben.

    Der Code könnte dann so aussehen:

    solipsism = true if mind? and not world?
    — CoffeeScript documentation about the existential operator.

  • In fact I have the same hardware raspberry3 + steca tarom and I wanted to have help about it. I don't know which cable to use to connect them and I don't know if there is specific boot or OS configuration needed to have this working. The hardware is quite old and I'm sure it was done before so it would be better not to do it from 0.

Participate now!

Don’t have an account yet? Register yourself now and be a part of our community!