Der Python-Faden für Python-Fragen

Der chaotische Hauptfaden

Moderatoren: Heaterman, Finger, Sven, TDI, Marsupilami72, duese

Antworten
Benutzeravatar
Hightech
Beiträge: 11496
Registriert: So 11. Aug 2013, 18:37

Der Python-Faden für Python-Fragen

Beitrag von Hightech »

Ich hab mal wieder einen Knoten in der Python und komme einfach nicht weiter:

Gegeben ist ein Analog-Modul, welches an einem RS485BUS hängt. Der Master pollt regelmäßig die Daten von dem Modul.

Der Datendump aud dem Bus sieht so aus:

Code: Alles auswählen

f 55 aa 50 60 00 02 00 a1 93 ff 55 aa 60 50 01 00 31 ff 55 aa 50 60 01 02 00 00 
33 ff 55 aa 60 50 02 00 32 ff 55 aa 50 60 02 02 00 67 57 ff 55 aa 60 50 03 00 33 ff 55 aa 50 60 03 02 00 a2 93 ff 55 aa 
60 50 04 00 34 ff 55 aa 50 60 04 02 00 a3 95 ff 55 aa 60 50 05 00 35 ff 55 aa 50 60 05 02 00 4b 7c ff 55 aa 60 50 06 00 
36 ff 55 aa 50 60 06 02 00 40 74 ff 55 aa 00 50 00 02 07 01 54 ff 55 aa 50 00 00 02 07 02 57 ff 55 aa 10 50 00 00 40 ff 
55 aa 50 10 00 01 07 46 ff 55 aa 60 50 00 00 30 ff 55 aa 50 60 00 02 00 a1 93 ff 55 aa 60 50 01 00 31 ff 55 aa 50 60 01 
02 00 00 33 ff 55 aa 60 50 02 00 32 ff 55 aa 50 60 02 02 00 67 57 ff 55 aa 60 50 03 00 33 ff 55 aa 50 60 03 02 00 a2 93 
ff 55 aa 60 50 04 00 34 ff 55 aa 50 60 04 02 00 a1 97 ff 55 aa 60 50 05 00 35 ff 55 aa 50 60 05 02 00 4a 7d ff 55 aa 60 
50 06 00 36 ff 55 aa 50 60 06 02 00 40 74 ff 55 aa 00 50 00 02 07 01 54 ff 55 aa 50 00 00 02 07 02 57 ff 55 aa 10 50 00 
00 40 ff 55 aa 50 10 00 01 07 46 ff 55 aa 60 50 00 00 30 ff 55 aa 50 60 00 02 00 a1 93 ff 55 aa 60 50 01 00 31 ff 55 aa 
50 60 01 02 00 00 33 ff 55 aa 60 50 02 00 32 ff 55 aa 50 60 02 02 00 67 57 ff 55 aa 60 50 03 00 33 ff 55 aa 50 60 03 02 
00 a2 93 ff 55 aa 60 50 04 00 34 ff 55 aa 50 60 04 02 00 a1 97 ff 55 aa 60 50 05 00 35 ff 55 aa 50 60 05 02 00 4a 7d ff 
55 aa 60 50 06 00 36 ff 55 aa 50 60 06 02 00 40 74 ff 55 aa 00 50 00 02 07 01 54 ff 55 aa 50 00 00 02 07 02 57 ff 55 aa 
10 50 00 00 40 ff 55 aa 50 10 00 01 07 46 ff 55 aa 60 50 00 00 30 ff 55 aa 50 60 00 02 00 a1 93 ff 55 aa 60 50 01 00 31 
ff 55 aa 50 60 01 02 00 00 33 ff 55 aa 60 50 02 00 32 ff 55 aa 50 60 02 02 00 67 57 ff 55 aa 60 50 03 00 33 ff 55 aa 50 
Die Daten die ich haben will sehen so aus:

Code: Alles auswählen

ff 55 aa 50 60 00 02 00 a1 93 
ff 55 aa 50 60 01 02 00 00 33 
ff 55 aa 50 60 02 02 00 66 56 
ff 55 aa 50 60 03 02 00 a2 93 
ff 55 aa 50 60 04 02 00 a2 94 
ff 55 aa 50 60 05 02 00 4b 7c 
Das Teilt sich auf in:

Code: Alles auswählen

ff 55 aa    Startsequenz
50 60       Quelladresse, Zieladresse
00            Kommando, bzw Kanaladresse 
02           Anzahl Datenbytes 
00 ab      Datenwort
93           Xor über Alles
 
Ich habe versucht mit

Code: Alles auswählen

ser_z = (serial.Serial('/dev/csTTY3' , 9600))

while True:
	for c in ser_z.read(1): // Ankommende einzelne Zeichen wird in c gespeichert
		string+=c            // Zeichen werden in string aneinander gesetzt
		if string.find('\xff\x55\xaa\x50\x60\'):    //Suche nach der Zeichenfolge, wenn Zeichenfolge erkannt 
				data=ser_z.read(4)		   // Einlesen der nächsten 4 Zeichen da müsste in data jetzt zb 00 02 00 00 33 oder 05 02 00 4b 7c drin stehen
				if data[0]==(’\x00’):		 //Wenn das 1 byte 00 ist, nehme den Wert der 4. Stelle und pack den in Ubat
					Ubat=data[3]
				if data[0]==('\x01’):
					Uger=data[3]	
					
					usw.
Das klappt aber nicht, die Zahlen würfeln irgendwie immer durcheinander
Die Baudrate stimmt und ich kann die Daten auch richtig umwandeln und lesen:
255 85 170 80 96 3 2 0 142
Wenn ich das mache:
data=ser_z.read(1)
print ( ord(data[0]))

Im Moment kommt da das raus:
0
255
255
255
255
85
0
Zuletzt geändert von Hightech am Fr 2. Okt 2020, 08:07, insgesamt 2-mal geändert.
Benutzeravatar
Fritzler
Beiträge: 12604
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der Python-Faden für Python-Fragen

Beitrag von Fritzler »

Nunja, einfach so mit Stringfind da rumzuwurschteln ist sehr unschön und man schießt sich damit schnell in den Fuß.

Es empfielt sich da nen Paketdekoder richtig zu bauen.
Startsequenz suchen und dann nach den Adressen und Kommandos zu verzweigen.
Irgendwann willste sicherlich eh noch was Anderes empfangen udnd ann wirds gebastel groß.
Benutzeravatar
Hightech
Beiträge: 11496
Registriert: So 11. Aug 2013, 18:37

Re: Der Python-Faden für Python-Fragen

Beitrag von Hightech »

Eigentlich nicht, und wenn dann würde ich den Suchstring am Anfang definieren.
Ich hab auch keine Ahnung wie ich einen Paketencoder bastel?
Benutzeravatar
Fritzler
Beiträge: 12604
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der Python-Faden für Python-Fragen

Beitrag von Fritzler »

Decoder ;)

Hier maln grober Aufbau:
1) Framestart + Ende Erkennung + CRC check
2) Tokenizing (https://de.wikipedia.org/wiki/Tokenisierung)
3) Aus den Tokens rausfischen was man braucht
4) Filtern wenn nicht alles gebraucht wird
Benutzeravatar
Hightech
Beiträge: 11496
Registriert: So 11. Aug 2013, 18:37

Re: Der Python-Faden für Python-Fragen

Beitrag von Hightech »

Das Problem an dem Käse ist, es gibt keine Leer, Zeilenende oder Stop Wörter, die Sequenzen sind verschieden lang, je nachdem wer in dem Bus was fragt.
Ich hänge wahrscheinlich schon an der Erkennung der Startsequenz.
Wenn ich die fix habe, also immer nach ff55aa5060 suche bekomme ich immer genau die Daten von dem einen Modul. So hatte ich gehofft, vermutlich hab ich einen Denkfehler was den "Hexadezimal" Suchstring angeht.
Benutzeravatar
Fritzler
Beiträge: 12604
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der Python-Faden für Python-Fragen

Beitrag von Fritzler »

Die Tokens sind in dem Fall die Bytefelder mit fester Länge wie Start, Adressen, Kommando.

Allerdings vermute ich, dass die Stingfind Funktion nicht sowas mag wie 0xff.
Also bei nicht validen Strings fliegt dir das um die Ohren.
Daher selbermachen.
Arne
Beiträge: 221
Registriert: So 11. Aug 2013, 19:12

Re: Der Python-Faden für Python-Fragen

Beitrag von Arne »

Man könnte die eingehenden Daten als Byte- bzw. Zahlen-Liste speichern. So kann man einfach die einzelnen Array-Elemente mit prüfen und muss sich keine Sorgen um unklares Verhalten der string.find-Funktion in Bezug auf die Hexwerte machen. Bei einem reinkommenden Byte einfach liste.append(byte) aufrufen. Dabei muss man aufpassen, dass die Liste nicht den RAM vollmüllt. Also gelegentlich zu sinnvollen Zeitpunkten (nicht mitten im Telegramm) leeren.

Erkennung des Programmstarts könnte z.B. so aussehen:

Code: Alles auswählen

start = [0xff, 0x55, 0xaa, 0x50, 0x60]

telegramm = [0x55, 0xaa, 0x50 , 0x10 , 0x00 , 0x01 , 0x07 , 0x46 , 0xff , 0x55 , 0xaa , 0x60 , 0x50 , 0x00 , 0x00 , 0x30 , 0xff , 0x55 , 0xaa , 0x50 , 0x60 , 0x00 , 0x02 , 0x00 , 0xa1 , 0x93 , 0xff , 0x55 , 0xaa , 0x60 , 0x50 , 0x01 , 0x00 , 0x31 , 0xff , 0xff , 0x55 , 0xaa , 0x50 , 0x60]

position = 0

for i in range(len(telegramm)-4):           # 5 Zeichen vorm Ende aufhören:
    if telegramm[i] == start[0] and \
        telegramm[i+1] == start[1] and \
        telegramm[i+2] == start[2] and \
        telegramm[i+3] == start[3] and \
        telegramm[i+4] == start[4]:
            print("Telegrammstart an Position " + str(i) + " erkannt.")
Edit: Das Telegramm ist vollständig wenn der Start erkannt wurde und i+9 < len(telegramm) ist. Dann lässt sich z.B. mit telegramm[i+7] und telegramm[i+8] gemütlich auf die Nutzdaten zugreifen.
Benutzeravatar
Hightech
Beiträge: 11496
Registriert: So 11. Aug 2013, 18:37

Re: Der Python-Faden für Python-Fragen

Beitrag von Hightech »

In der neuen Version geht es, die string.find() kommt anscheinend nicht mit dem Gehexe im String klar.

Mit if suchtext in string:
machwas

Code: Alles auswählen

      while True: #try:
                for c in ser_z.read(1): #// Ankommende einzelne Zeichen wird in c gespeichert
                        string+=c       #     // Zeichen werden in string aneinander gesetzt
                        if ('\xff\x55\xaa\x50\x60') in string:
                                string=""                       # //Suche nach der Zeichenfolge, wenn Zeichenfolge erkannt
                                data=ser_z.read(4)               #  // Einlesen der nchsten 4 Zeichen da msste in data jetzt zb 00 02 00 00 33 oder 05 02 00 4b 7c drin stehen
                                if data[0]==('\x00'):
                                        Ubat=ord(data[3])
                                if data[0]==('\x01'):
                                        Um=ord(data[3])
                                if data[0]==('\x02'):
                                        Uiso=ord(data[3])
                                if data[0]==('\x03'):
                                        Uger=ord(data[3])
                                if data[0]==('\x04'):
                                        UVer=ord(data[3])
                                if data[0]==('\x05'):
                                        Iger=ord(data[3])
                                if data[0]==('\x06'):
                                        ULad=ord(data[3])

#               bline=""
#               data=""
                        print (Ubat, Um, Uiso, Uger, UVer, Iger, ULad)
So kommen tatsächlich die Daten schön :

Code: Alles auswählen

(138, 0, 92, 140, 140, 0, 244)
(138, 0, 92, 140, 140, 0, 244)
(138, 0, 92, 140, 140, 0, 244)
(138, 0, 92, 140, 140, 0, 244)
(138, 0, 92, 140, 140, 0, 244)
(138, 0, 92, 140, 140, 0, 244)
(138, 0, 92, 140, 140, 0, 244)
(138, 0, 92, 140, 140, 0, 244)
(138, 0, 92, 140, 140, 0, 244)
(138, 0, 92, 140, 140, 0, 244)
duese
Beiträge: 6101
Registriert: So 11. Aug 2013, 17:56

Re: Der Python-Faden für Python-Fragen

Beitrag von duese »

Ich scheitere gerade an der Übergabe einer IP-Adresse als Kommandozeilenparameter.

Code: Alles auswählen

target_ip = '192.168.151.144'          
#target_ip = str(sys.argv[1])           

a = StupidArtnet(target_ip, universe, packet_size)
So wie oben klappt der Code und meine Artnet lampe leuchtet auf (da ist natürlich noch mehr Code im Programm).

Wenn ich die erste Zeile auskommentiere und die zweite reinnehme, geht es nicht mehr, ich krieg aber auch keine Fehlermeldung. Ohne str() hab ich es auch schon probiert. Die IP-Adresse habe ich als ersten Parameter angegeben beim Aufruf und ich kann die auch mit print in beiden Varianten ausgeben, sieht gut aus. type() liefert mir in beiden Varianten str zurück. Ich hab auf der Kommandezeile ich mit und ohne einfachen Anführungszeichen probiert. Kein Unterschied.

An welcher Stelle kann ich denn hier noch suchen. Meine bisherigen Googlesuchen waren nicht erfolgreich...
Benutzeravatar
Fritzler
Beiträge: 12604
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der Python-Faden für Python-Fragen

Beitrag von Fritzler »

Was steht denn in target_ip drinen wenns von der CLI kommt?
Mach doch maln simples print.
duese
Beiträge: 6101
Registriert: So 11. Aug 2013, 17:56

Re: Der Python-Faden für Python-Fragen

Beitrag von duese »

Ich kann keinen Unterschied erkennen. Das StupidArtnet-Modul druckt auch nochmal die IP-Adresse auf den Screen. Auch da steht (optisch) die korrekte IP-Adresse drin. Allein, es passiert nix auf der Lampenseite.
Benutzeravatar
Fritzler
Beiträge: 12604
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der Python-Faden für Python-Fragen

Beitrag von Fritzler »

Wenn dann StupidArtnet auch keine Exception wirft, dann wird das jetzt wohl ein Fall für Wireshark.
Da musste mal gucken ob da dann was unterschiedlich aussieht bei den Paketen.
sysconsol
Beiträge: 4059
Registriert: Fr 8. Jul 2016, 17:22

Re: Der Python-Faden für Python-Fragen

Beitrag von sysconsol »

Fritzler hat geschrieben: Sa 9. Jan 2021, 19:49 Was steht denn in target_ip drinen wenns von der CLI kommt?
Mach doch maln simples print.
Kann man davon ausgehen, dass print() immer das anzeigt, was da auch drinnensteht?
Benutzeravatar
Fritzler
Beiträge: 12604
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der Python-Faden für Python-Fragen

Beitrag von Fritzler »

Wie meinsten das jetz genau?
Es wandelt manchmal um*, aber zeigt das an was man ihm gibt.

* es ruft die str() Funktion eines Objekts auf, daher sind Dictionaries/Lists/Tuples/Sets sind printable, aber werden dann nach menschenlesbar konvertiert:
{'name': 'Alice', 'age': 42}
duese
Beiträge: 6101
Registriert: So 11. Aug 2013, 17:56

Re: Der Python-Faden für Python-Fragen

Beitrag von duese »

Ich hab gerade eine neue Form der Betriebsblindheit kennengelernt: Die Private-Ip-Adressen-Prefix-Bildheit.

Wenn man statt 192.168.151.144 191.168.151.144 tippt und das Gehirn beim lesen vorne sofort 192 draus macht... Grmphf. Dafür ist Wireshark jetzt auch installiert. (Ich mag Paketmanager, da geht das so einfach ohne herunterladen und so...)

Danke fürs mitdenken...
Benutzeravatar
Fritzler
Beiträge: 12604
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der Python-Faden für Python-Fragen

Beitrag von Fritzler »

:lol: Das konnt man jetz natürlich nich sehen :lol:

Aber du kannst dir ja trotzdem das Artnetpaket in Wireshark angucken.
Wenn ich mich recht erinnere erkennt Wireshark sogar direkt Artnet und zeigt kein langweiliges udp Paket an.
duese
Beiträge: 6101
Registriert: So 11. Aug 2013, 17:56

Re: Der Python-Faden für Python-Fragen

Beitrag von duese »

Tut er. Allerdings wollte ich auf Paketebene ja gar nicht runter...
Egal jetzt gehts, jetzt kann ich weiter meine Simple DMX-Über-Artnet-Ausgabe-für-die-Kommandzeile bauen...
Antworten