/*
Zeile 24: hier kommen die Daten vom Zähler rein und die Anzahl Bytes
In Setup wird der key abgefragt. Key eingeben und Enter
*/
#define ESP
#include "esp8266_obis.h"
#include <Crypto.h>
#include <AES.h>
#include <GCM.h>
GCM<AES128> *gcmaes128 = 0;
float voltage_l1, voltage_l2, voltage_l3, current_l1, current_l2, current_l3, active_power_plus, active_power_minus, active_energy_plus, active_energy_minus, reactive_energy_plus, reactive_energy_minus;
uint16_t year;
uint8_t month, day, hour, minute, second;
char timestamp[21]; // 0000-00-00T00:00:00Z
char zaehlernummer[20], devicename[20];
//byte rxBuffer[376] = {0x68, 0xFA, 0xFA, 0x68, 0x53, 0xFF, 0x00, 0x01, 0x67, 0xDB, 0x08, 0x4B, 0x46, 0x4D, 0x10, 0x20, 0x04, 0x3B, 0xD7, 0x82, 0x01, 0x55, 0x21, 0x00, 0x00, 0x8F, 0xA2, 0xDF, 0x4E, 0x42, 0x85, 0x0F, 0x1A, 0x76, 0xEB, 0x5A, 0x93, 0x5E, 0x42, 0x36, 0xEA, 0x7D, 0x26, 0x10, 0x76, 0x44, 0xC7, 0xC1, 0x63, 0x22, 0x9F, 0x25, 0x38, 0xBE, 0xF9, 0xE3, 0x54, 0x01, 0x6C, 0x5D, 0xFC, 0x2D, 0xAC, 0x07, 0x1D, 0xD0, 0x83, 0xFD, 0xD2, 0xAB, 0x1E, 0xB4, 0xF3, 0x35, 0xF3, 0x3F, 0xBC, 0xE5, 0x4A, 0x88, 0xB5, 0xC9, 0x7A, 0x52, 0x9E, 0x97, 0x9B, 0x61, 0x42, 0x90, 0xFD, 0xB2, 0xB5, 0xDF, 0x76, 0x0A, 0x4E, 0x88, 0xD6, 0x98, 0x4E, 0xF2, 0x3D, 0x79, 0xC4, 0x83, 0x36, 0xD1, 0x6F, 0x29, 0x9F, 0xC3, 0xBF, 0x16, 0xC8, 0x07, 0x2F, 0xCC, 0xA2, 0x3E, 0xE6, 0x67, 0xC8, 0x03, 0x17, 0x57, 0xDB, 0xFC, 0x1F, 0xF2, 0x4E, 0xE6, 0x73, 0x84, 0x65, 0xC9, 0x0E, 0x67, 0x5D, 0x90, 0x61, 0x1B, 0xA7, 0x40, 0xCE, 0x91, 0x25, 0xA0, 0x30, 0x08, 0x53, 0xC0, 0xF0, 0xD9, 0x58, 0x28, 0xE0, 0x43, 0xB5, 0x01, 0x84, 0xAA, 0xA4, 0x3F, 0xF8, 0x33, 0x5B, 0xCE, 0x02, 0xD6, 0xE8, 0xA7, 0xB5, 0xF7, 0x81, 0x89, 0x23, 0xFB, 0xFE, 0x30, 0xAA, 0xC3, 0xF6, 0x19, 0xF8, 0xB4, 0xAF, 0x77, 0x8D, 0xAC, 0x38, 0xBF, 0xB3, 0xCC, 0xFF, 0xC5, 0x9C, 0x22, 0x31, 0xE9, 0x0E, 0x06, 0x7C, 0x59, 0x11, 0xDC, 0x93, 0x53, 0x20, 0xE6, 0x55, 0xC2, 0xCF, 0x1C, 0x04, 0xCA, 0x38, 0x05, 0xEB, 0xED, 0x05, 0x16, 0x39, 0x04, 0x13, 0x8F, 0x2B, 0xE3, 0xC7, 0xFD, 0xE8, 0x4F, 0x7F, 0xCE, 0xAC, 0x95, 0x19, 0xF9, 0x9D, 0x33, 0x43, 0xBD, 0x64, 0xFC, 0xB1, 0x10, 0xBA, 0xD6, 0x98, 0xBF, 0x67, 0xAE, 0x11, 0x2E, 0xB4, 0x16, 0x68, 0x72, 0x72, 0x68, 0x53, 0xFF, 0x11, 0x01, 0x67, 0x35, 0x51, 0x83, 0xCB, 0x78, 0xC9, 0xE3, 0xC4, 0x06, 0x70, 0xCC, 0x90, 0x6A, 0x45, 0xE6, 0x13, 0x38, 0x62, 0xA3, 0x84, 0x7E, 0x45, 0x3A, 0x5B, 0xC8, 0x11, 0xD3, 0x80, 0x3D, 0x98, 0xC1, 0xC4, 0x7E, 0x16, 0x1F, 0xB0, 0xF1, 0xC7, 0x47, 0x8E, 0x65, 0xAB, 0x29, 0xA5, 0x1F, 0x79, 0x0A, 0xC0, 0xAF, 0x68, 0x5B, 0x13, 0x6E, 0x37, 0xB4, 0xA9, 0xE7, 0xFA, 0x10, 0xC2, 0x7D, 0xB2, 0x9E, 0x4E, 0x29, 0xB8, 0x4A, 0x86, 0x03, 0x12, 0x0F, 0xEB, 0x4D, 0xFC, 0x4E, 0xF5, 0x87, 0xF6, 0xB3, 0xE8, 0x14, 0x8E, 0x45, 0x70, 0xFA, 0x99, 0xBA, 0x97, 0xB3, 0xC9, 0x41, 0xA0, 0x97, 0xA7, 0x9D, 0x35, 0x58, 0x10, 0x2C, 0x24, 0x9A, 0xCB, 0xEF, 0x12, 0x56, 0x1A, 0xA5, 0x8E, 0xF2, 0xE4, 0x16};
byte rxBuffer[376] = {0x68, 0xFA, 0xFA, 0x68, 0x53, 0xFF, 0x00, 0x01, 0x67, 0xDB, 0x08, 0x4B, 0x46, 0x4D, 0x10, 0x20, 0x04, 0x3B, 0xD7, 0x82, 0x01, 0x55, 0x21, 0x00, 0x01, 0x21, 0x7A, 0x29, 0xBE, 0x82, 0x12, 0x03, 0xEF, 0x1B, 0x19, 0xA8, 0xDE, 0x2F, 0x39, 0xEB, 0xE5, 0x08, 0xB8, 0x4A, 0x4B, 0x07, 0x64, 0x57, 0xD1, 0xC0, 0x85, 0x1F, 0x48, 0x83, 0x40, 0x8A, 0x70, 0x2D, 0x48, 0x78, 0x5E, 0x01, 0x84, 0xBE, 0xC2, 0xB4, 0xB8, 0x13, 0x32, 0x68, 0x18, 0x5A, 0xAE, 0x32, 0x22, 0x1D, 0x08, 0xCB, 0xF6, 0x89, 0x14, 0xD3, 0x9E, 0x5C, 0x5E, 0xB4, 0x67, 0x8A, 0x88, 0xF1, 0x83, 0xD2, 0xE3, 0x2E, 0xC2, 0x65, 0xE1, 0x55, 0xE6, 0xED, 0x1A, 0xFB, 0xEC, 0x7D, 0xB6, 0x96, 0x15, 0x3F, 0x06, 0xA0, 0x5A, 0xF9, 0x5C, 0x9D, 0x2D, 0x8E, 0xDE, 0x9F, 0xE1, 0x24, 0x9C, 0x96, 0x74, 0xCB, 0xB2, 0xFF, 0xD4, 0x3C, 0xB9, 0x82, 0x83, 0xC7, 0x55, 0x21, 0xE5, 0xA3, 0x94, 0x5F, 0x87, 0x4C, 0xD3, 0xC8, 0xC3, 0x2A, 0xBA, 0x5B, 0xA6, 0x6C, 0xB0, 0x81, 0x36, 0xC3, 0xA0, 0xFA, 0x0F, 0xF6, 0x31, 0x82, 0xF0, 0xCC, 0x42, 0xBC, 0x20, 0x60, 0x9C, 0xAB, 0x62, 0xD6, 0xA8, 0x97, 0x0E, 0xA4, 0xE6, 0xCE, 0x0E, 0xC7, 0x58, 0x35, 0x7E, 0x25, 0xE1, 0x94, 0x4D, 0x65, 0x5B, 0xD6, 0x6F, 0xB4, 0x74, 0x99, 0x1A, 0x8A, 0x56, 0xD1, 0xA1, 0x7D, 0xD6, 0x57, 0x6C, 0x37, 0x34, 0x1E, 0x56, 0xFB, 0x76, 0x2C, 0xC8, 0x82, 0x29, 0x25, 0x48, 0x92, 0x57, 0xB1, 0xB7, 0x83, 0xB8, 0x34, 0x94, 0x42, 0x3F, 0x29, 0xAB, 0xA1, 0x56, 0x6F, 0xE0, 0xEF, 0x35, 0xE7, 0x70, 0xC0, 0x51, 0x2E, 0xC6, 0xA0, 0xAD, 0x25, 0x1E, 0x61, 0x47, 0x0B, 0xB6, 0x79, 0x0C, 0x18, 0x5A, 0xAA, 0xBD, 0xAE, 0x31, 0x48, 0x52, 0xC8, 0x08, 0x16, 0x68, 0x72, 0x72, 0x68, 0x53, 0xFF, 0x11, 0x01, 0x67, 0xF4, 0xB6, 0x87, 0xFE, 0xC9, 0xC8, 0x9F, 0xC0, 0x31, 0xF7, 0x36, 0x7F, 0x69, 0x8E, 0x02, 0x68, 0x6B, 0xBF, 0x9E, 0xCC, 0xBD, 0x02, 0x18, 0x22, 0x7E, 0x58, 0x4D, 0x13, 0xA7, 0xD3, 0xEA, 0x8C, 0xE3, 0x30, 0xAD, 0x1B, 0xD4, 0xB8, 0x16, 0xD2, 0x70, 0x5D, 0x46, 0x46, 0x79, 0x42, 0x67, 0x37, 0xE2, 0x0F, 0xC5, 0x4C, 0x49, 0x19, 0xED, 0x28, 0x2C, 0x71, 0x55, 0xD1, 0x31, 0x3E, 0x61, 0xC5, 0xFB, 0x19, 0x8B, 0x65, 0x8E, 0x38, 0x4C, 0x0E, 0x83, 0x64, 0xC5, 0xDB, 0xB4, 0x3B, 0x85, 0x95, 0x8F, 0xBC, 0x70, 0xEE, 0xEF, 0xF4, 0x91, 0x99, 0xFF, 0x8E, 0x1D, 0x7C, 0xEE, 0xCF, 0xC2, 0x40, 0x5E, 0x40, 0xEE, 0xA6, 0xE3, 0x95, 0x3F, 0x8E, 0x0B, 0x5D, 0x1A, 0x1F, 0x64, 0x78, 0x16};
byte key[16];
byte systitle[8]; // von 11 bis 18
byte ic[4]; // von 23 bis 26
byte iv[12]; // systitle + ic
byte nachricht1[227];
byte nachricht2[227]; // angenommen Block 2 wird so gross wie Block 1
int nachricht1_startbyte = 0; // muss 0x68 sein
int nachricht1_endebyte = 0; // muss 0xFA sein
int nachricht1_laenge = 0; // muss 0x16 sein
int nachricht1_start_offset = 6;
int nachricht1_beginn_offset = 27;
int nachricht1_ende_offset = 0; // setzt sich zusammen aus nachricht1_laenge + nachricht1_start_offset
int nachricht2_laenge;
String Hex8_2_String(uint8_t *data, int length) { // prints 8-bit data in hex with leading zeroes
String strg = "";
char tmp2[16];
for (int i = 0; i < length; i++) {
sprintf(tmp2, "%.2X", data[i]);
strg += tmp2;
}
return strg;
}
uint16_t swap_uint16(uint16_t val) { return (val << 8) | (val >> 8); }
uint16_t swap_uint4(uint16_t val) { return (val << 4) ; }
uint32_t swap_uint32(uint32_t val) {
val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF);
return (val << 16) | (val >> 16);
}
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(" ");
}
}
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(2400);
gcmaes128 = new GCM<AES128>();
Serial.println("32 stelligen key eingeben:");
while (!Serial.available()); // Wait for input
String keystring = Serial.readStringUntil('\n');
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);
if (extract == -1) {
Serial.print("ERROR - key Eingabefehler!");
} else {
key[i] = extract;
//Serial.print("key von der Eingabe: ");Serial.print(key[i], HEX); Serial.print(" ");
}
}
}
void loop()
{
nachricht1_startbyte = rxBuffer[0], DEC; // 104 ... 0x68
nachricht1_laenge = rxBuffer[1], DEC; // 250 ... 0xFA
//Serial.print("nachricht1_laenge: "); Serial.println(nachricht1_laenge); //
nachricht1_endebyte = rxBuffer[(nachricht1_start_offset + nachricht1_laenge - 1)], DEC;
//nachricht2_laenge = rxBuffer[27 + sizeof nachricht1 + 2 ], DEC; // zeigt auf 0x68 und damit den Beginn von Nachricht2 68 26 26 68 53 FF 11 01 67 ....
nachricht2_laenge = rxBuffer[27 + sizeof nachricht1 + 2 + 1], DEC; // zeigt auf 0x26 (38 DEZ)
nachricht2_laenge = nachricht2_laenge - 5; // 33 Zeichen lang; 3 bytes cosem layer und 2 bytes am ende (checksum, endebyte) weglassen
//Serial.print("nachricht2_laenge: "); Serial.println(nachricht2_laenge); //
//Serial.print("\nTelegramm_gesamtlaenge: "); Serial.println(nachricht1_laenge - 23 + nachricht2_laenge);
if (nachricht1_startbyte == 104 && nachricht1_endebyte == 22) {
Serial.print("\n\nNachricht 1 gueltig");
// memcpy um den IV zu bekommen
memcpy(systitle, rxBuffer + 11, sizeof systitle); // SysTitle holen
memcpy(ic, rxBuffer + 23, sizeof ic); // IC holen
memcpy(iv, systitle, sizeof systitle); // IV aus SysTitle und IC erstellen
memcpy(iv + sizeof systitle, ic, sizeof ic);
// IV wurde korrekt zusammengestellt
memcpy(nachricht1, rxBuffer + 27, sizeof nachricht1 ); // liegt im Array von 0 bis 226 // Nachricht1 kopieren
memcpy(nachricht2, rxBuffer + 27 + sizeof nachricht1 + 2 + 9, nachricht2_laenge ); // Nachricht2 kopieren; encrypted payload beginnt bei 9
Serial.print("\nLänge nachricht1 = "); Serial.print(sizeof nachricht1);
Serial.print("\nLänge nachricht2 = "); Serial.print(sizeof nachricht2);
Serial.print("\n\nIV: "); Serial.print(iv[0], HEX); Serial.print(" "); Serial.print(iv[1], HEX); Serial.print(" "); Serial.print(iv[2], HEX); Serial.print(" "); Serial.print(iv[3], HEX); Serial.print(" "); Serial.print(iv[4], HEX); Serial.print(" "); Serial.print(iv[5], HEX); Serial.print(" "); Serial.print(iv[6], HEX); Serial.print(" "); Serial.print(iv[7], HEX); Serial.print(" "); Serial.print(iv[8], HEX); Serial.print(" "); Serial.print(iv[9], HEX); Serial.print(" "); Serial.print(iv[10], HEX); Serial.print(" "); Serial.print(iv[11], HEX);
Serial.print("\nkey: "); Serial.print(key[0], HEX); Serial.print(" "); Serial.print(key[1], HEX); Serial.print(" "); Serial.print(key[2], HEX); Serial.print(" "); Serial.print(key[3], HEX); Serial.print(" "); Serial.print(key[4], HEX); Serial.print(" "); Serial.print(key[5], HEX); Serial.print(" "); Serial.print(key[6], HEX); Serial.print(" "); Serial.print(key[7], HEX); Serial.print(" "); Serial.print(key[8], HEX); Serial.print(" "); Serial.print(key[9], HEX); Serial.print(" "); Serial.print(key[10], HEX); Serial.print(" ... "); Serial.print(key[15], HEX);
Serial.print("\n\nNachricht1 Anfang Ende: "); Serial.print(nachricht1[0], HEX); Serial.print(" "); Serial.print(nachricht1[226], HEX);
Serial.print("\nNachricht2 Anfang Ende: "); Serial.print(nachricht2[0], HEX); Serial.print(" "); Serial.print(nachricht2[nachricht2_laenge - 1], HEX);
byte ciphertxt[nachricht1_laenge - 23 + nachricht2_laenge];
memcpy(ciphertxt, nachricht1, sizeof nachricht1);
memcpy(ciphertxt+nachricht1_laenge - 23, nachricht2, sizeof nachricht2);
Serial.print("\n\nciphertxt: "); Serial.println(sizeof ciphertxt);
Serial.print(Hex8_2_String(ciphertxt, sizeof ciphertxt));
uint16_t payloadLength;
memcpy(&payloadLength, &rxBuffer[20], 2); // die Payload Länge wird im Header mitgegeben !!! Copy payload length Byte[20] und Byte[21] ==> in payLoadLength steht 0x01 0x09
payloadLength = swap_uint16(payloadLength) - 5;
Serial.print("\n\npayloadLength: "); Serial.println(payloadLength);
Serial.print("\nOBIS Code:\n");
byte plaintext[payloadLength];
gcmaes128->setKey(key, gcmaes128->keySize());
gcmaes128->setIV(iv, 12);
gcmaes128->decrypt(plaintext, ciphertxt, payloadLength);
Serial.print(Hex8_2_String(plaintext, sizeof plaintext));
// ********************************************************************************************************************************
// ab hier domistyle Code => https://github.com/DomiStyle/esphome-dlms-meter/
// ********************************************************************************************************************************
if (plaintext[0] != 0x0F || plaintext[5] != 0x0C) {
Serial.print("\n\nERROR - Obis Code fehlerhaft\n");
}
int currentPosition = DECODER_START_OFFSET; // = 20
do {
if (plaintext[currentPosition + OBIS_TYPE_OFFSET] != DataType::OctetString)
{
Serial.print("\n\ERROR - Unsupported OBIS header type");
}
byte obisCodeLength = plaintext[currentPosition + OBIS_LENGTH_OFFSET];
if (obisCodeLength != 0x06)
{
Serial.print("\n\ERROR - Unsupported OBIS header length");
}
byte obisCode[obisCodeLength];
memcpy(&obisCode[0], &plaintext[currentPosition + OBIS_CODE_OFFSET], obisCodeLength);
currentPosition += obisCodeLength + 2;
byte dataType = plaintext[currentPosition];
currentPosition++; // Advance past data type
byte dataLength = 0x00;
CodeType codeType = CodeType::Unknown;
if (obisCode[OBIS_A] == Medium::Electricity) {
// Compare C and D against code
if (memcmp(&obisCode[OBIS_C], ESPDM_VOLTAGE_L1, 2) == 0) {
codeType = CodeType::VoltageL1;
} else if (memcmp(&obisCode[OBIS_C], ESPDM_VOLTAGE_L2, 2) == 0) {
codeType = CodeType::VoltageL2;
} else if (memcmp(&obisCode[OBIS_C], ESPDM_VOLTAGE_L3, 2) == 0) {
codeType = CodeType::VoltageL3;
} else if (memcmp(&obisCode[OBIS_C], ESPDM_CURRENT_L1, 2) == 0) {
codeType = CodeType::CurrentL1;
} else if (memcmp(&obisCode[OBIS_C], ESPDM_CURRENT_L2, 2) == 0) {
codeType = CodeType::CurrentL2;
} else if (memcmp(&obisCode[OBIS_C], ESPDM_CURRENT_L3, 2) == 0) {
codeType = CodeType::CurrentL3;
} else if (memcmp(&obisCode[OBIS_C], ESPDM_ACTIVE_POWER_PLUS, 2) == 0) {
codeType = CodeType::ActivePowerPlus;
} else if (memcmp(&obisCode[OBIS_C], ESPDM_ACTIVE_POWER_MINUS, 2) == 0) {
codeType = CodeType::ActivePowerMinus;
} else if (memcmp(&obisCode[OBIS_C], ESPDM_ACTIVE_ENERGY_PLUS, 2) == 0) {
codeType = CodeType::ActiveEnergyPlus;
} else if (memcmp(&obisCode[OBIS_C], ESPDM_ACTIVE_ENERGY_MINUS, 2) == 0) {
codeType = CodeType::ActiveEnergyMinus;
} else if (memcmp(&obisCode[OBIS_C], ESPDM_REACTIVE_ENERGY_PLUS, 2) == 0) {
codeType = CodeType::ReactiveEnergyPlus;
} else if (memcmp(&obisCode[OBIS_C], ESPDM_REACTIVE_ENERGY_MINUS, 2) == 0) {
codeType = CodeType::ReactiveEnergyMinus;
} else {
Serial.print("\n\nERROR: Unsupported OBIS code");
}
} else if (obisCode[OBIS_A] == Medium::Abstract) {
if (memcmp(&obisCode[OBIS_C], ESPDM_TIMESTAMP, 2) == 0) {
codeType = CodeType::Timestamp;
} else if (memcmp(&obisCode[OBIS_C], ESPDM_SERIAL_NUMBER, 2) == 0) {
codeType = CodeType::SerialNumber;
} else if (memcmp(&obisCode[OBIS_C], ESPDM_DEVICE_NAME, 2) == 0) {
codeType = CodeType::DeviceName;
} else {
Serial.print("\n\nERROR: Unsupported OBIS code");
}
} else {
Serial.print("\n\nERROR: Unsupported OBIS medium");
}
uint8_t uint8Value;
uint16_t uint16Value;
uint32_t uint32Value;
float floatValue;
active_power_plus = 0;
active_power_minus = 0;
active_energy_plus = 0;
active_energy_minus = 0;
reactive_energy_plus = 0;
reactive_energy_minus = 0;
voltage_l1 = 0;
voltage_l2 = 0;
voltage_l3 = 0;
current_l1 = 0;
current_l2 = 0;
current_l3 = 0;
switch (dataType) {
case DataType::DoubleLongUnsigned: // 0x06
dataLength = 4;
memcpy(&uint32Value, &plaintext[currentPosition], 4); // Copy bytes to integer
uint32Value = swap_uint32(uint32Value); // Swap bytes
floatValue = uint32Value; // Ignore decimal digits for now
if (codeType == CodeType::ActivePowerPlus) {
active_power_plus = floatValue;
Serial.print("\nWirkleistung Bezug +P (W):\t\t"); Serial.print(floatValue);
}
if (codeType == CodeType::ActivePowerMinus) {
active_power_minus = floatValue;
Serial.print("\nWirkleistung Lieferung -P (W):\t\t"); Serial.print(floatValue);
}
if (codeType == CodeType::ActiveEnergyPlus) {
active_energy_plus = floatValue;
Serial.print("\nWirkenergie Bezug +A (Wh):\t\t"); Serial.print(floatValue);
}
if (codeType == CodeType::ActiveEnergyMinus) {
active_energy_minus = floatValue;
Serial.print("\nWirkenergie Lieferung -A (Wh):\t\t"); Serial.print(floatValue);
}
if (codeType == CodeType::ReactiveEnergyPlus) {
reactive_energy_plus = floatValue;
Serial.print("\nBlindleistung Bezug +R (Wh):\t\t"); Serial.print(floatValue);
}
if (codeType == CodeType::ReactiveEnergyMinus) {
reactive_energy_minus = floatValue;
Serial.print("\nBlindleistung Lieferung -R (Wh):\t"); Serial.print(floatValue);
}
break;
case DataType::LongUnsigned: // 0x12
dataLength = 2;
memcpy(&uint16Value, &plaintext[currentPosition], 2); // Copy bytes to integer
uint16Value = swap_uint16(uint16Value); // Swap bytes
if (plaintext[currentPosition + 5] == Accuracy::SingleDigit)
floatValue = uint16Value / 10.0; // Divide by 10 to get decimal places
else if (plaintext[currentPosition + 5] == Accuracy::DoubleDigit)
floatValue = uint16Value / 100.0; // Divide by 100 to get decimal places
else
floatValue = uint16Value; // No decimal places
if (codeType == CodeType::VoltageL1) {
voltage_l1 = floatValue;
Serial.print("\nSpannung L1 (V):\t\t\t"); Serial.print(floatValue);
}
if (codeType == CodeType::VoltageL2) {
voltage_l2 = floatValue;
Serial.print("\nSpannung L2 (V):\t\t\t"); Serial.print(floatValue);
}
if (codeType == CodeType::VoltageL3) {
voltage_l3 = floatValue;
Serial.print("\nSpannung L3 (V):\t\t\t"); Serial.print(floatValue);
}
if (codeType == CodeType::CurrentL1) {
current_l1 = floatValue;
Serial.print("\nStrom L1 (A):\t\t\t\t"); Serial.print(floatValue);
}
if (codeType == CodeType::CurrentL2) {
current_l2 = floatValue;
Serial.print("\nStrom L2 (A):\t\t\t\t"); Serial.print(floatValue);
}
if (codeType == CodeType::CurrentL3) {
current_l3 = floatValue;
Serial.print("\nStrom L3 (A):\t\t\t\t"); Serial.print(floatValue);
}
break;
case DataType::OctetString: // 0x09
dataLength = plaintext[currentPosition];
currentPosition++; // Advance past string length
if (codeType == CodeType::Timestamp) // Handle timestamp generation
{
memcpy(&uint16Value, &plaintext[currentPosition], 2);
year = swap_uint16(uint16Value);
memcpy(&month, &plaintext[currentPosition + 2], 1);
memcpy(&day, &plaintext[currentPosition + 3], 1);
memcpy(&hour, &plaintext[currentPosition + 5], 1);
memcpy(&minute, &plaintext[currentPosition + 6], 1);
memcpy(&second, &plaintext[currentPosition + 7], 1);
//sprintf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02uZ", year, month, day, hour, minute, second);
sprintf(timestamp, "%02u.%02u.%04u %02u:%02u:%02u", day, month, year, hour, minute, second);
Serial.print("\n\nDatum/Zeit:\t\t\t"); Serial.print(timestamp);
}
if (codeType == CodeType::SerialNumber) // Handle SerialNumber generation
{
dataLength = plaintext[currentPosition - 1];
memcpy(&uint8Value, &plaintext[currentPosition - 1], 1); // Copy byte to integer
int zaehlernummerlen = uint8Value;
uint8Value = swap_uint16(uint16Value); // Swap bytes
memcpy(&zaehlernummer, &plaintext[currentPosition], zaehlernummerlen); // Copy byte to integer
Serial.print("\nZaehlernummer:\t\t\t"); Serial.print(zaehlernummer);
}
if (codeType == CodeType::DeviceName) // Handle DeviceName generation
{
dataLength = plaintext[currentPosition - 1];
memcpy(&uint8Value, &plaintext[currentPosition - 1], 1); // Copy byte to integer
int devicenamelen = uint8Value;
uint8Value = swap_uint16(uint16Value); // Swap bytes
memcpy(&devicename, &plaintext[currentPosition], devicenamelen); // Copy byte to integer
Serial.print("\nDevicename:\t\t\t"); Serial.print(devicename);
}
break;
default:
Serial.print("\n\nERROR: Unsupported OBIS data type");
break;
} // ENDE switch (dataType)
currentPosition += dataLength; // Skip data length
currentPosition += 2; // Skip break after data
if (plaintext[currentPosition] == 0x0F) // There is still additional data for this type, skip it
currentPosition += 6; // Skip additional data and additional break; this will jump out of bounds on last frame
} while (currentPosition <= payloadLength); // Loop until arrived at end
} else {
Serial.print("Nachricht 1 ungueltig - warte auf naechsten Block\n");
}
delay(3000);
}