Datenemfpang

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

Montag 29. März 2021, 10:51

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: 8575
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Montag 29. März 2021, 11:21

@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)
“Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”
Didination
User
Beiträge: 16
Registriert: Montag 1. Februar 2021, 15:24

Montag 29. März 2021, 11:33

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: 8575
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Montag 29. März 2021, 14:15

Das sollten dann eigentlich 4 Byte Floats sein. Was mit der Länge von jetzt 33 Bytes nicht so ganz hin kommt.
“Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”
Didination
User
Beiträge: 16
Registriert: Montag 1. Februar 2021, 15:24

Mittwoch 31. März 2021, 08:50

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: 14430
Registriert: Sonntag 21. Oktober 2012, 17:20

Mittwoch 31. März 2021, 09:42

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

Dienstag 6. April 2021, 09:08

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

Montag 12. April 2021, 07:31

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: 14430
Registriert: Sonntag 21. Oktober 2012, 17:20

Montag 12. April 2021, 08:44

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

Montag 12. April 2021, 09:17

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: 8575
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Montag 12. April 2021, 09:33

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).
“Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”
Didination
User
Beiträge: 16
Registriert: Montag 1. Februar 2021, 15:24

Montag 12. April 2021, 09:40

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: 8575
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Montag 12. April 2021, 10:04

Ah, das sieht ja sehr ähnlich aus. Und ist auch binär.
“Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”
__deets__
User
Beiträge: 9690
Registriert: Mittwoch 14. Oktober 2015, 14:29

Montag 12. April 2021, 10:37

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

Montag 12. April 2021, 10:48

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
Antworten