Update batch schema and add ACK handling

This commit is contained in:
2026-01-31 01:53:02 +01:00
parent 8ba7675a1c
commit 8fba67fcf3
9 changed files with 305 additions and 321 deletions

View File

@@ -5,167 +5,11 @@
#include <string.h>
static constexpr uint32_t METER_READ_TIMEOUT_MS = 2000;
static constexpr size_t SML_BUFFER_SIZE = 2048;
static const uint8_t OBIS_ENERGY_TOTAL[6] = {0x01, 0x00, 0x01, 0x08, 0x00, 0xFF};
static const uint8_t OBIS_TOTAL_POWER[6] = {0x01, 0x00, 0x10, 0x07, 0x00, 0xFF};
static const uint8_t OBIS_P1[6] = {0x01, 0x00, 0x24, 0x07, 0x00, 0xFF};
static const uint8_t OBIS_P2[6] = {0x01, 0x00, 0x38, 0x07, 0x00, 0xFF};
static const uint8_t OBIS_P3[6] = {0x01, 0x00, 0x4C, 0x07, 0x00, 0xFF};
static const uint8_t OBIS_V1[6] = {0x01, 0x00, 0x20, 0x07, 0x00, 0xFF};
static const uint8_t OBIS_V2[6] = {0x01, 0x00, 0x34, 0x07, 0x00, 0xFF};
static const uint8_t OBIS_V3[6] = {0x01, 0x00, 0x48, 0x07, 0x00, 0xFF};
static bool find_obis_value(const uint8_t *buf, size_t len, const uint8_t *obis, float &out_value) {
for (size_t i = 0; i + 6 < len; ++i) {
if (memcmp(&buf[i], obis, 6) == 0) {
int8_t scaler = 0;
bool scaler_found = false;
bool value_found = false;
int64_t value = 0;
size_t cursor = i + 6;
size_t limit = (i + 6 + 120 < len) ? i + 6 + 120 : len;
while (cursor < limit) {
uint8_t tl = buf[cursor++];
if (tl == 0x00) {
continue;
}
uint8_t type = (tl >> 4) & 0x0F;
uint8_t tlen = tl & 0x0F;
if (tlen == 0 || cursor + tlen > len) {
continue;
}
if (type == 0x05 || type == 0x06) {
int64_t val = 0;
for (uint8_t b = 0; b < tlen; ++b) {
val = (val << 8) | buf[cursor + b];
}
if (type == 0x05) {
int64_t sign_bit = 1LL << ((tlen * 8) - 1);
if (val & sign_bit) {
int64_t mask = (1LL << (tlen * 8)) - 1;
val = -((~val + 1) & mask);
}
}
if (!scaler_found && tlen <= 2 && val >= -6 && val <= 6) {
scaler = static_cast<int8_t>(val);
scaler_found = true;
} else if (!value_found) {
value = val;
value_found = true;
}
}
cursor += tlen;
if (value_found && scaler_found) {
break;
}
}
if (value_found) {
out_value = static_cast<float>(value) * powf(10.0f, scaler);
return true;
}
}
}
return false;
}
void meter_init() {
Serial2.begin(9600, SERIAL_7E1, PIN_METER_RX, -1);
}
static bool meter_read_sml(MeterData &data) {
uint8_t buffer[SML_BUFFER_SIZE];
size_t len = 0;
bool started = false;
uint32_t start = millis();
const uint8_t start_seq[] = {0x1B, 0x1B, 0x1B, 0x1B, 0x01, 0x01, 0x01, 0x01};
const uint8_t end_seq[] = {0x1B, 0x1B, 0x1B, 0x1B, 0x1A};
while (millis() - start < METER_READ_TIMEOUT_MS) {
while (Serial2.available()) {
uint8_t b = Serial2.read();
if (!started) {
buffer[len++] = b;
if (len >= sizeof(start_seq)) {
if (memcmp(&buffer[len - sizeof(start_seq)], start_seq, sizeof(start_seq)) == 0) {
started = true;
len = 0;
}
}
if (len >= sizeof(buffer)) {
len = 0;
}
} else {
if (len < sizeof(buffer)) {
buffer[len++] = b;
if (len >= sizeof(end_seq)) {
if (memcmp(&buffer[len - sizeof(end_seq)], end_seq, sizeof(end_seq)) == 0) {
start = millis();
goto parse_frame;
}
}
}
}
}
delay(5);
}
parse_frame:
if (!started || len == 0) {
return false;
}
data.energy_total_kwh = NAN;
data.total_power_w = NAN;
data.phase_power_w[0] = NAN;
data.phase_power_w[1] = NAN;
data.phase_power_w[2] = NAN;
data.phase_voltage_v[0] = NAN;
data.phase_voltage_v[1] = NAN;
data.phase_voltage_v[2] = NAN;
bool ok = true;
float value = 0.0f;
if (find_obis_value(buffer, len, OBIS_ENERGY_TOTAL, value)) {
data.energy_total_kwh = value;
} else {
ok = false;
}
if (find_obis_value(buffer, len, OBIS_TOTAL_POWER, value)) {
data.total_power_w = value;
} else {
ok = false;
}
if (find_obis_value(buffer, len, OBIS_P1, value)) {
data.phase_power_w[0] = value;
}
if (find_obis_value(buffer, len, OBIS_P2, value)) {
data.phase_power_w[1] = value;
}
if (find_obis_value(buffer, len, OBIS_P3, value)) {
data.phase_power_w[2] = value;
}
if (find_obis_value(buffer, len, OBIS_V1, value)) {
data.phase_voltage_v[0] = value;
}
if (find_obis_value(buffer, len, OBIS_V2, value)) {
data.phase_voltage_v[1] = value;
}
if (find_obis_value(buffer, len, OBIS_V3, value)) {
data.phase_voltage_v[2] = value;
}
data.valid = ok;
return ok;
}
static bool parse_obis_ascii_value(const char *line, const char *obis, float &out_value) {
const char *p = strstr(line, obis);
if (!p) {
@@ -243,10 +87,6 @@ static bool meter_read_ascii(MeterData &data) {
bool p1_ok = false;
bool p2_ok = false;
bool p3_ok = false;
bool v1_ok = false;
bool v2_ok = false;
bool v3_ok = false;
char line[128];
size_t line_len = 0;
@@ -298,21 +138,6 @@ static bool meter_read_ascii(MeterData &data) {
p3_ok = true;
got_any = true;
}
if (parse_obis_ascii_value(line, "1-0:32.7.0", value)) {
data.phase_voltage_v[0] = value;
v1_ok = true;
got_any = true;
}
if (parse_obis_ascii_value(line, "1-0:52.7.0", value)) {
data.phase_voltage_v[1] = value;
v2_ok = true;
got_any = true;
}
if (parse_obis_ascii_value(line, "1-0:72.7.0", value)) {
data.phase_voltage_v[2] = value;
v3_ok = true;
got_any = true;
}
line_len = 0;
continue;
@@ -324,7 +149,7 @@ static bool meter_read_ascii(MeterData &data) {
delay(5);
}
data.valid = energy_ok || total_p_ok || p1_ok || p2_ok || p3_ok || v1_ok || v2_ok || v3_ok;
data.valid = energy_ok || total_p_ok || p1_ok || p2_ok || p3_ok;
return data.valid;
}
@@ -334,13 +159,7 @@ bool meter_read(MeterData &data) {
data.phase_power_w[0] = NAN;
data.phase_power_w[1] = NAN;
data.phase_power_w[2] = NAN;
data.phase_voltage_v[0] = NAN;
data.phase_voltage_v[1] = NAN;
data.phase_voltage_v[2] = NAN;
data.valid = false;
if (meter_read_ascii(data)) {
return true;
}
return meter_read_sml(data);
return meter_read_ascii(data);
}