Closed EIKSEU closed 1 year ago
`
GCM
// Variables for DLMS decoding uint32_t last_read = 0; // Timestamp when data was last read uint16_t receive_buffer_index = 0; // Current position in the receive buffer uint8_t receive_buffer[RECEIVE_BUFFER_SIZE]; // Stores the received data
// Function prototypes uint32_t swap_uint32(uint32_t val); uint16_t swap_uint16(uint16_t val); void serial_dump();
// SETUP void setup() { // Debug port Serial.begin(115200);
// MBus input
Serial1.begin(2400, SERIAL_8E1);
// Serial1.txBufferSize(RECEIVE_BUFFER_SIZE);
gcmaes128 = new GCM
// MAIN LOOP void loop() { uint32_t current_time = millis(); // Read while data is available while (Serial1.available()) { if (receive_buffer_index >= RECEIVE_BUFFER_SIZE) { Serial.println("Buffer overflow!"); receive_buffer_index = 0; return; }
receive_buffer[receive_buffer_index++] = Serial1.read();
last_read = current_time;
}
static unsigned long previous_millis = 0;
Serial.println(receive_buffer_index);
uint16_t payload_length = 243;
uint16_t payload_length_msg1 = 228;
uint16_t payload_length_msg2 = payload_length - payload_length_msg1;
uint8_t iv[12]; // Initialization vector
memcpy(&iv[0], &receive_buffer[DLMS_SYST_OFFSET], DLMS_SYST_LENGTH); // Copy system title to IV
memcpy(&iv[8], &receive_buffer[DLMS_IC_OFFSET], DLMS_IC_LENGTH); // Copy invocation counter to IV
uint8_t ciphertext[payload_length];
memcpy(&ciphertext[0], &receive_buffer[DLMS_HEADER1_LENGTH], payload_length_msg1);
memcpy(&ciphertext[payload_length_msg1], &receive_buffer[DLMS_HEADER2_OFFSET + DLMS_HEADER2_LENGTH], payload_length_msg2);
// Start decrypting
uint8_t plaintext[payload_length];
gcmaes128->setKey(key, gcmaes128->keySize());
gcmaes128->setIV(iv, 12);
gcmaes128->decrypt(plaintext, ciphertext, payload_length);
// Decode data
uint16_t current_position = DECODER_START_OFFSET;
meterData meter_data;
if (plaintext[current_position + OBIS_TYPE_OFFSET] != DATA_OCTET_STRING)
{
Serial.println("Unsupported OBIS header type!");
receive_buffer_index = 0;
return;
}
uint8_t data_length = plaintext[current_position + OBIS_LENGTH_OFFSET];
if (data_length != 0x06)
{
// read timestamp
if ((data_length == 0x0C) && (current_position == DECODER_START_OFFSET))
{
uint8_t dateTime[data_length];
memcpy(&dateTime[0], &plaintext[current_position + 2], data_length);
uint16_t year;
uint8_t month, day, hour, minute, second;
year = (plaintext[current_position + 2] << 8) + plaintext[current_position + 3];
month = plaintext[current_position + 4];
day = plaintext[current_position + 5];
hour = plaintext[current_position + 7];
minute = plaintext[current_position + 8];
second = plaintext[current_position + 9];
sprintf(meter_data.timestamp_str, "%02u.%02u.%04u %02u:%02u:%02u", day, month, year, hour, minute, second);
meter_data.timestamp_unix = -1;
// COMMENTED OUT BECAUSE I DONT WANT THE PAIN CONVERSION WITH TIMEZONZES
// JUST USE -1 TO USE TIME OF ARRIVAL ON GRAPHITE HOST
//
// convert to unix timestamp for graphite
// struct tm tm;
// if (strptime(meter_data.timestamp_str, "%d.%m.%Y %H:%M:%S", &tm) != NULL)
// {
//// TODO: detect time zone summer time/winter time
// meter_data.timestamp_unix = mktime(&tm) - 7200;
// Serial.print("Unix Time: ");
// Serial.println(meter_data.timestamp_unix);
// }
// else
// {
// Serial.println("Invalid Timestamp");
// receive_buffer_index = 0;
// return;
// }
Serial.print("Timestamp: ");
Serial.println(meter_data.timestamp_str);
current_position = 34;
data_length = plaintext[current_position + OBIS_LENGTH_OFFSET];
}
else if ((data_length == 0x0C) && (current_position > 225))
{
uint8_t meterNumber[data_length];
memcpy(&meterNumber[0], &plaintext[current_position + 2], data_length);
// THIS IS THE END OF THE PACKET
// break;
}
else
{
Serial.println("Unsupported OBIS header length");
receive_buffer_index = 0;
return;
}
uint8_t obis_code[data_length];
memcpy(&obis_code[0], &plaintext[current_position + OBIS_CODE_OFFSET], data_length); // Copy OBIS code to array
current_position += data_length + 2; // Advance past code, position and type
uint8_t obis_data_type = plaintext[current_position];
current_position++; // Advance past data type
uint8_t obis_data_length = 0x00;
uint8_t code_type = TYPE_UNKNOWN;
if (obis_code[OBIS_A] == 0x01)
{
// Compare C and D against code
if (memcmp(&obis_code[OBIS_C], OBIS_VOLTAGE_L1, 2) == 0)
{
code_type = TYPE_VOLTAGE_L1;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_VOLTAGE_L2, 2) == 0)
{
code_type = TYPE_VOLTAGE_L2;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_VOLTAGE_L3, 2) == 0)
{
code_type = TYPE_VOLTAGE_L3;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_CURRENT_L1, 2) == 0)
{
code_type = TYPE_CURRENT_L1;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_CURRENT_L2, 2) == 0)
{
code_type = TYPE_CURRENT_L2;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_CURRENT_L3, 2) == 0)
{
code_type = TYPE_CURRENT_L3;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_ACTIVE_POWER_PLUS, 2) == 0)
{
code_type = TYPE_ACTIVE_POWER_PLUS;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_ACTIVE_POWER_MINUS, 2) == 0)
{
code_type = TYPE_ACTIVE_POWER_MINUS;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_ACTIVE_ENERGY_PLUS, 2) == 0)
{
code_type = TYPE_ACTIVE_ENERGY_PLUS;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_ACTIVE_ENERGY_MINUS, 2) == 0)
{
code_type = TYPE_ACTIVE_ENERGY_MINUS;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_POWER_FACTOR, 2) == 0)
{
code_type = TYPE_POWER_FACTOR;
}
else
{
Serial.println("Unsupported OBIS code");
}
}
else
{
Serial.println("Unsupported OBIS medium");
receive_buffer_index = 0;
return;
}
uint16_t uint16_value;
uint32_t uint32_value;
float float_value;
switch (obis_data_type)
{
case DATA_LONG_DOUBLE_UNSIGNED:
obis_data_length = 4;
memcpy(&uint32_value, &plaintext[current_position], 4); // Copy uint8_ts to integer
uint32_value = swap_uint32(uint32_value); // Swap uint8_ts
float_value = uint32_value; // Ignore decimal digits for now
switch (code_type)
{
case TYPE_ACTIVE_POWER_PLUS:
meter_data.power_plus = float_value;
Serial.print("ActivePowerPlus ");
Serial.println(float_value);
break;
case TYPE_ACTIVE_POWER_MINUS:
meter_data.power_minus = float_value;
Serial.print("ActivePowerMinus ");
Serial.println(float_value);
break;
case TYPE_ACTIVE_ENERGY_PLUS:
meter_data.energy_plus = float_value;
Serial.print("ActiveEnergyPlus ");
Serial.println(float_value);
break;
case TYPE_ACTIVE_ENERGY_MINUS:
meter_data.energy_minus = float_value;
Serial.print("ActiveEnergyMinus ");
Serial.println(float_value);
break;
}
break;
case DATA_LONG:
case DATA_LONG_UNSIGNED:
obis_data_length = 2;
memcpy(&uint16_value, &plaintext[current_position], 2); // Copy uint8_ts to integer
uint16_value = swap_uint16(uint16_value); // Swap uint8_ts
if (plaintext[current_position + 5] == SCALE_TENTHS)
float_value = uint16_value / 10.0;
else if (plaintext[current_position + 5] == SCALE_HUNDREDTHS)
float_value = uint16_value / 100.0;
else if (plaintext[current_position + 5] == SCALE_THOUSANDS)
float_value = uint16_value / 1000.0;
else
float_value = uint16_value;
switch (code_type)
{
case TYPE_VOLTAGE_L1:
meter_data.voltage_l1 = float_value;
Serial.print("VoltageL1 ");
Serial.println(float_value);
break;
case TYPE_VOLTAGE_L2:
meter_data.voltage_l2 = float_value;
Serial.print("VoltageL2 ");
Serial.println(float_value);
break;
case TYPE_VOLTAGE_L3:
meter_data.voltage_l3 = float_value;
Serial.print("VoltageL3 ");
Serial.println(float_value);
break;
case TYPE_CURRENT_L1:
meter_data.current_l1 = float_value;
Serial.print("CurrentL1 ");
Serial.println(float_value);
break;
case TYPE_CURRENT_L2:
meter_data.current_l2 = float_value;
Serial.print("CurrentL2 ");
Serial.println(float_value);
break;
case TYPE_CURRENT_L3:
meter_data.current_l3 = float_value;
Serial.print("CurrentL3 ");
Serial.println(float_value);
break;
case TYPE_POWER_FACTOR:
meter_data.cos_phi = float_value;
Serial.print("PowerFactor ");
Serial.println(float_value);
break;
}
break;
case DATA_OCTET_STRING:
obis_data_length = plaintext[current_position];
current_position++; // Advance past string length
break;
default:
Serial.println("Unsupported OBIS data type");
receive_buffer_index = 0;
return;
break;
}
current_position += obis_data_length; // Skip data length
current_position += 2; // Skip pause after data
if (plaintext[current_position] == 0x0F) // There is still additional data for this type, skip it
current_position += 4; // Skip additional data and additional break; this will jump out of bounds on last frame
} while (current_position <= payload_length); // Loop until end of packet
receive_buffer_index = 0;
Serial.println("Received valid data!");
// copy timestamp into file string
// creates new file every month
char filename[13] = {"/YYYY_MM.CSV"};
memcpy(&filename[6], &meter_data.timestamp_str[3], 2);
memcpy(&filename[1], &meter_data.timestamp_str[6], 4);
sprintf(filename, "/%d_%02d.CSV", random(2021, 2026), random(1, 12));
char record[128];
sprintf(record, "%.1f;%.1f;%.1f;%.2f;%.2f;%.2f;%.3f;%.1f;%.1f;%.0f;%.0f;%.2f;%.2f;%d", meter_data.voltage_l1, meter_data.voltage_l2, meter_data.voltage_l3, meter_data.current_l1, meter_data.current_l2, meter_data.current_l3, meter_data.cos_phi, meter_data.power_plus, meter_data.power_minus, meter_data.energy_plus, meter_data.energy_minus, meter_data.temperature, meter_data.humidity, meter_data.rssi);
String _tmp = String(record);
_tmp.replace(".", ",");
sprintf(record, "%s;%s", meter_data.timestamp_str, _tmp.c_str());
}
uint16_t swap_uint16(uint16_t val) { return (val << 8) | (val >> 8); }
uint32_t swap_uint32(uint32_t val) { val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF); return (val << 16) | (val >> 16); }`
code von evn habe ich
`String keystring = ""; char char_keystring[] = "00000000000000000000000000000000"; byte key[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; char convertCharToHex(char ch) { char returnType; switch (ch) { case '0': returnType = 0; break; case '1': returnType = 1; break; case '2': returnType = 2; break; case '3': returnType = 3; break; case '4': returnType = 4; break; case '5': returnType = 5; break; case '6': returnType = 6; break; case '7': returnType = 7; break; case '8': returnType = 8; break; case '9': returnType = 9; break; case 'A': case 'a': returnType = 10; break; case 'B': case 'b': returnType = 11; break; case 'C': case 'c': returnType = 12; break; case 'D': case 'd': returnType = 13; break; case 'E': case 'e': returnType = 14; break; case 'F': case 'f': returnType = 15; break; default: returnType = -1; break; } return returnType; }
void setup() { Serial.begin(115200);
keystring = "mein code"; keystring.toCharArray(char_keystring, keystring.length() + 1);
if (keystring.length() != 32) { Serial.println("ERROR - key Eingabefehler!"); } else { for (char i = 0; i < 16; i++) { byte extract; char a = keystring[2 i]; char b = keystring[2 i + 1]; extract = convertCharToHex(a) << 4 | convertCharToHex(b);
key[i] = extract;
Serial.print("key von der Eingabe: ");Serial.print(key[i], HEX); Serial.print(" ");
}
}
}
void loop() { keystring = "meinevncode"; keystring.toCharArray(char_keystring, keystring.length() + 1);
if (keystring.length() != 32) { Serial.println("ERROR - key Eingabefehler!"); } else { for (char i = 0; i < 16; i++) { byte extract; char a = keystring[2 i]; char b = keystring[2 i + 1]; extract = convertCharToHex(a) << 4 | convertCharToHex(b); delay(1000);
key[i] = extract;
if (i == 0){
Serial.print("Start: ");Serial.print(key[i], HEX); Serial.print("----- ");}
Serial.print("0x");Serial.print(key[i], HEX); Serial.print(", ");
}
}
}`
Wenn dein Code von der EVN "3B4C183A" wäre, musst du im Programm einfach "0x3B, 0x4C, 0x18, 0x3A" eintragen. War zumindest bei mir so.
Ok ja das kommt hin ...
Hattest du das so eingetragen? Bzw. war das das Problem?
Den Key habe habe so in der key.h // Your Encryption Key static const unsigned char key[] = {0x00, 0x00, 0x00, 0x00, 0x00,.....};
Der Fehler liegt vermutlich bei #include <mbedtls/gcm.h> da das im Arduino nicht läuft und ich das mit AES.h und GCM.h versuche zu entschlüsseln vermute der Fehler liegt hier:
// Start decrypting
uint8_t plaintext[payload_length];
gcmaes128->setKey(key, gcmaes128->keySize());
gcmaes128->setIV(iv, 12);
gcmaes128->decrypt(plaintext, ciphertext, payload_length);
Hast du die mbedtls heruntergeladen und im Projektordner? https://github.com/wolfeidau/mbedtls Mit der funktionierts bei mir.
So siehts bei mir aus:
uint8_t plaintext[payload_length];
mbedtls_gcm_init(&aes);
mbedtls_gcm_setkey(&aes, MBEDTLS_CIPHER_ID_AES, KEY, KEY_LENGTH * 8);
mbedtls_gcm_auth_decrypt(&aes, payload_length, iv, sizeof(iv), NULL, 0, NULL, 0, ciphertext, plaintext);
mbedtls_gcm_free(&aes);
Von wo hast du den Code? Das ist ja nicht genau der von hier oder zumindest abgeändert.
für einen Sagecom macht das einer so: `
void decrypt_text(Vector_GCM &vect) {
GCM
struct Vector_GCM { const char *name; byte keysize; unsigned int datasize; byte authsize; byte ivsize; byte tagsize; uint8_t key[16]; byte plaintext[MAX_PLAINTEXT_LEN]; byte ciphertext[MAX_PLAINTEXT_LEN]; byte authdata[17]; byte iv[12]; byte tag[12]; };
IncommingData aktuelleDaten;
Vector_GCM datenMbus = { //static
.name = "AES-128 GCM",
.keysize = 16,
.datasize = 297,
.authsize = 17,
.ivsize = 12,
.tagsize = 12,
.key = { key},
.plaintext = {},
.ciphertext = {},
.authdata = {},
.iv = {},
.tag = {},
};`
aber was davon wird für n Kaifa benötigt?
So wie es in diesem Link ist sollte es beim Kaifa funktionieren ( zumindest gehts bei mir): https://github.com/FKW9/esp-smartmeter-netznoe/blob/master/src/main.cpp
Ich weiß nicht für was das sein soll, was du da geschickt hast, bin aber auch kein Profi :D Ich hab noch die Vorgängerversion am laufen und sie für mich etwas angepasst, dass ich die Daten über MQTT erhalte.
läuft das bei dir auf einem Arduino?
@EIKSEU Warum verwendest du keinen ESP32? Welches M-Bus Interface hast du zur Verfügung?
Bei mir läufts auf einem ESP32, weil ich für MQTT W-Lan benötige. Aber fürn Arduino ist der Code eigentlich genau der gleiche. Nur halt ohne die ganzen W-Lan sachen.
Bekommst du überhaupt Daten vom Zähler oder bekommst du gar nix rein?
da ich arduino sonst auch verwende. Ja es kommen daten der Fehler ist dieser
.....................smartmeter-netznoe.ino:78: undefined reference to `mbedtls_gcm_init'
.......................smartmeter-netznoe.ino:79: undefined reference to `mbedtls_gcm_setkey'
......................smartmeter-netznoe.ino:80: undefined reference to `mbedtls_gcm_auth_decrypt'
......................smartmeter-netznoe.ino:81: undefined reference to `mbedtls_gcm_free'
collect2.exe: error: ld returned 1 exit status
exit status 1
ich habe alle ordner im im Ordner mit der .ino datei kopiert das Problem habe ich von Anfang an daher habe ich es anders versucht
Hast du die mbedtls Library was ich oben verlinkt habe im Projektordner? Die ist hier nämlich nicht dabei.
https://github.com/wolfeidau/mbedtls die meinst du?
Ja genau. Ohne die gehts nicht. Ich hab da selbst auch etwas gebraucht, bis ich die gefunden hab. Wenn du den Ordner mbedtls in deinen Projektordner einfügst, müsste es schon funktionieren.
Ich hab grad nachgesehen. Ich hab die ganzen Dateien vom Ordner Source auch in den Ordner mbedtls kopiert.
ok das hab ich jetzt auch aber noch kein erfolg....
ich habs nun so eingefügt
jetzt ist noch dieser fehler .... \source\gcm.c:82:33: error: invalid conversion from 'void' to 'volatile unsigned char' [-fpermissive] volatile unsigned char p = v; while( n-- ) p++ = 0
hast eine Idee
`You need to cast as you can not convert a void* to anything without casting it first.
You would need to do
unsigned char etherhead = (unsigned char)buffer; (although you could use a static_cast also)
To learn more about void pointers, take a look at [6.13 — Void pointers](http://www.learncpp.com/cpp-tutorial/613-void-pointers/`
das habe ich versucht da sind noch mehr Fehler gekommen
gcm.c musst u nicht einbinden. Wie hast du denn die Ordner in deinem Projekt angelegt? liegt der mbedtls ordner im source ordner? Versuch mal so: Dein Projekt => mbedtls => hier alle Dateien vom ordner mbedtls und source
Den source Ordner kannst dann löschen und mit
#include "mbedtls/gcm.h"
einbinden
Das hatte ich aber dan passen die includes nicht mehr und die .c datein werden anscheinend nur gefunden wenn ich sie miteinander....
Ich hab grad versucht es für Arduino ohne WiFi zu kompilieren, aber da fehlen dann einen haufen Librarys. Ich würd sagen, am einfachsten wäre es, wenn du dir einfach einen ESP32 kaufst. Die kosten ja ned wirklich was und du kannst dann auch mal was mit WLan programmieren, dass du dir z.B. die Werte am Handy ansehen kannst.
Ok danke für deine Hilfe werde noch versuchen es zu lösen.....
Wie SebTrax schon gesagt hat, fehlen viele Librarys für Arduino, unter anderem basiert der ganze WiFi Stack, die TFT-Lib, der Logger, das Filesystem, die GPIOs usw. alles auf dem ESP32. Am einfachsten wäre es, wenn du ein ESP32 Devkit für 14€ (auf AliExpress noch billiger) kaufst. Wenn du bei Arduino bleiben willst, wäre es besser wenn du den Code von Null-auf neu schreiben würdest, mit meinem z.B. als Vorlage. Somit kannst du immer stückweise testen, ob auch alles funktioniert.
Danke für eure Hilfe ich hab s jetzt....
`#include
GCM
// Variables for DLMS decoding uint32_t last_read = 0; // Timestamp when data was last read uint16_t receive_buffer_index = 0; // Current position in the receive buffer uint8_t receive_buffer[RECEIVE_BUFFER_SIZE]; // Stores the received data
// Function prototypes uint32_t swap_uint32(uint32_t val); uint16_t swap_uint16(uint16_t val); void serial_dump();
void PrintHex8(uint8_t *data, int length) // prints 8-bit data in hex with leading zeroes { char tmp[16]; for (int i = 0; i < length; i++) { sprintf(tmp, "0x%.2X", data[i]); Serial.print(tmp); Serial.print(" "); } }
// SETUP void setup() { // Debug port Serial.begin(115200);
// MBus input
Serial1.begin(2400, SERIAL_8E1);
// Serial1.setRxBufferSize(RECEIVE_BUFFER_SIZE); Serial1.setTimeout(2);
gcmaes128 = new GCM<AES128>();
Serial.println("\nWarte auf Smartmeter Daten...");
delay(2000);
}
// MAIN LOOP void loop() {
uint32_t current_time = millis();
// Read while data is available
while (Serial1.available())
{
if (receive_buffer_index >= RECEIVE_BUFFER_SIZE)
{
Serial.println("Buffer overflow!");
receive_buffer_index = 0;
return;
}
receive_buffer[receive_buffer_index++] = Serial1.read();
last_read = current_time;
}
const uint8_t test_data[] = {0x68, 0xFA, 0xFA, 0x68, 0x53, 0xFF, 0x00, 0x01, 0x67, 0xDB, 0x08, 0x4B, 0x46, 0x4D, 0x67, 0x50, 0x00, 0x08, 0x81, 0x81, 0xF8, 0x20, 0x00, 0x00, 0x60, 0x05, 0xC1, 0xFA, 0x38, 0xBC, 0xC6, 0xD9, 0x59, 0x4E, 0x5A, 0x7C, 0x36, 0x59, 0x13, 0x8B, 0x7E, 0xE9, 0x9A, 0x83, 0x47, 0xBF, 0x50, 0xB9, 0x98, 0xF8, 0x33, 0x85, 0x81, 0x08, 0x45, 0x12, 0xA3, 0x78, 0x0C, 0xAC, 0xBF, 0x5B, 0xCB, 0x36, 0x67, 0x44, 0xC9, 0x9E, 0x99, 0xE5, 0x3A, 0x12, 0xE8, 0x67, 0xD4, 0xED, 0xE6, 0x8E, 0xF8, 0x2A, 0x91, 0xF6, 0xD7, 0x6C, 0x08, 0x6C, 0x73, 0xAD, 0x57, 0x54, 0xCE, 0x8F, 0x13, 0x13, 0xD9, 0xF7, 0x38, 0xC8, 0x50, 0xD4, 0x93, 0x62, 0x75, 0x0A, 0x9B, 0x6F, 0xCB, 0xE3, 0x3A, 0xDE, 0x62, 0xA1, 0x6C, 0x62, 0xA9, 0xB5, 0xCA, 0xC7, 0x93, 0x31, 0xE9, 0x78, 0x62, 0x81, 0x60, 0x4B, 0xC9, 0x24, 0x22, 0xA1, 0x24, 0xE0, 0xC3, 0xB9, 0xC9, 0x79, 0xD0, 0xE2, 0x65, 0xDA, 0x60, 0x14, 0x03, 0xC5, 0x56, 0xB8, 0x96, 0x09, 0x44, 0xC4, 0x24, 0xBA, 0xD4, 0x9D, 0x63, 0xAD, 0xAB, 0xFB, 0xAE, 0xDA, 0x07, 0x5D, 0x66, 0x88, 0x2F, 0x5C, 0xB5, 0x5A, 0x7A, 0xAD, 0x43, 0xFC, 0x24, 0x47, 0x0F, 0x3B, 0x23, 0xBD, 0x6B, 0xBB, 0xFF, 0x71, 0xC6, 0x44, 0x7A, 0x3D, 0xEB, 0x2E, 0xA4, 0x7D, 0x80, 0x60, 0xD7, 0xAA, 0xF6, 0x2F, 0x14, 0x9C, 0x0D, 0xD4, 0xCF, 0x60, 0xFD, 0xC9, 0x1C, 0x20, 0xED, 0x9A, 0x6D, 0xCC, 0xF0, 0x6D, 0xA5, 0x4D, 0xFB, 0x9B, 0x5F, 0x45, 0x60, 0xDF, 0xB5, 0x36, 0x4E, 0x0E, 0x01, 0x05, 0x6A, 0x07, 0x36, 0x4A, 0x60, 0x5F, 0x85, 0x75, 0xF3, 0x84, 0x1D, 0x51, 0x7D, 0x07, 0x22, 0x06, 0x14, 0xCF, 0xC7, 0xCF, 0x98, 0x82, 0x5E, 0xE7, 0x20, 0xC5, 0x1C, 0xBC, 0x59, 0x16, 0x68, 0x14, 0x14, 0x68, 0x53, 0xFF, 0x11, 0x01, 0x67, 0x4C, 0xC1, 0xD2, 0x17, 0xB8, 0xD8, 0x03, 0x4C, 0xC7, 0x51, 0x5F, 0xE0, 0x20, 0x95, 0x61, 0x0D, 0x16, 0x68, 0xFA, 0xFA, 0x68, 0x53, 0xFF, 0x00, 0x01, 0x67, 0xDB, 0x08, 0x4B, 0x46, 0x4D, 0x67, 0x50, 0x00, 0x08, 0x81, 0x81, 0xF8, 0x20, 0x00, 0x00, 0x60, 0x05, 0xC1, 0xFA, 0x38, 0xBC, 0xC6, 0xD9, 0x59, 0x4E, 0x5A, 0x7C, 0x36, 0x59, 0x13, 0x8B, 0x7E, 0xE9, 0x9A, 0x83, 0x47, 0xBF, 0x50, 0xB9, 0x98, 0xF8, 0x33, 0x85, 0x81, 0x08, 0x45, 0x12, 0xA3, 0x78, 0x0C, 0xAC, 0xBF, 0x5B, 0xCB, 0x36, 0x67, 0x44, 0xC9, 0x9E, 0x99, 0xE5, 0x3A, 0x12, 0xE8, 0x67, 0xD4, 0xED, 0xE6, 0x8E, 0xF8, 0x2A, 0x91, 0xF6, 0xD7, 0x6C, 0x08, 0x6C, 0x73, 0xAD, 0x57, 0x54, 0xCE, 0x8F, 0x13, 0x13, 0xD9, 0xF7, 0x38, 0xC8, 0x50, 0xD4, 0x93, 0x62, 0x75, 0x0A, 0x9B, 0x6F, 0xCB, 0xE3, 0x3A, 0xDE, 0x62, 0xA1, 0x6C, 0x62, 0xA9, 0xB5, 0xCA, 0xC7, 0x93, 0x31, 0xE9, 0x78, 0x62, 0x81, 0x60, 0x4B, 0xC9, 0x24, 0x22, 0xA1, 0x24, 0xE0, 0xC3, 0xB9, 0xC9, 0x79, 0xD0, 0xE2, 0x65, 0xDA, 0x60, 0x14, 0x03, 0xC5, 0x56, 0xB8, 0x96, 0x09, 0x44, 0xC4, 0x24, 0xBA, 0xD4, 0x9D, 0x63, 0xAD, 0xAB, 0xFB, 0xAE, 0xDA, 0x07, 0x5D, 0x66, 0x88, 0x2F, 0x5C, 0xB5, 0x5A, 0x7A, 0xAD, 0x43, 0xFC, 0x24, 0x47, 0x0F, 0x3B, 0x23, 0xBD, 0x6B, 0xBB, 0xFF, 0x71, 0xC6, 0x44, 0x7A, 0x3D, 0xEB, 0x2E, 0xA4, 0x7D, 0x80, 0x60, 0xD7, 0xAA, 0xF6, 0x2F, 0x14, 0x9C, 0x0D, 0xD4, 0xCF, 0x60, 0xFD, 0xC9, 0x1C, 0x20, 0xED, 0x9A, 0x6D, 0xCC, 0xF0, 0x6D, 0xA5, 0x4D, 0xFB, 0x9B, 0x5F, 0x45, 0x60, 0xDF, 0xB5, 0x36, 0x4E, 0x0E, 0x01, 0x05, 0x6A, 0x07, 0x36, 0x4A, 0x60, 0x5F, 0x85, 0x75, 0xF3, 0x84, 0x1D, 0x51, 0x7D, 0x07, 0x22, 0x06, 0x14, 0xCF, 0xC7, 0xCF, 0x98, 0x82, 0x5E, 0xE7, 0x20, 0xC5, 0x1C, 0xBC, 0x59, 0x16, 0x68, 0x14, 0x14, 0x68, 0x53, 0xFF, 0x11, 0x01, 0x67, 0x4C, 0xC1, 0xD2, 0x17, 0xB8, 0xD8, 0x03, 0x4C, 0xC7, 0x51, 0x5F, 0xE0, 0x20, 0x95, 0x61, 0x0D, 0x16};
static unsigned long previous_millis = 0;
if (millis() - previous_millis > 4000)
{
previous_millis = last_read = millis();
memcpy(&receive_buffer, &test_data, sizeof(test_data));
receive_buffer_index = sizeof(test_data) - 1;
}
if (receive_buffer_index > 0 && current_time - last_read > READ_TIMEOUT)
{
if (receive_buffer_index < 256)
{
Serial.println("Received packet with invalid size!");
Serial.println(receive_buffer_index);
receive_buffer_index = 0;
return;
}
/**
* @TODO: ADD ROUTINE TO DETERMINE PAYLOAD LENGTHS AUTOMATICALLY
*/
uint16_t payload_length = 243;
uint16_t payload_length_msg1 = 228;
uint16_t payload_length_msg2 = payload_length - payload_length_msg1;
uint8_t iv[12]; // Initialization vector
memcpy(&iv[0], &receive_buffer[DLMS_SYST_OFFSET], DLMS_SYST_LENGTH); // Copy system title to IV
memcpy(&iv[8], &receive_buffer[DLMS_IC_OFFSET], DLMS_IC_LENGTH); // Copy invocation counter to IV
uint8_t ciphertext[payload_length];
memcpy(&ciphertext[0], &receive_buffer[DLMS_HEADER1_LENGTH], payload_length_msg1);
memcpy(&ciphertext[payload_length_msg1], &receive_buffer[DLMS_HEADER2_OFFSET + DLMS_HEADER2_LENGTH], payload_length_msg2);
// Start decrypting
uint8_t plaintext[payload_length];
Serial.print("\n\nkey: ");
PrintHex8(key, sizeof key);
//Serial.print("\nkey vom Server: "); Serial.print(keystring);
Serial.print("\niv: ");
PrintHex8(iv, sizeof iv);
gcmaes128->setKey(key, gcmaes128->keySize());
gcmaes128->setIV(iv, 12);
gcmaes128->decrypt(plaintext, ciphertext, payload_length);
/*mbedtls_gcm_init(&aes);
mbedtls_gcm_setkey(&aes, MBEDTLS_CIPHER_ID_AES, KEY, KEY_LENGTH * 8);
mbedtls_gcm_auth_decrypt(&aes, payload_length, iv, sizeof(iv), NULL, 0, NULL, 0, ciphertext, plaintext);
mbedtls_gcm_free(&aes);
*/
if (plaintext[0] != 0x0F || plaintext[5] != 0x0C)
{
Serial.println("Packet was decrypted but data is invalid!");
receive_buffer_index = 0;
return;
}
// Decode data
uint16_t current_position = DECODER_START_OFFSET;
meterData meter_data;
do
{
if (plaintext[current_position + OBIS_TYPE_OFFSET] != DATA_OCTET_STRING)
{
Serial.println("Unsupported OBIS header type!");
receive_buffer_index = 0;
return;
}
uint8_t data_length = plaintext[current_position + OBIS_LENGTH_OFFSET];
if (data_length != 0x06)
{
// read timestamp
if ((data_length == 0x0C) && (current_position == DECODER_START_OFFSET))
{
uint8_t dateTime[data_length];
memcpy(&dateTime[0], &plaintext[current_position + 2], data_length);
uint16_t year;
uint8_t month, day, hour, minute, second;
year = (plaintext[current_position + 2] << 8) + plaintext[current_position + 3];
month = plaintext[current_position + 4];
day = plaintext[current_position + 5];
hour = plaintext[current_position + 7];
minute = plaintext[current_position + 8];
second = plaintext[current_position + 9];
sprintf(meter_data.timestamp_str, "%02u.%02u.%04u %02u:%02u:%02u", day, month, year, hour, minute, second);
meter_data.timestamp_unix = -1;
Serial.print("Timestamp: ");
Serial.println(meter_data.timestamp_str);
current_position = 34;
data_length = plaintext[current_position + OBIS_LENGTH_OFFSET];
}
else if ((data_length == 0x0C) && (current_position > 225))
{
uint8_t meterNumber[data_length];
memcpy(&meterNumber[0], &plaintext[current_position + 2], data_length);
// THIS IS THE END OF THE PACKET
break;
}
else
{
Serial.println("Unsupported OBIS header length");
receive_buffer_index = 0;
return;
}
}
uint8_t obis_code[data_length];
memcpy(&obis_code[0], &plaintext[current_position + OBIS_CODE_OFFSET], data_length); // Copy OBIS code to array
current_position += data_length + 2; // Advance past code, position and type
uint8_t obis_data_type = plaintext[current_position];
current_position++; // Advance past data type
uint8_t obis_data_length = 0x00;
uint8_t code_type = TYPE_UNKNOWN;
if (obis_code[OBIS_A] == 0x01)
{
// Compare C and D against code
if (memcmp(&obis_code[OBIS_C], OBIS_VOLTAGE_L1, 2) == 0)
{
code_type = TYPE_VOLTAGE_L1;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_VOLTAGE_L2, 2) == 0)
{
code_type = TYPE_VOLTAGE_L2;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_VOLTAGE_L3, 2) == 0)
{
code_type = TYPE_VOLTAGE_L3;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_CURRENT_L1, 2) == 0)
{
code_type = TYPE_CURRENT_L1;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_CURRENT_L2, 2) == 0)
{
code_type = TYPE_CURRENT_L2;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_CURRENT_L3, 2) == 0)
{
code_type = TYPE_CURRENT_L3;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_ACTIVE_POWER_PLUS, 2) == 0)
{
code_type = TYPE_ACTIVE_POWER_PLUS;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_ACTIVE_POWER_MINUS, 2) == 0)
{
code_type = TYPE_ACTIVE_POWER_MINUS;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_ACTIVE_ENERGY_PLUS, 2) == 0)
{
code_type = TYPE_ACTIVE_ENERGY_PLUS;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_ACTIVE_ENERGY_MINUS, 2) == 0)
{
code_type = TYPE_ACTIVE_ENERGY_MINUS;
}
else if (memcmp(&obis_code[OBIS_C], OBIS_POWER_FACTOR, 2) == 0)
{
code_type = TYPE_POWER_FACTOR;
}
else
{
Serial.println("Unsupported OBIS code");
}
}
else
{
Serial.println("Unsupported OBIS medium");
receive_buffer_index = 0;
return;
}
uint16_t uint16_value;
uint32_t uint32_value;
float float_value;
switch (obis_data_type)
{
case DATA_LONG_DOUBLE_UNSIGNED:
obis_data_length = 4;
memcpy(&uint32_value, &plaintext[current_position], 4); // Copy uint8_ts to integer
uint32_value = swap_uint32(uint32_value); // Swap uint8_ts
float_value = uint32_value; // Ignore decimal digits for now
switch (code_type)
{
case TYPE_ACTIVE_POWER_PLUS:
meter_data.power_plus = float_value;
Serial.print("ActivePowerPlus ");
Serial.println(float_value);
break;
case TYPE_ACTIVE_POWER_MINUS:
meter_data.power_minus = float_value;
Serial.print("ActivePowerMinus ");
Serial.println(float_value);
break;
case TYPE_ACTIVE_ENERGY_PLUS:
meter_data.energy_plus = float_value;
Serial.print("ActiveEnergyPlus ");
Serial.println(float_value);
break;
case TYPE_ACTIVE_ENERGY_MINUS:
meter_data.energy_minus = float_value;
Serial.print("ActiveEnergyMinus ");
Serial.println(float_value);
break;
}
break;
case DATA_LONG:
case DATA_LONG_UNSIGNED:
obis_data_length = 2;
memcpy(&uint16_value, &plaintext[current_position], 2); // Copy uint8_ts to integer
uint16_value = swap_uint16(uint16_value); // Swap uint8_ts
if (plaintext[current_position + 5] == SCALE_TENTHS)
float_value = uint16_value / 10.0;
else if (plaintext[current_position + 5] == SCALE_HUNDREDTHS)
float_value = uint16_value / 100.0;
else if (plaintext[current_position + 5] == SCALE_THOUSANDS)
float_value = uint16_value / 1000.0;
else
float_value = uint16_value;
switch (code_type)
{
case TYPE_VOLTAGE_L1:
meter_data.voltage_l1 = float_value;
Serial.print("VoltageL1 ");
Serial.println(float_value);
break;
case TYPE_VOLTAGE_L2:
meter_data.voltage_l2 = float_value;
Serial.print("VoltageL2 ");
Serial.println(float_value);
break;
case TYPE_VOLTAGE_L3:
meter_data.voltage_l3 = float_value;
Serial.print("VoltageL3 ");
Serial.println(float_value);
break;
case TYPE_CURRENT_L1:
meter_data.current_l1 = float_value;
Serial.print("CurrentL1 ");
Serial.println(float_value);
break;
case TYPE_CURRENT_L2:
meter_data.current_l2 = float_value;
Serial.print("CurrentL2 ");
Serial.println(float_value);
break;
case TYPE_CURRENT_L3:
meter_data.current_l3 = float_value;
Serial.print("CurrentL3 ");
Serial.println(float_value);
break;
case TYPE_POWER_FACTOR:
meter_data.cos_phi = float_value;
Serial.print("PowerFactor ");
Serial.println(float_value);
break;
}
break;
case DATA_OCTET_STRING:
obis_data_length = plaintext[current_position];
current_position++; // Advance past string length
break;
default:
Serial.println("Unsupported OBIS data type");
receive_buffer_index = 0;
return;
break;
}
current_position += obis_data_length; // Skip data length
current_position += 2; // Skip pause after data
if (plaintext[current_position] == 0x0F) // There is still additional data for this type, skip it
current_position += 4; // Skip additional data and additional break; this will jump out of bounds on last frame
} while (current_position <= payload_length); // Loop until end of packet
receive_buffer_index = 0;
Serial.println("Received valid data!");
/* // send the data
submitToGraphite(meter_data.timestamp_unix, GRAPHITE_VOLTAGE_L1, meter_data.voltage_l1);
submitToGraphite(meter_data.timestamp_unix, GRAPHITE_VOLTAGE_L2, meter_data.voltage_l2);
submitToGraphite(meter_data.timestamp_unix, GRAPHITE_VOLTAGE_L3, meter_data.voltage_l3);
submitToGraphite(meter_data.timestamp_unix, GRAPHITE_CURRENT_L1, meter_data.current_l1);
submitToGraphite(meter_data.timestamp_unix, GRAPHITE_CURRENT_L2, meter_data.current_l2);
submitToGraphite(meter_data.timestamp_unix, GRAPHITE_CURRENT_L3, meter_data.current_l3);
submitToGraphite(meter_data.timestamp_unix, GRAPHITE_POWER_FACTOR, meter_data.cos_phi);
submitToGraphite(meter_data.timestamp_unix, GRAPHITE_ACTIVE_POWER_PLUS, meter_data.power_plus);
submitToGraphite(meter_data.timestamp_unix, GRAPHITE_ACTIVE_POWER_MINUS, meter_data.power_minus);
submitToGraphite(meter_data.timestamp_unix, GRAPHITE_ACTIVE_ENERGY_PLUS, meter_data.energy_plus);
submitToGraphite(meter_data.timestamp_unix, GRAPHITE_ACTIVE_ENERGY_MINUS, meter_data.energy_minus);
submitToGraphite(meter_data.timestamp_unix, GRAPHITE_T, meter_data.temperature);
submitToGraphite(meter_data.timestamp_unix, GRAPHITE_RH, meter_data.humidity);
submitToGraphite(meter_data.timestamp_unix, GRAPHITE_RSSI, meter_data.rssi);
*/
}
}
uint16_t swap_uint16(uint16_t val)
{
return (val << 8) | (val >> 8);
}
uint32_t swap_uint32(uint32_t val) { val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF); return (val << 16) | (val >> 16); }`
Hallo,
versuche den Code auf einem Arduino zu verwenden kannst du mir dabei helfen ich hänge beim entschlüsseln.....
Mfg