Forum: Haus & Smart Home SMA Home-Manager Multicast-Messages Auswertung


von Bot N. (botnec)


Lesenswert?

Hallo,

ich konnte mit Hilfe hier aus dem Forum mittels ESP01S Multicast-
messages vom SMA Homemanager2 und Energymeter empfangen. Meine
Beispiele liefert alles was in der Message steckt. Ich brauche aber
nur paar bestimmte Werte daraus und bin jetzt dabei die Ausgaben
zu durchforsten und nur das was für mich interessant ist auszuwählen.

Dabei bin ich auf folgende Dinge gestoßen dir mir im Moment nicht
ergründlich sind.

- Ich bekomme einen Timestampwert. Welche Zeit ist das ? Epochtime wäre
zu weit in der Zukunft.

- Es gibt da eine OBIS Wert 0:73.4.0 , der ist in der SMA Doku zum
Protokoll aber nicht aufgeführt.

- dann gibt es am Ende noch paar Bytes die auch nicht dokumentiert sind.

Hier ein Beispiel:

0 4 2 A0 0 0 0 1 defaultGroup=1
2 4C 0 10 60 69 1 74
protocolID=24681, susyID=372, serial=3011230234, timestamp=2572600805
0:1.4.0=49
0:1.8.0=506032560.00
.....
.....
0:71.4.0=910
0:72.4.0=224305
0:73.4.0=758
144:0.0.0=Strange measurement skipped
2:13.6.82=Strange measurement skipped

Hat da vielleicht jemand weitere Kenntnisse dazu oder Hinweise
auf Dokumentation dazu und kann mir helfen?

Das SMA Dokument zum Protokoll habe ich.

Danke für sachdienliche Hinweise.

: Bearbeitet durch User
von Εrnst B. (ernst)


Lesenswert?

Wie schon geschrieben: Bei mir läuft das über node-red, das Parsen des 
UDP-Packets hab ich in Javascript.
Für deinen ESP-Beispielcode hab ich das KI-Gestützt in Arduino-C++ 
übersetzt. Ob da die Byteorder passt, ob irgendwelche integer-promotions 
den int64 kaputt machen, usw. bitte selber prüfen. Als MSP430-Entwickler 
sollten dir die C-Fallstricke an der Stelle ja bekannt sein.

Für die Datenübertragung ESP->MSP430 ist das als Dezimalzahl eh 
"suboptimal", der liest das einfacher als HEX oder Binär...
d.H. das ganze rumgerechne ist eher für den Menschen der an der 
Seriellen mitliest.

Ansonsten, das ist meine Feld-Config:
1
const WsToWh=1.0/3600.0;
2
3
const felder={
4
    "0:1.8.0": { name: "Summe_Bezug", factor: WsToWh, db: true },
5
    "0:1.4.0": { name: "Wirkleistung_Summe_Plus", factor: 0.1 },
6
7
    "0:2.8.0": { name: "Summe_Einspeisung", factor: WsToWh, db:true },
8
    "0:2.4.0": { name: "Wirkleistung_Summe_Minus", factor: 0.1 },
9
10
    "0:3.8.0": { name: "Blindleistung_Summe_Saldo_Plus", factor: WsToWh },
11
    "0:3.4.0": { name: "Blindleistung_Summe_Plus", factor: 0.1 },
12
13
    "0:4.8.0": { name: "Blindleistung_Summe_Saldo_Minus", factor: WsToWh },
14
    "0:4.4.0": { name: "Blindleistung_Summe_Minus", factor: 0.1 },
15
16
    "0:9.8.0": { name: "Scheinleistung_Summe_Saldo_Plus", factor: WsToWh },
17
    "0:9.4.0": { name: "Scheinleistung_Summe_Plus", factor: 0.1 },
18
19
    "0:10.8.0": { name: "Scheinleistung_Summe_Saldo_Minus", factor: WsToWh },
20
    "0:10.4.0": { name: "Scheinleistung_Summe_Minus", factor: 0.1 },
21
22
    "0:13.4.0": { name: "Leistungsfaktor", factor: 0.001 },
23
24
    // dieser Block wiederholt sich für jede Phase:
25
    "0:21.8.0": { name: "Summe_L1_Bezug", factor: WsToWh },
26
    "0:21.4.0": { name: "Wirkleistung_L1_Plus", factor: 0.1 },
27
    "0:22.8.0": { name: "Summe_L1_Einspeisung", factor: WsToWh },
28
    "0:22.4.0": { name: "Wirkleistung_L1_Minus", factor: 0.1 },
29
    "0:23.4.0": { name: "Blindleistung_L1_Plus", factor: 0.1 },
30
    "0:24.4.0": { name: "Blindleistung_L1_Minus", factor: 0.1 },
31
    "0:23.8.0": { name: "Blindleistung_L1_Saldo_Plus", factor: WsToWh },
32
    "0:24.8.0": { name: "Blindleistung_L1_Saldo_Minus", factor: WsToWh },
33
    "0:29.4.0": { name: "Scheinleistung_L1_Plus", factor: 0.1 },
34
    "0:30.4.0": { name: "Scheinleistung_L1_Minus", factor: 0.1 },
35
    "0:29.8.0": { name: "Scheinleistung_L1_Saldo_Plus", factor: WsToWh },
36
    "0:30.8.0": { name: "Scheinleistung_L1_Saldo_Minus", factor: WsToWh },
37
    "0:31.4.0": { name: "Strom_L1", factor: 0.001, db: true },
38
    "0:32.4.0": { name: "Spannung_L1", factor: 0.1, db: true },
39
    "0:33.4.0": { name: "Leistungsfaktor_L1", factor: 0.001 },
40
41
    "0:41.8.0": { name: "Summe_L2_Bezug", factor: WsToWh },
42
    "0:41.4.0": { name: "Wirkleistung_L2_Plus", factor: 0.1 },
43
    "0:42.8.0": { name: "Summe_L2_Einspeisung", factor: WsToWh },
44
    "0:42.4.0": { name: "Wirkleistung_L2_Minus", factor: 0.1},
45
    "0:43.4.0": { name: "Blindleistung_L2_Plus", factor: 0.1 },
46
    "0:44.4.0": { name: "Blindleistung_L2_Minus", factor: 0.1 },
47
    "0:43.8.0": { name: "Blindleistung_L2_Saldo_Plus", factor: WsToWh },
48
    "0:44.8.0": { name: "Blindleistung_L2_Saldo_Minus", factor: WsToWh },
49
    "0:49.4.0": { name: "Scheinleistung_L2_Plus", factor: 0.1 },
50
    "0:50.4.0": { name: "Scheinleistung_L2_Minus", factor: 0.1 },
51
    "0:49.8.0": { name: "Scheinleistung_L2_Saldo_Plus", factor: WsToWh },
52
    "0:50.8.0": { name: "Scheinleistung_L2_Saldo_Minus", factor: WsToWh },
53
    "0:51.4.0": { name: "Strom_L2", factor: 0.001, db: true },
54
    "0:52.4.0": { name: "Spannung_L2", factor: 0.1, db: true },
55
    "0:53.4.0": { name: "Leistungsfaktor_L2", factor: 0.001 },
56
57
    "0:61.8.0": { name: "Summe_L3_Bezug", factor: WsToWh },
58
    "0:61.4.0": { name: "Wirkleistung_L3_Plus", factor: 0.1 },
59
    "0:62.8.0": { name: "Summe_L3_Einspeisung", factor: WsToWh },
60
    "0:62.4.0": { name: "Wirkleistung_L3_Minus", factor: 0.1 },
61
    "0:63.4.0": { name: "Blindleistung_L3_Plus", factor: 0.1 },
62
    "0:64.4.0": { name: "Blindleistung_L3_Minus", factor: 0.1 },
63
    "0:63.8.0": { name: "Blindleistung_L3_Saldo_Plus", factor: WsToWh },
64
    "0:64.8.0": { name: "Blindleistung_L3_Saldo_Minus", factor: WsToWh },
65
    "0:69.4.0": { name: "Scheinleistung_L3_Plus", factor: 0.1 },
66
    "0:70.4.0": { name: "Scheinleistung_L3_Minus", factor: 0.1 },
67
    "0:69.8.0": { name: "Scheinleistung_L3_Saldo_Plus", factor: WsToWh },
68
    "0:70.8.0": { name: "Scheinleistung_L3_Saldo_Minus", factor: WsToWh },
69
    "0:71.4.0": { name: "Strom_L3", factor: 0.001, db: true },
70
    "0:72.4.0": { name: "Spannung_L3", factor: 0.1, db: true },
71
    "0:73.4.0": { name: "Leistungsfaktor_L3", factor: 0.001 }

jeweils mit Namen und Umrechnungsfaktor (Zählerwerte sind in 
Wattsekunden, Spannungen in 0.1V usw), das "db"-Flag markiert die Werte 
die ich zur Auswertung in der Datenbank speichere.

Der Datenblock für jede Phase ist immer gleich, nur um 20 verschoben, 
startet bei 21, 41, 61. So kommst du auch ohne explizite Dokumentation 
auf den 0:73.4.0 er Wert.

Was das 144er Feld bedeutet, weiß ich auch nicht.

und "2:13.6.82" macht wenig Sinn. Könnte sein, dass da der Parser-Code 
irgendwie aus dem Tritt gekommen ist, und die Feldgrenzen nicht mehr 
richtig erwischt. Evtl. wegen falscher Länge des 144er Feldes davor? 
Wenn die Werte danach nicht interessieren, könntest du die Bearbeitung 
auch gleich an der Stelle abbrechen.

Und der Timestamp sagt bei mir auch nix aus, kommt auch über Minuten 
immer derselbe Wert.

von Bot N. (botnec)


Lesenswert?

Danke Ernst für die erneute Hilfe!

Ohne deine Unterstützung und Vorbereitung wäre ich nicht soweit 
gekommen.
Da ich jetzt sowohl die serielle Schnittstelle in beiden Richtungen und
einen TCP Server betreiben und auch noch die Multicast Messages
mitlesen kann, gebe ich meine AT-FW Version auf. Der MSP430 bleibt
natürlich. Diese eigene ESP01S FW-Version erleichtert das Ganze 
ungemein.

Mit der Darstellung der Multicast Messages oben komme ich weiter, danke
für die ausführliche Beschreibung.

Zu 144:0.0.0 habe ich was in der Doku EMETER-Protokoll-TI-de-10.pdf
gefunden. Wird als Softwareversion mit 4 Byte angegeben.

Der Timestampwert zählt bei mir schon hoch, deshalb dachte ich zuerst
an Epochtime, aber da wäre heute der 12. April 2053. Wäre schön gewesen
wenn man daraus noch die Uhrzeit ermitteln könnte.

Habe jetzt wieder neues "Futter" .

Danke nochmals für die äußerst hilfreich Unterstützung!

: Bearbeitet durch User
von Εrnst B. (ernst)


Lesenswert?

Bot N. schrieb:
> Zu 144:0.0.0 habe ich was in der Doku EMETER-Protokoll-TI-de-10.pdf
> gefunden. Wird als Softwareversion mit 4 Byte angegeben.

Beitrag "Re: ESP01S: TCP Server und UDP Multicast"

Dann also ein
1
} if (index==144) {
2
  // Optional: Versionsnummer auslesen... aber interessiert die?
3
  offset += 4;
vor dem
1
} else {
2
// Strange
ergänzen...
dann sollte auch das "2:13.6.82" - Feld weg sein.

: Bearbeitet durch User
von Bot N. (botnec)


Lesenswert?

Danke,

nein , Versionsnummer und vieles andere interessiert nicht. Mir ging es
nur ums Verständnis der Daten.

Grüße und schönes WE

: Bearbeitet durch User
von Holger (mindmaster)


Lesenswert?

Hi,

habe dank der 2 Beiträge hier, es geschaft meinen Home Manger 2.0 
auzulesen.
Habe noch einen Punkt:
Mein Timestamp ist negativ und zählt somit runter Richtung 0.
-1482800258#Leistung=699.40
-1482799263#Leistung=715.50
-1482798268#Leistung=722.80
-1482797263#Leistung=710.50

@Bot N.: Könntest du mir deinen ESP Code zukommen lassen zum Vergleich?!
1
#include <ESP8266WiFi.h>
2
#include <ESP8266WiFiSTA.h>
3
#include <WiFiUdp.h>
4
#define LED D4 
5
const char* ssid = "********";
6
const char* password = "********";
7
unsigned int multicastPort = 9522;  // local port to listen on
8
IPAddress multicastIP(239, 12, 255, 254);
9
WiFiUDP Udp;
10
static void initWiFi() {
11
    WiFi.mode(WIFI_STA);
12
    WiFi.begin(ssid, password);
13
    Serial.print("Connecting to WiFi ..");
14
    while (WiFi.status() != WL_CONNECTED) {
15
        Serial.print('.');
16
        delay(500);
17
    }
18
    Serial.println(WiFi.localIP());
19
}
20
static void Soutput(int kanal, int index, int art, int tarif, String Bezeichnung, double value, int timestamp){
21
  Serial.print (timestamp);
22
  Serial.print ('#');
23
  //Serial.print(kanal);
24
  //Serial.print(':');
25
  //Serial.print(index);
26
  //Serial.print('.');
27
  //Serial.print(art);
28
  //Serial.print('.');
29
  //Serial.print(tarif);
30
  //Serial.print('#');
31
  Serial.print(Bezeichnung);
32
  Serial.print('=');
33
  Serial.println(value);
34
}
35
void setup() {
36
  pinMode(LED, OUTPUT);    // Setzen des PINs als Ausgang
37
  Serial.begin(57600);
38
  Serial.println("Connecting...");
39
  initWiFi();
40
  Udp.begin(multicastPort);
41
#ifdef ESP8266
42
  Udp.beginMulticast(WiFi.localIP(), multicastIP, multicastPort);
43
#else
44
  Udp.beginMulticast(multicastIP, multicastPort);
45
#endif
46
}
47
void loop() {
48
    digitalWrite(LED, !(digitalRead(LED))); // LED umschalten
49
    uint8_t buffer[1024];
50
    int packetSize = Udp.parsePacket();
51
    String Bezeichnung;
52
    double Pbezug = 0;
53
    double Peinspeisung = 0;
54
    double Leistung = 0;
55
    uint32_t timestampalt = 0;
56
    bool output = false;
57
    if (packetSize) {
58
        int rSize = Udp.read(buffer, 1024);
59
        if (buffer[0] != 'S' || buffer[1] != 'M' || buffer[2] != 'A') {
60
            Serial.println("Not an SMA packet?");
61
            return;
62
        }
63
        uint16_t grouplen;
64
        uint16_t grouptag;
65
        uint8_t* offset = buffer + 4;
66
        do {
67
            grouplen = (offset[0] << 8) + offset[1];
68
            grouptag = (offset[2] << 8) + offset[3];
69
            offset += 4;
70
            if (grouplen == 0xffff) return;
71
            if (grouptag == 0x02A0 && grouplen == 4) {
72
                offset += 4;
73
            } else if (grouptag == 0x0010) {
74
                uint8_t* endOfGroup = offset + grouplen;
75
                uint16_t protocolID = (offset[0] << 8) + offset[1];
76
                offset += 2;
77
                uint16_t susyID = (offset[0] << 8) + offset[1];
78
                offset += 2;
79
                uint32_t serial = (offset[0] << 24) + (offset[1] << 16) + (offset[2] << 8) + offset[3];
80
                offset += 4;
81
                uint32_t timestamp = (offset[0] << 24) + (offset[1] << 16) + (offset[2] << 8) + offset[3];
82
                offset += 4;
83
                while (offset < endOfGroup) {
84
                    uint8_t kanal = offset[0];
85
                    uint8_t index = offset[1];
86
                    uint8_t art = offset[2];
87
                    uint8_t tarif = offset[3];
88
                    offset += 4;
89
                    if (art == 8) {
90
                        uint64_t data = ((uint64_t)offset[0] << 56) +
91
                                      ((uint64_t)offset[1] << 48) +
92
                                      ((uint64_t)offset[2] << 40) +
93
                                      ((uint64_t)offset[3] << 32) +
94
                                      ((uint64_t)offset[4] << 24) +
95
                                      ((uint64_t)offset[5] << 16) +
96
                                      ((uint64_t)offset[6] << 8) +
97
                                      offset[7];
98
                        offset += 8;
99
                    } else if (art == 4) {
100
                      uint32_t data = (offset[0] << 24) +
101
                      (offset[1] << 16) +
102
                      (offset[2] << 8) +
103
                      offset[3];
104
                      offset += 4;
105
                      switch (index) {
106
                      case 1:
107
                        Pbezug = data * 0.1;
108
                        break;
109
                      case 2:
110
                        Peinspeisung = data * 0.1;
111
                        output = true;
112
                        break;
113
                      default:
114
                        Bezeichnung = "Data         : ";
115
                        break; // Wird nicht benötigt, wenn Statement(s) vorhanden sind
116
                      }
117
                        if (output == true){
118
                        Leistung = Peinspeisung - Pbezug;
119
                        Soutput(kanal, index, art, tarif, "Leistung", Leistung, timestamp);
120
                        output = false;
121
                      }
122
                    } else if (kanal==144) {
123
                      // Optional: Versionsnummer auslesen... aber interessiert die?
124
                      offset += 4;
125
                    } else {
126
                        offset += art;
127
                        Serial.println("Strange measurement skipped");
128
                    }
129
                }
130
            } else if (grouptag == 0) {
131
                // end marker
132
                offset += grouplen;
133
            } else {
134
                Serial.print("unhandled group ");
135
                Serial.print(grouptag);
136
                Serial.print(" with len=");
137
                Serial.println(grouplen);
138
                offset += grouplen;
139
            }
140
        } while (grouplen > 0 && offset + 4 < buffer + rSize);
141
    }
142
}

: Bearbeitet durch User
von Bot N. (botnec)


Lesenswert?

Ich benutze hier den originalen Teil des Sourcecodes von
Ernst B. hier im Forum.

Beitrag "ESP01S: TCP Server und UDP Multicast"

Habe da nichts geändert. Meine Timestamp zählt aufwärts, ist aber
leider keine Uhrzeit. Ich ignoriere diesen Wert.

Hoffe das hilft weiter.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.