Refactor meter parser to single-pass OBIS dispatch
This commit is contained in:
@@ -33,12 +33,47 @@ void meter_init() {
|
|||||||
Serial2.begin(9600, SERIAL_7E1, PIN_METER_RX, -1);
|
Serial2.begin(9600, SERIAL_7E1, PIN_METER_RX, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool parse_obis_ascii_value(const char *line, const char *obis, float &out_value) {
|
enum class ObisField : uint8_t {
|
||||||
const char *p = strstr(line, obis);
|
None = 0,
|
||||||
if (!p) {
|
Energy = 1,
|
||||||
return false;
|
TotalPower = 2,
|
||||||
|
Phase1 = 3,
|
||||||
|
Phase2 = 4,
|
||||||
|
Phase3 = 5,
|
||||||
|
MeterSeconds = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
static ObisField detect_obis_field(const char *line) {
|
||||||
|
if (!line) {
|
||||||
|
return ObisField::None;
|
||||||
}
|
}
|
||||||
const char *lparen = strchr(p, '(');
|
const char *p = line;
|
||||||
|
while (*p == ' ' || *p == '\t') {
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
if (strncmp(p, "1-0:1.8.0", 9) == 0) {
|
||||||
|
return ObisField::Energy;
|
||||||
|
}
|
||||||
|
if (strncmp(p, "1-0:16.7.0", 10) == 0) {
|
||||||
|
return ObisField::TotalPower;
|
||||||
|
}
|
||||||
|
if (strncmp(p, "1-0:36.7.0", 10) == 0) {
|
||||||
|
return ObisField::Phase1;
|
||||||
|
}
|
||||||
|
if (strncmp(p, "1-0:56.7.0", 10) == 0) {
|
||||||
|
return ObisField::Phase2;
|
||||||
|
}
|
||||||
|
if (strncmp(p, "1-0:76.7.0", 10) == 0) {
|
||||||
|
return ObisField::Phase3;
|
||||||
|
}
|
||||||
|
if (strncmp(p, "0-0:96.8.0*255", 14) == 0) {
|
||||||
|
return ObisField::MeterSeconds;
|
||||||
|
}
|
||||||
|
return ObisField::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_obis_ascii_payload_value(const char *line, float &out_value) {
|
||||||
|
const char *lparen = strchr(line, '(');
|
||||||
if (!lparen) {
|
if (!lparen) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -68,12 +103,12 @@ static bool parse_obis_ascii_value(const char *line, const char *obis, float &ou
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool parse_obis_ascii_unit_scale(const char *line, const char *obis, float &value) {
|
static bool parse_obis_ascii_unit_scale(const char *line, float &value) {
|
||||||
const char *p = strstr(line, obis);
|
const char *lparen = strchr(line, '(');
|
||||||
if (!p) {
|
if (!lparen) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const char *asterisk = strchr(p, '*');
|
const char *asterisk = strchr(lparen, '*');
|
||||||
if (!asterisk) {
|
if (!asterisk) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -113,12 +148,8 @@ static int8_t hex_nibble(char c) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool parse_obis_hex_u32(const char *line, const char *obis, uint32_t &out_value) {
|
static bool parse_obis_hex_payload_u32(const char *line, uint32_t &out_value) {
|
||||||
const char *p = strstr(line, obis);
|
const char *lparen = strchr(line, '(');
|
||||||
if (!p) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const char *lparen = strchr(p, '(');
|
|
||||||
if (!lparen) {
|
if (!lparen) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -261,37 +292,54 @@ bool meter_parse_frame(const char *frame, size_t len, MeterData &data) {
|
|||||||
return data.valid;
|
return data.valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObisField field = detect_obis_field(line);
|
||||||
float value = NAN;
|
float value = NAN;
|
||||||
if (parse_obis_ascii_value(line, "1-0:1.8.0", value)) {
|
|
||||||
parse_obis_ascii_unit_scale(line, "1-0:1.8.0", value);
|
|
||||||
data.energy_total_kwh = value;
|
|
||||||
energy_ok = true;
|
|
||||||
got_any = true;
|
|
||||||
}
|
|
||||||
if (parse_obis_ascii_value(line, "1-0:16.7.0", value)) {
|
|
||||||
data.total_power_w = value;
|
|
||||||
total_p_ok = true;
|
|
||||||
got_any = true;
|
|
||||||
}
|
|
||||||
if (parse_obis_ascii_value(line, "1-0:36.7.0", value)) {
|
|
||||||
data.phase_power_w[0] = value;
|
|
||||||
p1_ok = true;
|
|
||||||
got_any = true;
|
|
||||||
}
|
|
||||||
if (parse_obis_ascii_value(line, "1-0:56.7.0", value)) {
|
|
||||||
data.phase_power_w[1] = value;
|
|
||||||
p2_ok = true;
|
|
||||||
got_any = true;
|
|
||||||
}
|
|
||||||
if (parse_obis_ascii_value(line, "1-0:76.7.0", value)) {
|
|
||||||
data.phase_power_w[2] = value;
|
|
||||||
p3_ok = true;
|
|
||||||
got_any = true;
|
|
||||||
}
|
|
||||||
uint32_t meter_seconds = 0;
|
uint32_t meter_seconds = 0;
|
||||||
if (parse_obis_hex_u32(line, "0-0:96.8.0*255", meter_seconds)) {
|
switch (field) {
|
||||||
data.meter_seconds = meter_seconds;
|
case ObisField::Energy:
|
||||||
data.meter_seconds_valid = true;
|
if (parse_obis_ascii_payload_value(line, value)) {
|
||||||
|
parse_obis_ascii_unit_scale(line, value);
|
||||||
|
data.energy_total_kwh = value;
|
||||||
|
energy_ok = true;
|
||||||
|
got_any = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ObisField::TotalPower:
|
||||||
|
if (parse_obis_ascii_payload_value(line, value)) {
|
||||||
|
data.total_power_w = value;
|
||||||
|
total_p_ok = true;
|
||||||
|
got_any = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ObisField::Phase1:
|
||||||
|
if (parse_obis_ascii_payload_value(line, value)) {
|
||||||
|
data.phase_power_w[0] = value;
|
||||||
|
p1_ok = true;
|
||||||
|
got_any = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ObisField::Phase2:
|
||||||
|
if (parse_obis_ascii_payload_value(line, value)) {
|
||||||
|
data.phase_power_w[1] = value;
|
||||||
|
p2_ok = true;
|
||||||
|
got_any = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ObisField::Phase3:
|
||||||
|
if (parse_obis_ascii_payload_value(line, value)) {
|
||||||
|
data.phase_power_w[2] = value;
|
||||||
|
p3_ok = true;
|
||||||
|
got_any = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ObisField::MeterSeconds:
|
||||||
|
if (parse_obis_hex_payload_u32(line, meter_seconds)) {
|
||||||
|
data.meter_seconds = meter_seconds;
|
||||||
|
data.meter_seconds_valid = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
line_len = 0;
|
line_len = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user