#include <math.h>
#include <ArduinoJson.h>
const uint8_t packet1[] {0x1B, 0x1B, 0x1B, 0x1B, 0x01, 0x01, 0x01, 0x01, 0x76, 0x05, 0x28, 0x91, 0x2B, 0x03, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x01, 0x01, 0x76, 0x01, 0x01, 0x02, 0x31, 0x0B, 0x0A, 0x01, 0x44, 0x5A, 0x47, 0x00, 0x03, 0xA0, 0x86, 0xBC, 0x72, 0x62, 0x01, 0x65, 0x01, 0x0E, 0x86, 0x07, 0x62, 0x02, 0x63, 0x6A, 0x40, 0x00, 0x76, 0x05, 0x29, 0x91, 0x2B, 0x03, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x07, 0x01, 0x77, 0x01, 0x0B, 0x0A, 0x01, 0x44, 0x5A, 0x47, 0x00, 0x03, 0xA0, 0x86, 0xBC, 0x07, 0x01, 0x00, 0x62, 0x0A, 0xFF, 0xFF, 0x72, 0x62, 0x01, 0x65, 0x01, 0x0E, 0x86, 0x07, 0x75, 0x77, 0x07, 0x01, 0x00, 0x60, 0x32, 0x01, 0x01, 0x01, 0x72, 0x62, 0x01, 0x62, 0x00, 0x62, 0x00, 0x52, 0x00, 0x04, 0x44, 0x5A, 0x47, 0x01, 0x77, 0x07, 0x01, 0x00, 0x60, 0x01, 0x00, 0xFF, 0x01, 0x72, 0x62, 0x01, 0x62, 0x00, 0x62, 0x00, 0x52, 0x00, 0x0B, 0x0A, 0x01, 0x44, 0x5A, 0x47, 0x00, 0x03, 0xA0, 0x86, 0xBC, 0x01, 0x77, 0x07, 0x01, 0x00, 0x01, 0x08, 0x00, 0xFF, 0x64, 0x1C, 0x49, 0x04, 0x72, 0x62, 0x01, 0x62, 0x00, 0x62, 0x1E, 0x52, 0xFF, 0x65, 0x01, 0x2C, 0xF5, 0xF8, 0x01, 0x77, 0x07, 0x01, 0x00, 0x02, 0x08, 0x00, 0xFF, 0x01, 0x72, 0x62, 0x01, 0x62, 0x00, 0x62, 0x1E, 0x52, 0xFF, 0x64, 0x05, 0xC5, 0x51, 0x01, 0x77, 0x07, 0x01, 0x00, 0x10, 0x07, 0x00, 0xFF, 0x01, 0x72, 0x62, 0x01, 0x62, 0x00, 0x62, 0x1B, 0x52, 0xFE, 0x53, 0x8F, 0x7F, 0x01, 0x01, 0x01, 0x63, 0xB7, 0x43, 0x00, 0x76, 0x05, 0x2A, 0x91, 0x2B, 0x03, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x02, 0x01, 0x71, 0x01, 0x63, 0xCD, 0x6E, 0x00, 0x00, 0x00, 0x1B, 0x1B, 0x1B, 0x1B, 0x1A, 0x02, 0xEA, 0xB6};
#define SML_ARRAY 0x00
#define SML_BOOL 0x04
#define SML_INT 0x05
#define SML_UINT 0x06
#define SML_LIST 0x07
#define SML_OpenResponse 0x0101
#define SML_CloseResponse 0x0201
#define SML_GetListResponse 0x0701
#define OBIS_1_8_0 0x010800
#define OBIS_2_8_0 0x020800
#define OBIS_16_7_0 0x100700
#define SML_TYPE_MASK 0x70
#define MAX_DEPTH 15
#define FieldType(x) *x >> 4
#define FieldTypeStr(x) SML_TYPE_STR[x]
#define FieldLength(x) *x & 0x0F
const char* unit_str[] = {
"", // (0) dummy
"a", // (1) a time year
"mo", // (2) mo time month
"wk", // (3) wk time week 7*24*60*60 s
"d", // (4) d time day 24*60*60 s
"h", // (5) h time hour 60*60 s
"min", // (6) min time minute 60 s
"s", // (7) s time (t) second s
"deg", // (8) ° (phase) angle degree rad*180/π
"degC", // (9) °C temperature (T) degree-celsius K-273.15
"", // (10) currency (local) currency
"m", // (11) m length (l) metre m
"m/s", // (12) m/s speed (v) metre per second m/s
"m3", // (13) m 3 volume (V) rV , meter constant or pulse value (volume) cubic metre m 3
"m3", // (14) m 3 corrected volume cubic metre m 3
"m3/h", // (15) m 3/h volume flux cubic metre per hour m 3/(60*60s)
"m3/h", // (16) m 3/h corrected volume flux cubic metre per hour m 3/(60*60s)
"m3/d", // (17) m 3/d volume flux m 3/(24*60*60s)
"m3/d", // (18) m 3/d corrected volume flux m 3/(24*60*60s)
"l", // (19) l volume litre 10- 3 m 3
"kg", // (20) kg mass (m) kilogram
"N", // (21) N force (F) newton
"Nm", // (22) Nm energy newton meter J = Nm = Ws
"Pa", // (23) Pa pressure (p) pascal N/m2
"bar", // (24) bar pressure (p) bar 105 N/m2
"J", // (25) J energy joule J = Nm = Ws
"J/h", // (26) J/h thermal power joule per hour J/(60*60s)
"W", // (27) W active power (P) watt W = J/s
"VA", // (28) VA apparent power (S) volt-ampere
"var", // (29) var reactive power (Q) var
"Wh", // (30) Wh active energy rW , active energy meter constant or pulse value watt-hour W*(60*60s)
"VAh", // (31) VAh apparent energy rS , apparent energy meter constant or pulse value volt-ampere-hour VA*(60*60s)
"varh", // (32) varh reactive energy rB , reactive energy meter constant or pulse value var-hour var*(60*60s)
"A", // (33) A current (I) ampere A
"C", // (34) C electrical charge (Q) coulomb C = As
"V", // (35) V voltage (U) volt V
"V/m", // (36) V/m electric field strength (E) volt per metre V/m
"F", // (37) F capacitance (C) farad C/V = As/V
"Ohm", // (38) Ω resistance (R) ohm Ω = V/A
"Ohmm 2/m", // (39) Ωm 2/m resistivity (ρ) Ωm
"Wb", // (40) Wb magnetic flux (Φ) weber Wb = Vs
"T", // (41) T magnetic flux density (B) tesla Wb/m2
"A/m", // (42) A/m magnetic field strength (H) ampere per metre A/m
"H", // (43) H inductance (L) henry H = W b/A
"Hz", // (44) Hz frequency (f, ω) hertz 1/s
"1/(W h)", // (45) 1/(W h) RW , active energy meter constant or pulse value
"1/(varh)", // (46) 1/(varh) RB , reactive energy meter constant or pulse value
"1/(VAh)", // (47) 1/(VAh) RS , apparent energy meter constant or pulse value
"V2h", // (48) V2h volt-squared hour, rU 2h , volt-squared hour meter constant or pulse value volt-squared-hours V2(60*60s)
"A2h", // (49) A2h ampere-squared hour, rI2 h , ampere-squared hour meter constant or pulse value ampere-squared-hours A2(60*60s)
"kg/s", // (50) kg/s mass flux kilogram per second kg/s
"S", // (51) S, mho conductance siemens 1/Ω
"K", // (52) K temperature (T) kelvin
"1/(V2h)", // (53) 1/(V2h) RU2 h , volt-squared hour meter constant or pulse value
"1/(A2h)", // (54) 1/(A2h) RI2h , ampere-squared hour meter constant or pulse value
"1/m3", // (55) 1/m3 RV , meter constant or pulse value (volume)
"%", // (56) percentage %
"Ah", // (57) Ah ampere-hours Ampere-hour ...
"", // (58) dummy
"", // (59) dummy
"Wh/m3", // (60) Wh/m3 energy per volume 3,6*103 J/m3
"J/m3", // (61) J/m3 calorific value, wobbe
"Mol", // (62) Mol % molar fraction of gas composition mole percent (Basic gas composition unit)
"g/m3", // (63) g/m3 mass density, quantity of material (Gas analysis, accompanying elements)
"Pas", // (64) Pas dynamic viscosity pascal second (Characteristic of gas stream)
"J/kg", // (65) J/kg specific energy NOTE The amount of energy per unit of mass of a substance Joule / kilogram m 2 . kg . s -2 / kg = m2 . s –2 ....
"", // (66) dummy
"", // (67) dummy
"", // (68) dummy
"", // (69) dummy
"dBm", // (70) dBm signal strength, dB milliwatt (e.g. of GSM radio systems)
"dbmV", // (71) dbμV signal strength, dB microvolt
"dB", // (72) dB logarithmic unit that expresses the ratio between two values of a physical quantity ...
};
struct ListInfo {
uint8_t maxItems = 0;
uint8_t currentItem = 0;
};
uint32_t obis_short(const uint8_t* data) {
data += 2;
uint32_t result = 0;
for (size_t i = 0; i < 3; i++) {
result = (result << 8) + *(data++);
}
return result;
}
uint64_t parseUint(const uint8_t* data, size_t len) {
uint64_t result = 0;
for (size_t i = 0; i < len; i++) result = (result << 8) + *(data++);
return result;
}
int64_t parseInt(const uint8_t* data, size_t len) {
int64_t result = *(data) & 0x80 ? -1 : 0;
for (size_t i = 0; i < len; i++) result = (result << 8) + *(data++);
return result;
}
String parseObis(const uint8_t* data) {
char buf[255];
sprintf(buf, "%d.%d.%d",
data[2],
data[3],
data[4]
);
return String(buf);
}
void parseList(const uint8_t* data, size_t len) {
ListInfo li[MAX_DEPTH];
uint8_t current_level = 0;
const uint8_t* ptr = data;
uint64_t smlMessage = 0;
uint64_t unit = 0;
int64_t scaler = 0;
double value = 0;
String obis_code = "";
StaticJsonDocument<1024> doc;
while (ptr < data + len) {
uint8_t field_type = FieldType(ptr);
uint8_t field_length = FieldLength(ptr);
ptr++;
if (current_level == 0 && field_type != SML_LIST) {
continue;
}
li[current_level].currentItem++;
if (field_type == SML_LIST) {
current_level++;
li[current_level].maxItems = field_length;
continue;
} else {
if (current_level == 2 && li[current_level].currentItem == 1) {
smlMessage = parseUint(ptr, field_length - 1);
}
if (smlMessage = SML_GetListResponse && current_level == 5) {
uint8_t& currentItem = li[current_level].currentItem;
switch (currentItem) {
case 1:
obis_code = parseObis(ptr);
break;
case 4:
unit = parseUint(ptr, field_length - 1);
break;
case 5:
scaler = parseInt(ptr, field_length - 1);
break;
case 6:
if (field_type == SML_INT || field_type == SML_UINT) {
if (field_type == SML_UINT) value = parseUint(ptr, field_length - 1 ) * pow(10, scaler);
if (field_type == SML_INT) value = parseInt(ptr, field_length - 1 ) * pow(10, scaler);
doc[obis_code]["v"] = value;
doc[obis_code]["u"] = unit_str[unit];
unit = 0;
scaler = 0;
obis_code = "";
}
break;
default: break;
}
}
ptr += field_length ? field_length - 1 : 0;
}
while (current_level > 0 && li[current_level].currentItem == li[current_level].maxItems) {
li[current_level].maxItems = 0;
li[current_level].currentItem = 0;
current_level--;
}
}
String result = "";
serializeJsonPretty(doc, result);
Serial.println(result);
}
void setup() {
Serial.begin(115200);
parseList(packet1, sizeof(packet1));
}
void loop() {
delay(10); // this speeds up the simulation
}