serial.read() - Problem (Nextion Display)

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
cosmoxer
User
Beiträge: 2
Registriert: Mittwoch 20. Mai 2020, 07:22

Mittwoch 20. Mai 2020, 09:07

Hallo Zusammen,
ich habe ein paar Problem mit dem Lesen von Eingaben von einem Nextion Display. Für diejenigen, die mit dem Nextion Display nichts anfangen können: Das ist ein Touch fähiges Display, dass über die Serielle Schnittstelle kommuniziert (https://nextion.tech/basic-series-introduction/).

Jetzt ein wenig zu meinem Projekt.
Ich habe für meinen Sohn eine Music-Box realisiert, bestehend aus einem Raspberry Pi 3, einen Nextion Display, Hifi-Berry + Endstufe, RFID Kartenleser. Das Grundsätzliche funktioniert schon sehr gut. Also Musik abspielen, anzeigen diverser Daten auf dem Display, starten von Musik in Abhängigkeit der RFID Karte, etc. Das Ganze natürlich in Python geschrieben.

Schreiben von Daten auf das Display funktioniert ohne Problem, aber mit dem Lesen von Eingaben über das Touch-Display bereiten mir noch ein paar Probleme. Ich habe einiges an Zeit investiert, um im Internet eine Lösung zu finden. Dabei habe ich mehrere Libraries für Python-Nextion gefunden, die aber nie ans laufen bekommen, zumal ich immer das Gefühl hatte, dass die noch einen "beta" Stand haben. Deshalb habe ich mir gedacht, dass die Kommunikation ja auch mit dem "normalen"
import serial
funktionieren muss.

Design mäßig mache ich jetzt folgendes in meinem Script (vereinfachter Ablauf):
- Setup und Initialisierung
- Zyklischer Bereich
-> RFID Kram
-> MPC Kram
-> Physical Button Check (Play, pause, next,...)
-> Display beschreiben (z.B. Album Name, Uhrzeit, Spielzeit, ...)
-> Daten vom Display lesen.

Jetzt bin ich mir zum einen nicht sicher, ob das Lesen der Daten vom Display so vom Design richtig ist. Zum anderen weiß ich nicht, wie man die Daten, die da über die Schnittstelle kommen ordentlich verarbeitet. Das sind ja keine zyklischen Daten, sondern die werden ja nur gesendet, wenn ich auf das Display tippe. In meiner Unwissenden Denke, stelle ich vor, dass es einen Puffer geben müsste, wo die Daten landen, wenn sie vom Display geschickt werden und wenn ich mit meinen Script "Zeit" habe, hole ich mir die Daten ab und werte sie aus. Gibt es in der Seriellen Kommunikation so einen Puffer? Macht man das so?

Kurze Zusammenfassung ..
1. Wäre es toll, wenn es jemanden gibt, der mir den grundsätzliche Ablauf eines Seriellen Lesen und Verarbeiten von nicht zyklischen Daten beschreiben könnte.
2. Kann mir jemand ein einfaches Python Bespiel zu dem Ablauf zum Kopieren und erweitern geben?

Ich sag schon mal vielen, vielen Dank und wünsche schon mal einen schönen Feiertag Morgen.

Viele Grüße
cosmoxer
__deets__
User
Beiträge: 8106
Registriert: Mittwoch 14. Oktober 2015, 14:29

Mittwoch 20. Mai 2020, 13:25

Man kann das so machen. Es wird gebuffert, und bei pyserial gibt es dazu auch extra eine Eigentschaft, mit der du abfragen kannst, wieviel Bytes gerade vorliegen: https://pyserial.readthedocs.io/en/late ... in_waiting

Achtung aber: serielle Daten sind KEINE Nachrichten! Sondern - wie ihr Name schon sagt - seriell! Du musst dich also darauf einstellen, dass die Daten nicht vollstaendig sind, weil du in dem Moment, wo du pruefst, noch nicht alle Bytes angekommen sind. Dann musst du ggf. buffern, und beim naechsten mal den Rest lesen, bevor du die Eingaben wirklich verarbeitest. Wie genau das aussieht haengt vom Nextion-Protokoll zusammen, das kenne ich nicht.
cosmoxer
User
Beiträge: 2
Registriert: Mittwoch 20. Mai 2020, 07:22

Mittwoch 20. Mai 2020, 15:45

Hallo deets,

vielen Dank für deine Antwort. Geht das in die richtige Richtung? Im Bereich "evaluate data" würde ich die Daten entsprechen der Nextion-Spezifikation analysieren und weiter verarbeiten.

Code: Alles auswählen

# IMPORTS
import serial

# CONSTANTS
SERIAL_EOF = '\xff\xff\xff'
SERIAL_BAUDRADE = 38400
SERIAL_TIMEOUT_S = 0.25
SERIAL_PORT = "/dev/ttyS0"

# init serial communication to display
serialDisplay = serial.Serial(port=SERIAL_PORT, baudrate=SERIAL_BAUDRADE, timeout=SERIAL_TIMEOUT_S)    

try: 
    while True:
        # do some music-box stuff
        #...
        
        # read serial buffer - number of bytes
        noOfBytes = serialDisplay.in_waiting()
        
        # read data from buffer
        displayData = serialDisplay.read(noOfBytes)
        
            # evaluate data
            # ...
        
        # Flush input buffer, discarding all its contents.
        serialDisplay.reset_input_buffer()
        
        time.sleep(1)
Benutzeravatar
__blackjack__
User
Beiträge: 6012
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Mittwoch 20. Mai 2020, 16:32

@cosmoxer: Kommentare wie ``# IMPORTS`` und ``# CONSTANTS`` sind nicht sinnvoll. Man sieht doch das dort Importe und Konstanten folgen. Faustregel: Kommentare sollten nicht beschreiben was der Code macht, das steht da ja bereits als Code, sondern warum er das *so* macht. Sofern das nicht offensichtlich ist.

Seriel-Objekte liefern `bytes` und keine `str`-Objekte. Beim `SERIAL_EOF` fehlt also ein kleines `b` um das als `bytes`-Literal zu kennzeichnen.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).

Sicher das der `reset_input_buffer()` keine Daten verwerfen könnte die noch gebraucht werden?

Die gelesenen Daten müsste man puffern. Ein `bytearray` bietet sich da an.
long long ago; /* in a galaxy far far away */
Antworten