Datenemfpang

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
Didination
User
Beiträge: 16
Registriert: Montag 1. Februar 2021, 15:24

Hallo alle zusammen,

ich will mit meinem Raspberry die Daten einer Solaranlage auslesen und dartsellen lassen. Die Daten werden von einem Datalogger aufbereitet und auf abruf gesendet.
Das habe ich auch soweit hinbekommen, also ich bekomme die Werte zugesendet.
Mein Problem ist nun, dass mir die Daten in hex dargestellt werden. Ich habe schon im Internet rumgesucht, wie ich die in Gleitkommazahlen umwandeln kann, leider hat bisher nichts funktioniert.
Die Werte bekomme ich so angezeigt
\xb7\xbb\xbb\xb7\xbc\xbb\xb7\xbf\xb7\xbd\xbd\xbb\xbd\xb7\xbf\xb5k\xbd\xbdw\xaf\xbd\xbf\xbf\xbd\xbd\xb5{\xb7\xbd\xb7
Es irritiert mich aber auch ziemlich, dass sich da vieles wiederholt. Ich habe auch schon versucht, die einzelnd zu lesen (b7 hex = 183 binär) aber das hilft mir nicht sonderlich weiter.
Wäre super, wenn mir jemand auf die Sprünge helfen kann.
Gruß, Didination
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Didination: Was ist das denn? Ein Ausschnitt der Daten? Warum 31 Bytes? Hast Du eines vergessen? Wie viele Gleitkommawerte sollen das sein? Weisst Du welche Zahlen bei diesem Beispiel heraus kommen müssten?

Sieht irgend etwas hiervon ”richtig” aus? (auf e-Notation achten!)

Code: Alles auswählen

In [148]: data                                                                  
Out[148]: b'\xb7\xbb\xbb\xb7\xbc\xbb\xb7\xbf\xb7\xbd\xbd\xbb\xbd\xb7\xbf\xb5k\xbd\xbdw\xaf\xbd\xbf\xbf\xbd\xbd\xb5{\xb7\xbd\xb7'

In [149]: struct.unpack("<3d", data[:3*8])                                      
Out[149]: (-0.09270839200665547, -8.477405308588575e-50, -0.12398811982506223)

In [150]: struct.unpack(">3d", data[:3*8])                                      
Out[150]: (-3.1836235338265684e-40, -3.414116118467234e-40, 9.777312955409109e+210)

In [151]: struct.unpack("<7f", data[:7*4])                                      
Out[151]: 
(-2.237954868178349e-05,
 -1.4354166984558105,
 -0.005790438037365675,
 -1.4284083817983628e-06,
 7.696765305402825e+33,
 -1.4979761838912964,
 1.8873081618652183e+36)

In [152]: struct.unpack(">7f", data[:7*4])                                      
Out[152]: 
(-2.237954868178349e-05,
 -0.022914765402674675,
 -2.2618905859417282e-05,
 -0.08972112089395523,
 4.587634046699441e+26,
 -3.4515143521041125e-10,
 -0.09263130277395248)
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Didination
User
Beiträge: 16
Registriert: Montag 1. Februar 2021, 15:24

Hi, danke für die die Antwort.
Mit dem struct.unpack habe ich es auch schon probiert, aber bei mir kam da ein Fehler zurück.
Leider sieht nichts davon richtig aus. Da müsste bei meinem Beispiel ein Wert um die 110,x rauskommen.
Was ich mir auch schon gedacht habe ist, dass ich ein Fehler zurück bekomme. Habe dies auch im Handbuch des Dataloggers IDL101 nachgeschaut, dazu aber nichts gefunden.
Ja ich habe ein paar vergessen:
\xb7\xbd\xbd\xbd\xb7\xbf\xbf\xb7\xbf\xb7\xbf\xbd\xbd\xbf\xbd\xaf\xb7{\xb7\xbdw\xbf\xbd\xbb\xbf\xbd\xbd\xbd\xb5{\xbf\xbd\xb7
Das ist nun das komplette.
Gruß, Didination
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Das sollten dann eigentlich 4 Byte Floats sein. Was mit der Länge von jetzt 33 Bytes nicht so ganz hin kommt.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Didination
User
Beiträge: 16
Registriert: Montag 1. Februar 2021, 15:24

mein Programm sieht wie folgend aus:

Code: Alles auswählen

import serial
from time import *
from ast import literal_eval
import struct

connection = serial.Serial(
                port = "COM3",
                baudrate = 19200,
                parity = serial.PARITY_EVEN,
                stopbits = serial.STOPBITS_ONE,
                bytesize = serial.EIGHTBITS,
                #timeout = 1,
                )
print("Serial Port ist offen!")

def sendenDaten():
    daten1 = b'68 06 06 68 81 80 4C 0D 00 01 5B 16'
    daten2 = b'68 06 06 68 81 80 4C 0D 00 02 5C 16'
    daten3 = b'68 06 06 68 81 80 4C 0D 00 03 5D 16'
    daten4 = b'68 06 06 68 81 80 4C 0D 00 04 5E 16'
    daten5 = b'68 06 06 68 81 80 4C 0D 00 05 5F 16'
    daten6 = b'68 06 06 68 81 80 4C 0D 00 06 60 16'
    daten7 = b'68 06 06 68 81 80 4C 0D 00 07 61 16'
    daten8 = b'68 06 06 68 81 80 4C 0D 00 08 62 16'
    daten129 = b'68 06 06 68 81 80 4C 0D 00 81 DB 16'
    daten130 = b'68 06 06 68 81 80 4C 0D 00 82 DC 16'
    daten132 = b'68 06 06 68 81 80 4C 0D 00 84 DE 16'
    daten133 = b'68 06 06 68 81 80 4C 0D 00 85 DF 16'
    daten135 = b'68 06 06 68 81 80 4C 0D 00 87 E1 16'
    daten136 = b'68 06 06 68 81 80 4C 0D 00 88 E2 16'
    daten138 = b'68 06 06 68 81 80 4C 0D 00 8A E4 16'
    daten139 = b'68 06 06 68 81 80 4C 0D 00 8B E5 16'
    daten141 = b'68 06 06 68 81 80 4C 0D 00 8D E5 16'
    daten142 = b'68 06 06 68 81 80 4C 0D 00 8E E8 16'
    daten144 = b'68 06 06 68 81 80 4C 0D 00 90 EA 16'
    
    
    
    while True:
        print("Neu lesen: \n")
        #Kanal 1
        connection.write(daten1)
        print("Sende Daten: " + str(daten1))
        Kanal1 = connection.readline(35)
        print(Kanal1)
        #Kanal 2
        connection.write(daten2)
        print("Sende Daten: " + str(daten2))
        Kanal2 = connection.readline(35)
        print(Kanal2)
        #Kanal 3
        connection.write(daten3)
        print("Sende Daten: " + str(daten3))
        Kanal3 = connection.readline(35)
        print(Kanal3)
        #Kanal 4
        connection.write(daten4)
        print("Sende Daten: " + str(daten4))
        Kanal4 = connection.readline(35)
        print(Kanal4)
        #Kanal 5
        connection.write(daten5)
        print("Sende Daten: " + str(daten5))
        Kanal5 = connection.readline(35)
        print(Kanal5)
        #Kanal 6
        connection.write(daten6)
        print("Sende Daten: " + str(daten6))
        Kanal6 = connection.readline(35)
        print(Kanal6)
        #Kanal 7
        connection.write(daten7)
        print("Sende Daten: " + str(daten7))
        Kanal7 = connection.readline(35)
        print(Kanal7)
        #Kanal 8
        connection.write(daten8)
        print("Sende Daten: " + str(daten8))
        Kanal8 = connection.readline(35)
        print(Kanal8)
        #Kanal 129
        connection.write(daten129)
        print("Sende Daten: " + str(daten129))
        Kanal129 = connection.readline(35)
        print(Kanal129)
        #Kanal 130
        connection.write(daten130)
        print("Sende Daten: " + str(daten130))
        Kanal130 = connection.readline(35)
        print(Kanal130)
        #Kanal 132
        connection.write(daten132)
        print("Sende Daten: " + str(daten132))
        Kanal132 = connection.readline(35)
        print(Kanal132)
        #Kanal 133
        connection.write(daten133)
        print("Sende Daten: " + str(daten133))
        Kanal133 = connection.readline(35)
        print(Kanal133)
        #Kanal 135
        connection.write(daten135)
        print("Sende Daten: " + str(daten135))
        Kanal135 = connection.readline(35)
        print(Kanal135)
        #Kanal 136
        connection.write(daten136)
        print("Sende Daten: " + str(daten136))
        Kanal136 = connection.readline(35)
        print(Kanal136)
        #Kanal 148
        connection.write(daten138)
        print("Sende Daten: " + str(daten138))
        Kanal138 = connection.readline(35)
        print(Kanal138)
        #Kanal 139
        connection.write(daten139)
        print("Sende Daten: " + str(daten139))
        Kanal139 = connection.readline(35)
        print(Kanal139)
        #Kanal 141
        connection.write(daten141)
        print("Sende Daten: " + str(daten141))
        Kanal141 = connection.readline(35)
        print(Kanal141)
        #Kanal 142
        connection.write(daten142)
        print("Sende Daten: " + str(daten142))
        Kanal142 = connection.readline(35)
        print(Kanal142)
        #Kanal 144
        connection.write(daten144)
        print("Sende Daten: " + str(daten144))
        Kanal144 = connection.readline(35)
        print(Kanal144)
        sleep(15)

        

if __name__ == "__main__":
    sendenDaten()
    
Es wird noch was dazu kommen, um die Werte dann zu speichern, aber vorerst geht es darum, dass ich die richtig bekommen und auch lesen kann.
Kann es auch sein, dass ich die Befehle anders sehen muss? Also noch \68 sondern \x68?
Gruß, Didination
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Man benutzt keine *-Importe, sondern importiert die Namen, die man braucht (sleep) explizit. literal_eval wird importiert, aber gar nicht verwendet.
Man benutzt keine durchnummerierten Namen und kopiert auch nicht gleichlautenden Code 19 mal.

Code: Alles auswählen

import serial
from time import sleep

DATEN = {
    1: b'68 06 06 68 81 80 4C 0D 00 01 5B 16',
    2: b'68 06 06 68 81 80 4C 0D 00 02 5C 16',
    3: b'68 06 06 68 81 80 4C 0D 00 03 5D 16',
    4: b'68 06 06 68 81 80 4C 0D 00 04 5E 16',
    5: b'68 06 06 68 81 80 4C 0D 00 05 5F 16',
    6: b'68 06 06 68 81 80 4C 0D 00 06 60 16',
    7: b'68 06 06 68 81 80 4C 0D 00 07 61 16',
    8: b'68 06 06 68 81 80 4C 0D 00 08 62 16',
    129: b'68 06 06 68 81 80 4C 0D 00 81 DB 16',
    130: b'68 06 06 68 81 80 4C 0D 00 82 DC 16',
    132: b'68 06 06 68 81 80 4C 0D 00 84 DE 16',
    133: b'68 06 06 68 81 80 4C 0D 00 85 DF 16',
    135: b'68 06 06 68 81 80 4C 0D 00 87 E1 16',
    136: b'68 06 06 68 81 80 4C 0D 00 88 E2 16',
    138: b'68 06 06 68 81 80 4C 0D 00 8A E4 16',
    139: b'68 06 06 68 81 80 4C 0D 00 8B E5 16',
    141: b'68 06 06 68 81 80 4C 0D 00 8D E5 16',
    142: b'68 06 06 68 81 80 4C 0D 00 8E E8 16',
    144: b'68 06 06 68 81 80 4C 0D 00 90 EA 16',
}

def senden_daten():
    connection = serial.Serial(
                    port = "COM3",
                    baudrate = 19200,
                    parity = serial.PARITY_EVEN,
                    stopbits = serial.STOPBITS_ONE,
                    bytesize = serial.EIGHTBITS,
                    #timeout = 1,
                    )
    print("Serial Port ist offen!")
    while True:
        print("Neu lesen: \n")
        results = {}
        for channel, data in DATEN.items()
            connection.write(data)
            print(f"Kanal: {channel}")
            print(f"Sende Daten: {data}")
            results[channel] = connection.readline(35)
            print(f"Empfangene Daten: {results[channel]}")
        sleep(15)

if __name__ == "__main__":
    senden_daten()
Die gesendeten Daten sehen so ähnlich aus, dass man die bestimmt aus der Kanalnummer berechnen kann.
Du benutzt readline. Also hast Du ein zeilenbasiertes Protokoll. Dann fehlt aber beim Senden das Newline-Zeichen.
Beim Lesen würde ich dann aber immer die komplette Zeile lesen und nicht nur 35 Zeichen davon.

Code: Alles auswählen

import serial
from time import sleep

CHANNELS = [1,2,3,4,5,6,7,8,129,130,32,133,135,136,138,139,141,142,144]
DATA = '68 06 06 68 81 80 4C 0D 00 {:02X} {:02X} 16\n'

def senden_daten():
    connection = serial.Serial(
                    port = "COM3",
                    baudrate = 19200,
                    parity = serial.PARITY_EVEN,
                    stopbits = serial.STOPBITS_ONE,
                    bytesize = serial.EIGHTBITS,
                    #timeout = 1,
                    )
    print("Serial Port ist offen!")
    while True:
        print("Neu lesen: \n")
        results = {}
        for channel in CHANNELS
            data = DATA.format(channel, channel + 90).encode('ASCII')
            connection.write(data)
            print(f"Kanal: {channel}")
            print(f"Sende Daten: {data}")
            results[channel] = connection.readline()
            print(f"Empfangene Daten: {results[channel]}")
        sleep(15)

if __name__ == "__main__":
    senden_daten()
Und wie sehen nun die Empfangenen Daten exakt aus?
Didination
User
Beiträge: 16
Registriert: Montag 1. Februar 2021, 15:24

Danke für die Rückantwort. Wie die Daten aussehen, kann ich leider momentan nicht sehen, da ich nicht vor Ort arbeiten kann und dies auch erst ab kommendem Montag.

Ich werde mich melden, wenn ich dann was habe.
Gruß, Didination
Didination
User
Beiträge: 16
Registriert: Montag 1. Februar 2021, 15:24

Morgen alle zusammen,

ich habe nun das Programm ausprobiert (danke dafür nochmals, es ist wesentlich übersichtlicher).
Die empfangenen Daten sehen weiter nach dem Muster
\xb7\xbb\xbb\xb7\xbc\xbb\xb7\xbf\xb7\xbd\xbd\xbb\xbd\xb7\xbf\xb5k\xbd\xbdw\xaf\xbd\xbf\xbf\xbd\xbd\xb5{\xb7\xbd\xb7
aus. Ich weiß leider noch nicht, was das für eine genaue Darstellung ist, da die Werte eigentlich nach dem Befehl in "real" gesendet werden sollen.
Gruß, Didination
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Es wäre sehr seltsam, dass man zwar HexZahlen als ASCII-Zeichen senden muß, aber Binäre Daten zurückbekommt. Hast Du die richtigen Serial-Parameter angegeben?
Und wie sieht die Ausgabe meines Beispielprogramms exakt aus?
Didination
User
Beiträge: 16
Registriert: Montag 1. Februar 2021, 15:24

Die Ausgabe aus deinem Beispiel ist genau die gleiche wie bei meinem ursprünglichem Code.
Serial Port ist offen!
Neu lesen:

Kanal: 1
Sende Daten: b'68 06 06 68 81 80 4C 0D 00 01 5B 16'
Empfangene Daten: b'\xb7\xbd\xbf\xbb\xb7\xbf\xbd\xb7\xbf\xb7\xbf\xbf\xbd\xbd\xbd\xbd\xbb\xbf\xb5k\xbd\xbfw\xbf\xbd\xbf\xbf\xbf\xbd\xbd\xb5k\xbf\xbd\xb7'
Kanal: 2
Sende Daten: b'68 06 06 68 81 80 4C 0D 00 02 5C 16'
Empfangene Daten: b'\xb7\xbe\xbd\xbd\xb7\xaf\xbd\xb7\xbf\xb7\xbf\xbd\xbd\xbd\xbd\xbf\xbb\xbf\xb7k\xbd\xbfw\xbf\xbd\xbf\xbf\xbf\xbb\xbf\xb5k\xbf\xbd\xb7'
Kanal: 3
Sende Daten: b'68 06 06 68 81 80 4C 0D 00 03 5D 16'
Empfangene Daten: b'\xb7\xbf\xbd\xbf\xb7\xbf\xbf\xb7\xbf\xb7\xbb\xbd\xbf\xbd\xbf\xbf\xbd\xbf\xb5k\xbf\xbfw\xbf\xbf\xb7\xbf\xbf\xbb\xbf\xb5w\xbf\xbd\xb7'
Kanal: 4
Sende Daten: b'68 06 06 68 81 80 4C 0D 00 04 5E 16'
Empfangene Daten: b'\xb7\xbf\xbd\xbf\xb7\xbf\xbf\xb7\xbf\xb7\xbf\xbd\xbf\xbd\xaf\xbd\xbd\xbf\xb7k\xbf\xbfw\xbf\xbf\xbb\xbb\xbf\xb7\xbf\xb5u\xbf\xbd\xb7'
Kanal: 5
Sende Daten: b'68 06 06 68 81 80 4C 0D 00 05 5F 16'
Empfangene Daten: b'\xb7\xbf\xbf\xbf\xb7\xbf\xbf\xb7\xaf\xb7\xbf\xbf\xbd\xbd\xbf\xbf\xbd\xbf\xb7{\xbf\xbfw\xbf\xbf\xbb\xbb\xbf\xb5\xaf\xb5w\xbf\xbd\xb7'
und so weiter mit den weiteren Kanälen. Ich habe nun auch versucht, das jeweils anders anzeigen zu lassen, aber hat bisher leider nichts funktioniert.
Gruß, Didination
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Also wenn man im Netz sucht, sieht das sehr nach dem M-BUS-Protokoll aus, und das ist Binär und ohne Textzeilenenden. Frames werden mit dem Bytewert 0x16 beendet (+ es gibt einen Nachrichtentyp (ACK) der nur aus dem Bytewert 0xE5 besteht).
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Didination
User
Beiträge: 16
Registriert: Montag 1. Februar 2021, 15:24

Der Datalogger kann auf Modbus eingestellt werden, ist aber auf Profibus eingestellt.
Das was ich auch an Befehlen sende (68 06 06 68 81 80 4C 0D 00 01 5B 16) ist das, was ein fertiges Programm auch sendet. Nach den Informationen, die ich habe, wird auch mitgegeben, dass die Werte in real gesendet werden sollen.
Gruß, Didination
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ah, das sieht ja sehr ähnlich aus. Und ist auch binär.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was ist denn dieses “real” das du immer erwähnst? Das ist in diesem Zusammenhang kein feststehender Begriff.
Didination
User
Beiträge: 16
Registriert: Montag 1. Februar 2021, 15:24

Das andere Programm verwendet Funktionen aus einer dll-Datei. Einer dieser Funktionen ist "_SDLG_GetChannelReal". Die Befehle, die ich verwende, sind die Befehle, die das andere Programm an den Datalogger schickt. So wie ich das nun sehe, ist diese Funktion wahrscheinlich mit darin enthalten. Irrtum ist natürlich nicht ausgeschlossen.
Gruß, Didination
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich behaupte ja mal, dass deine Daten NICHT in hexadezimal versandt werden sollen. Sondern binär.

Hast du Dokumentation zu dem Protokoll?
Didination
User
Beiträge: 16
Registriert: Montag 1. Februar 2021, 15:24

Auf die Dokumentation kann man nicht mehr zugreifen, da man sich dazu einloggen muss und ich das nicht gespeichert habe, da ich die auch nicht verwenden kann.

https://www.google.com/url?sa=t&rct=j&q ... wKnk3LZwkY
Gruß, Didination
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ah, das Thema gab's im Raspi-Forum schon mal, da hattest Du es mit der DLL für Windows versucht, was auf dem Raspi natürlich nicht geht: https://forum-raspberrypi.de/forum/thre ... empfangen/

Da hatte ich ein PDF zum Datalogger IDL101 verlinkt. Damals noch wegen dem ASCII-Protokoll, aber da steht auch etwas zum Profibus-Protokoll drin.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

@didination die Gesamten Informationen, die in dem anderen Thread mühselig zusammengesammelt worden sind, hättest du hier schon gleich im ersten Post beibringen können, oder sogar müssen. Stattdessen hast du alle Beteiligten hier unnötig rumraten und experimentieren lassen. Unter anderem mit dem offensichtlich falschen “hex” Protokoll. Du darfst dir schon ein bisschen Mühe geben beim vorbringen deiner Anliegen hier. Und das ist auch einer der Gründe, warum Cross-posting schlecht ist.

Die Dokumentation die wir dank blackjack jetzt vorliegen haben erwæhnt zwei Baudraten. Bist dir sicher, dass du die korrekte hast? Und wenn das geklärt ist, dann wandele eine der Nachrichten in die korrespondierenden Bytes um, statt “hex”. Und schick die, und schau, was als Ergebnis kommt. Wobei die auch nicht im Zeilenformat vorliegen. Readline kann also NICHT verwandt werden.
Antworten