Variable mit serieller zeichenfolge nicht vergleichbar

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Elektri
User
Beiträge: 6
Registriert: Samstag 26. April 2025, 15:22

Hallo Zusammen,

ein Teil eines größeren Scripts ist bei mir das Einlesen einer Zeichenflolge über die serielle Schnittstelle.
Dies soll dann in einer Variable gespeichert werden und mit einer If-Abfrage weiterverarbeitet werden.

Dazu habe ich mir jetzt einen Code-Schnipsel nur für die serielle-Abfrage erstellt.
Ich sende den Code über das Tool hterm als Ascii-Zeichen (alles andere macht glaube ich keinen Sinn, also Bin, Hex, oder DEC).

Der Code wird auch von meinem Python-Script empfangen und mit den Steuerzeichen oder ohne die Steuerzeichen dargestellt.
Jedoch gibt die If-Abfrage immer "Falsch" aus. Habe es schon mit anderen Codierungen in Hterm versucht und auch im Script. Aber nix führt zum Erfolg.

Könnt Ihr mir bitte helfen? Ich hoffe es ist nur ein kleiner Fehler.

Danke Euch.

Code: Alles auswählen

# coding: utf-8
import serial
ser = serial.Serial('COM5', 9600)
test=4
#ser.write(test)
data = ser.readline()
#dataneu = filter(str.isdecimal, data)
dataneu = data.decode('ascii', 'ignore') # 'ignore' ignoriert nicht-ASCII-Zeichen
print(dataneu)
print (data)
if dataneu == 'asd':
    print ('Rischdisch')
else:
    print ('Folsch')

Code: Alles auswählen

>>> %Run testseriell.py
asd

b'asd\r\n'
Folsch
>>> 
Benutzeravatar
snafu
User
Beiträge: 6844
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Naja, "asd\r\n" ist halt nicht "asd". Du müsstest daher mit dataneu.strip() vergleichen, damit er den Whitespace im String entfernt.
Elektri hat geschrieben: Samstag 26. April 2025, 15:28 Ich sende den Code über das Tool hterm als Ascii-Zeichen (alles andere macht glaube ich keinen Sinn, also Bin, Hex, oder DEC).
Kommt drauf an, was mit der Zeichenkette im weiteren Verlauf passiert. Wenn das so eine Art Kommando für den Verarbeitungsablauf ist, würde ich wohl in der Byte-Welt bleiben. Byte-Objekte kennen ebenfalls strip(), da könntest du dir die Konvertierung und das "Verschlucken" von Zeichen somit sparen.
Benutzeravatar
sparrow
User
Beiträge: 4522
Registriert: Freitag 17. April 2009, 10:28

Elektri hat geschrieben: Samstag 26. April 2025, 15:28Ich sende den Code über das Tool hterm als Ascii-Zeichen (alles andere macht glaube ich keinen Sinn, also Bin, Hex, oder DEC).
Ich denke, das ist inhaltlich falsch. Zumindest so, wie ich den Satz verstehe ist das nicht das, was du tust. Da kommen Bytes an. Keine ASCII-Zeichen (also 7-bit Zeichen).
Und daraus ergibt sich:

Code: Alles auswählen

>>> "a" == b"a"
False
Sirius3
User
Beiträge: 18245
Registriert: Sonntag 21. Oktober 2012, 17:20

@sparrow: Du übersiehst, dass Elektri die Bytes decodiert. Also ist das, was snafu schreibt, schon richtig, es liegt an den Zeileendezeichen.
Benutzeravatar
sparrow
User
Beiträge: 4522
Registriert: Freitag 17. April 2009, 10:28

@Sirius3: Ah, danke. Da war ich etwas zu fixiert auf die gezeigten Print-Ausgaben.
Benutzeravatar
__blackjack__
User
Beiträge: 13969
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Elektri: Weitere Anmerkungen zum Quelltext: Den Kodierungskommentar kann man sich sparen — UTF-8 ist das was Python 3 auch ohne den Kommentar erwartet.

`ser` ist kein sinnvoller Name. Das Objekt steht für eine serielle Verbindung, also macht beispielsweise `connection` Sinn.

Man sollte die Verbindung auch wieder schliessen. `Serial`-Objekte sind Kontextmanager, also kann man die ``with``-Anweisung in dem Zusammenhang verwenden.

Geschrieben und gelesen werden `bytes`-Objekte oder welche die „bytes-like“ sind, aber keine ganzen Zahlen. Wenn man den Bytewert 4 senden möchte, dann wäre das b"\x04" oder ``bytes([4])``, falls das ASCII-Zeichen „4“ gemeint war, dann b"4".

Ich würde hier keine Zeichen ignorieren beim dekodieren. Entweder verwirft man damit Informationen oder man ignoriert Fehler. Solange man nicht wirklich Text braucht, würde ich auch eher bei Byteketten bleiben.

Zwischen Funktionsname und öffnender Klammer für den Aufruf gehört kein Leerzeichen.

Code: Alles auswählen

#!/usr/bin/env python3
import serial


def main():
    with serial.Serial("COM5") as connection:
        data = connection.readline().rstrip(b"\r\n")

    print(data)
    print("Rischdisch" if data == b"asd" else "Folsch")


if __name__ == "__main__":
    main()
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Elektri
User
Beiträge: 6
Registriert: Samstag 26. April 2025, 15:22

Hallo Zusammen,

wow - das hätte ich nicht gedacht, das mir hier gleich so gut geholfen wird.
Vielen Dank Euch!

Mit dem letzten Code von Sparrow hat es auch sofort einwandfrei funktioniert.
Ich denke Ihr habt mit Eurer Vermutung recht, dass ich nicht wirklich das sende, was ich glaube zu senden.

Im Endeffekt geht es darum, dass ein Gerät einen längere Zeichenfolge mit Parametern und Codes (Text und Zahlen) über die serielle Schnittstelle ausgiebt.
Daraus muss ich mir einen ganz bestimmten Teil ausschneiden z. B. "DX436565" wo ich wiederum das "DX" entfernen muss.
Die Zahl die übrig bleibt, wird mittels pandas in einer csv-Datei gesucht und deren (Partnerwert in der nächsten Spalte) ausgegeben.

Das mit Datei, suchen und Ausgeben funktioniert alles schon. Es geht nur darum die Zeichenfolge so zu erkennen, dass ich Sie mit den Zahlen in der csv-Datei vergleichen kann.

Wenn ich das richtig verstehe, sollte ich das dann also nicht auf Ascii wandeln, sondern als Bytes lassen.
Ich muss halt noch hinkriegen, dass das "b" und die einfachen Anführungszeichen nicht mit in der Varaiable sind:

Code: Alles auswählen

>>> %Run testserielv2.py
b'234'
Folsch
Benutzeravatar
sparrow
User
Beiträge: 4522
Registriert: Freitag 17. April 2009, 10:28

Das steht nicht in der Variablen. Das ist die Python-Art dir zu sagen, dass es sich um eine Abfolge von Bytes handelt.
Sie sind so wenig Teil des Wertes wie die `'` bei a = 'text'

Edit: Die Dokumentation weiß wie immer mehr.
Benutzeravatar
__blackjack__
User
Beiträge: 13969
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Elektri: Wenn das am Ende mit Zeichenketten verglichen werden soll/muss, dann würde ich da doch auch eine Zeichenkette draus machen. Das ist weniger Aufwand als aus den ganzen Zeichenketten Bytes zu machen.

Pandas erscheint mir etwas mit Kanonen auf Spatzen geschossen, sofern man das wirklich nur für diese Zuordnung verwendet.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Sirius3
User
Beiträge: 18245
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn man Muster in Text erkennen will, kann man reguläre Ausdrücke benutzen:

Code: Alles auswählen

import re
...
data = b"DX436565\r\n"
match = re.fullmatch(br"DX(\d+)\s*", data)
if not match:
    print("Folsch")
else:
    dx = int(match.group(1))
    print("Rischdisch", dx)
Elektri
User
Beiträge: 6
Registriert: Samstag 26. April 2025, 15:22

sparrow hat geschrieben: Sonntag 27. April 2025, 10:45 Das steht nicht in der Variablen. Das ist die Python-Art dir zu sagen, dass es sich um eine Abfolge von Bytes handelt.
Sie sind so wenig Teil des Wertes wie die `'` bei a = 'text'
Ah Danke. Das verstehe ich natürlich.
__blackjack__ hat geschrieben: Sonntag 27. April 2025, 11:07 Pandas erscheint mir etwas mit Kanonen auf Spatzen geschossen, sofern man das wirklich nur für diese Zuordnung verwendet.
Naja, es werden wohl ziemlich viele Daten in der .csv-Datei gesammelt, die immer mehr werden.
Der Zugriff, das Suchen nach Werten und das Zurückgeben eines Wertes muss sehr schnell gehen, da das Endgerät auf die Antwort am seriellen Port wartet.
Sirius3 hat geschrieben: Sonntag 27. April 2025, 11:12 Wenn man Muster in Text erkennen will, kann man reguläre Ausdrücke benutzen:

Code: Alles auswählen

import re
...
data = b"DX436565\r\n"
match = re.fullmatch(br"DX(\d+)\s*", data)
if not match:
    print("Folsch")
else:
    dx = int(match.group(1))
    print("Rischdisch", dx)
Mit import re wollte ich schon mal was probieren. Leider ging das nicht, da ich mit Thonny am PC arbeite und hier das Modul "re" zum Nachinstallieren nicht gefunden habe. Es wurde mir nur irgendwas mit google gezeigt.
Upsi - das geht ja doch... Musste hier gar nix nachinstallieren. Aber ich verstehe den Code nicht ganz:
Sucht das Script in einer Variablen nach DX, egal was dahinter kommt?
Und die Zeile dx = int(match.group(1)) weist dann die Zeichenfolge nach DX der Variablen dx zu?
Richtig?
Sirius3
User
Beiträge: 18245
Registriert: Sonntag 21. Oktober 2012, 17:20

@Elektri: wenn man etwas nicht versteht, sollte man als erstes in die Dokumentation schauen.
Du schreibst davon, dass es zu einer Zahl eine weitere Zahl gesucht werden soll. Dafür gibt es in Python Wörterbücher. Etwas schnelleres gibt es nicht.
Benutzeravatar
snafu
User
Beiträge: 6844
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Elektri:
Der reguläre Ausdruck "DX(\d+)\s*" bedeutet, dass ein Muster gesucht wird, welches:
- mit DX beginnt
- gefolgt von einer beliebigen Anzahl von Digits (Ziffern)
- \d steht für ein Digit und das Plus heißt mindestens 1 Vorkommen
- die Klammerung ist die Gruppierung, deshalb kann man da mit group(1) drauf zugreifen
- weil das re-Modul auch bei Digits das Ergebnis als Text liefert, muss man int(match.group(1)) sagen
- und das \s ist Whitespace, der Stern macht es optional (0 bis "unendlich" viele Vorkommen)
- das \s* ist sozusagen Regex-Sprech für rstrip(), da es sich an der Stelle nur auf Whitespace NACH dem Text bezieht
Elektri
User
Beiträge: 6
Registriert: Samstag 26. April 2025, 15:22

Hallöchen,

da ich jetzt die endgültigen Daten habe, wollte ich Euch nochmal um Eure Hilfe bitten.
Die Daten kommen also über die serielle Schnittstelle als Hex-Code rein, den ich unten anfüge.
Ich habe ihn schon mal im Internet als ascii umwandeln lassen, dann enthält der Code einmal WP1 .............(Nummerfolge), RP1........(Nummernfolge) und WP3........(Nummernfolge).
Diese 3 Werte müssten von Python extrahiert und in Variablen als Text gelegt werden.
Leider scheitert es bei mir schon daran, dass scheinbar kein CR oder LF am Ende kommt und Python somit das Ende nicht erkennt.
Vom Umwandeln gar nicht zu reden. (Habe das zwar mit ein paar ergoogelten Befehlen versucht, was aber nicht funktioniert).

Könnt Ihr mir da bitte nochmal auf die Sprünge helfen?

Code: Alles auswählen

FE 00 7F 0E 57 53 53 20 30 78 30 31 3E FD FE 7F 00 09 57 3E 20 49 FD FE 00 7F 0F 52 55 43 2B 33 36 36 38 35 51 FD FE 7F 00 0F 52 55 43 2B 34 32 30 30 30 59 FD FE 00 7F 10 52 49 43 2B 30 30 30 30 30 30 73 FD FE 7F 00 10 52 49 43 2B 30 30 34 30 30 30 77 FD FE 00 7F 0A 52 43 44 20 75 FD FE 7F 00 10 52 43 44 2B 30 30 32 31 30 30 7D FD FE 00 7F 0A 52 53 41 20 60 FD FE 7F 00 10 52 53 41 2B 30 78 38 30 30 30 2B FD FE 00 7F 0A 52 53 53 20 72 FD FE 7F 00 10 52 53 53 2B 30 78 30 30 30 35 34 FD FE 00 7F 0A 52 55 41 20 66 FD FE 7F 00 0F 52 55 41 2B 33 36 37 36 37 5E FD FE 00 7F 0A 52 55 41 20 66 FD FE 7F 00 0F 52 55 41 2B 33 36 37 36 37 5E FD FE 00 7F 0A 52 53 41 20 60 FD FE 7F 00 10 52 53 41 2B 30 78 38 30 30 30 2B FD FE 00 7F 0A 52 53 53 20 72 FD FE 7F 00 10 52 53 53 2B 30 78 30 30 30 35 34 FD FE 00 7F 0F 52 55 43 2B 33 36 36 38 35 51 FD FE 7F 00 0F 52 55 43 2B 34 32 30 30 30 59 FD FE 00 7F 10 52 49 43 2B 30 30 30 30 30 30 73 FD FE 7F 00 10 52 49 43 2B 30 30 34 30 30 30 77 FD FE 00 7F 0A 52 53 41 20 60 FD FE 7F 00 10 52 53 41 2B 30 78 38 30 30 30 2B FD FE 00 7F 0A 52 53 53 20 72 FD FE 7F 00 10 52 53 53 2B 30 78 30 30 30 35 34 FD FE 00 7F 0A 52 55 41 20 66 FD FE 7F 00 0F 52 55 41 2B 33 36 37 36 37 5E FD FE 00 7F 0F 52 55 43 2B 33 36 37 33 32 5C FD FE 7F 00 0F 52 55 43 2B 34 32 30 30 30 59 FD FE 00 7F 10 52 49 43 2B 30 30 30 30 30 30 73 FD FE 7F 00 10 52 49 43 2B 30 30 34 30 30 30 77 FD FE 00 7F 0A 52 53 41 20 60 FD FE 7F 00 10 52 53 41 2B 30 78 38 30 30 30 2B FD FE 00 7F 0A 52 53 53 20 72 FD FE 7F 00 10 52 53 53 2B 30 78 30 30 30 35 34 FD FE 00 7F 0A 52 55 41 20 66 FD FE 7F 00 0F 52 55 41 2B 33 36 37 36 37 5E FD FE 00 7F 0A 52 53 53 20 72 FD FE 7F 00 10 52 53 53 2B 30 78 30 30 30 35 34 FD FE 00 7F 0A 52 53 53 20 72 FD FE 7F 00 10 52 53 53 2B 30 78 30 30 30 35 34 FD FE 00 7F 14 57 50 31 20 30 32 33 36 37 37 35 32 33 33 16 FD FE 7F 00 09 57 3E 20 49 FD FE 00 7F 0A 52 50 32 20 10 FD FE 7F 00 14 52 50 32 2B 33 38 34 37 36 35 31 33 34 36 10 FD FE 00 7F 14 57 50 33 20 33 32 37 30 30 33 36 32 33 36 10 FD
Benutzeravatar
sparrow
User
Beiträge: 4522
Registriert: Freitag 17. April 2009, 10:28

Varum versteifst du dich eigentlich so auf ASCII?
Da kommen Bytes mit, die deutlich nicht im 7bit-Bereich liegen. Woher weißt du, dass die nicht wichtig für das Protokoll sind?

Und dann sind wir auch schon bei der nächsten Frage:
Protokoll- bzw. Formatbeschreibung?
Wild da Daten heraus zu parsen macht nur Sinn, wenn man auch weiß wo sie auftreten.
Benutzeravatar
__blackjack__
User
Beiträge: 13969
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Elektri: Das wird irgendein Datenformat mit Rahmen, Längeninformation, und eventuell Prüfsumme sein, dass in der Dokumentation zu dem Gerät beschrieben sein wird. Wenn man sich das anschaut gibt es ein ziemlich deutliches Längenbyte, ein ziemlich deutliches Byte das die Nutzlast beendet und ein deutlich alternierendes Muster in jedem Rahmen.

Aber das sollte man sich nicht zusammen raten, sondern nachlesen.

Kommt das da wirklich als Hexdump rein? Du hast doch am Anfang offenbar noch Daten direkt Binär bekommen‽ Hexdumps seriell haben mal Sinn gemacht als die Rechner noch nicht alle 8 Bits pro Byte hatten und man mit Fernschreiber und Lochstreifen mit den Geräten kommuniziert hat. 😉
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Elektri
User
Beiträge: 6
Registriert: Samstag 26. April 2025, 15:22

Hallo,
also Dokumentation gibt es dazu sicher nicht. Ich mache das für einen Freund, der die Kommunikation zwischen einem Akku und Ladegerät nachbauen möchte.
Die Hex-Folge ist ein Mitschnitt der Kommunikation.

Ob es jetzt ascii sein muss weiß ich nicht, jedenfalls hat mir der online-umwandler von Hex nach Ascii die richtigen Werte ausgespuckt (WP...... RP...... WP).
Auf die kommt es an, das wurde auch schon manuell getestet von meinem Kumpel.

Aber um es zu automatisieren, müsste eben python die Werte auslesen.
Benutzeravatar
__blackjack__
User
Beiträge: 13969
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Elektri: Naja das komplizierteste dürfte sein herauszufinden wie die Prüfsumme gebildet wird. Es scheint wirklich eine *Summe* zu sein, denn wenn sich die Nutzlast von zwei Nachrichten nur an einer Stelle um den Wert 4 unterscheidet, dann ist auch die ganz gewöhnliche Summe über die Nutzlast um 4 in die gleiche Richtung verschoben. Jetzt ist die Frage ob es da einen Konstanten Anfangswert gibt, den man addieren muss, oder ob vielleicht das High-Byte der Summe mit dem Low-Byte verrechnet wird, und ob die Länge mit in die Summe eingeht.

Ist der Mitschnitt der Daten eigentlich von Anfang an oder erst mitten in der Kommunikation aufgesetzt? Und ist das nur eine Richtung oder ist das senden und empfangen gemischt?
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Sirius3
User
Beiträge: 18245
Registriert: Sonntag 21. Oktober 2012, 17:20

Da die Prüfsumme immer <128 ist, war meine Vermutung, dass es sich einfach um XOR handelt, was sich auch bestätigte.

Code: Alles auswählen

def read_frame(stream):
    start_of_frame, a, b, length = stream.read(4)
    data = stream.read(length - 4)
    checksum = 0
    for char in data[:-1]:
        checksum ^= char
    if start_frame != 0xfe or data[-1] != 0xfd or checksum != 0:
        raise ValueError("corrupt frame")
    return data[:-2].decode('ASCII')
Elektri
User
Beiträge: 6
Registriert: Samstag 26. April 2025, 15:22

__blackjack__ hat geschrieben: Montag 5. Mai 2025, 16:49 Ist der Mitschnitt der Daten eigentlich von Anfang an oder erst mitten in der Kommunikation aufgesetzt? Und ist das nur eine Richtung oder ist das senden und empfangen gemischt?
Das ist "denke ich" mitten in der Kommunikation und auch in beide Richtungen.

Ich treffe mich jetzt erst nochmal mit meinem Freund und klär das genau ab. Ihr habt mir schon so viel geholfen und bevor ich Euch weiter Arbeit mache, hohl ich mir Fakten.
Sirius3 hat geschrieben: Montag 5. Mai 2025, 21:41 Da die Prüfsumme immer <128 ist, war meine Vermutung, dass es sich einfach um XOR handelt, was sich auch bestätigte.
Wenn dat funktioniert, das wäre ja der Wahnsinn! Ich werde es in Kürze testen.
Antworten