Add meter Sekundenindex anchoring for epoch timestamps

Parse 0-0:96.8.0*255 meter seconds, derive sample epoch from anchored offset, and detect meter-time jumps via monotonic/delta checks.
This commit is contained in:
2026-02-13 23:31:46 +01:00
parent c58e1627f4
commit 5e27e2e7e8
3 changed files with 153 additions and 6 deletions

View File

@@ -100,6 +100,52 @@ static bool parse_obis_ascii_unit_scale(const char *line, const char *obis, floa
return false;
}
static int8_t hex_nibble(char c) {
if (c >= '0' && c <= '9') {
return static_cast<int8_t>(c - '0');
}
if (c >= 'A' && c <= 'F') {
return static_cast<int8_t>(10 + (c - 'A'));
}
if (c >= 'a' && c <= 'f') {
return static_cast<int8_t>(10 + (c - 'a'));
}
return -1;
}
static bool parse_obis_hex_u32(const char *line, const char *obis, uint32_t &out_value) {
const char *p = strstr(line, obis);
if (!p) {
return false;
}
const char *lparen = strchr(p, '(');
if (!lparen) {
return false;
}
const char *cur = lparen + 1;
uint32_t value = 0;
size_t n = 0;
while (*cur && *cur != ')' && *cur != '*') {
int8_t nib = hex_nibble(*cur++);
if (nib < 0) {
if (n == 0) {
continue;
}
break;
}
if (n >= 8) {
return false;
}
value = (value << 4) | static_cast<uint32_t>(nib);
n++;
}
if (n == 0) {
return false;
}
out_value = value;
return true;
}
static void meter_debug_log() {
if (!SERIAL_DEBUG_MODE) {
return;
@@ -242,6 +288,11 @@ bool meter_parse_frame(const char *frame, size_t len, MeterData &data) {
p3_ok = true;
got_any = true;
}
uint32_t meter_seconds = 0;
if (parse_obis_hex_u32(line, "0-0:96.8.0*255", meter_seconds)) {
data.meter_seconds = meter_seconds;
data.meter_seconds_valid = true;
}
line_len = 0;
continue;
@@ -261,6 +312,8 @@ bool meter_parse_frame(const char *frame, size_t len, MeterData &data) {
}
bool meter_read(MeterData &data) {
data.meter_seconds = 0;
data.meter_seconds_valid = false;
data.energy_total_kwh = NAN;
data.total_power_w = NAN;
data.phase_power_w[0] = NAN;