Add IEC62056 parsing, OLED timing, and batch LoRa send

This commit is contained in:
2026-01-28 01:22:13 +01:00
parent 449fff1f06
commit e480677b49
8 changed files with 570 additions and 65 deletions

View File

@@ -59,3 +59,90 @@ bool jsonToMeterData(const String &json, MeterData &data) {
return true;
}
bool meterBatchToJson(const MeterData *samples, size_t count, String &out_json) {
if (!samples || count == 0) {
return false;
}
DynamicJsonDocument doc(8192);
doc["id"] = samples[count - 1].device_id;
doc["bat_v"] = samples[count - 1].battery_voltage_v;
doc["bat_pct"] = samples[count - 1].battery_percent;
JsonArray arr = doc.createNestedArray("s");
for (size_t i = 0; i < count; ++i) {
JsonArray row = arr.createNestedArray();
row.add(samples[i].ts_utc);
row.add(samples[i].energy_total_kwh);
row.add(samples[i].total_power_w);
row.add(samples[i].phase_power_w[0]);
row.add(samples[i].phase_power_w[1]);
row.add(samples[i].phase_power_w[2]);
row.add(samples[i].phase_voltage_v[0]);
row.add(samples[i].phase_voltage_v[1]);
row.add(samples[i].phase_voltage_v[2]);
row.add(samples[i].valid ? 1 : 0);
}
out_json = "";
size_t len = serializeJson(doc, out_json);
return len > 0;
}
bool jsonToMeterBatch(const String &json, MeterData *out_samples, size_t max_count, size_t &out_count) {
out_count = 0;
if (!out_samples || max_count == 0) {
return false;
}
DynamicJsonDocument doc(8192);
DeserializationError err = deserializeJson(doc, json);
if (err) {
return false;
}
JsonArray arr = doc["s"].as<JsonArray>();
if (arr.isNull()) {
return false;
}
const char *id = doc["id"] | "";
float bat_v = doc["bat_v"] | NAN;
uint8_t bat_pct = doc["bat_pct"] | 0;
size_t idx = 0;
for (JsonArray row : arr) {
if (idx >= max_count) {
break;
}
MeterData &data = out_samples[idx];
data = {};
strncpy(data.device_id, id, sizeof(data.device_id));
data.device_id[sizeof(data.device_id) - 1] = '\0';
data.ts_utc = row[0] | 0;
data.energy_total_kwh = row[1] | NAN;
data.total_power_w = row[2] | NAN;
data.phase_power_w[0] = row[3] | NAN;
data.phase_power_w[1] = row[4] | NAN;
data.phase_power_w[2] = row[5] | NAN;
data.phase_voltage_v[0] = row[6] | NAN;
data.phase_voltage_v[1] = row[7] | NAN;
data.phase_voltage_v[2] = row[8] | NAN;
data.valid = (row[9] | 1) != 0;
data.battery_voltage_v = bat_v;
if (doc["bat_pct"].isNull() && !isnan(bat_v)) {
data.battery_percent = battery_percent_from_voltage(bat_v);
} else {
data.battery_percent = bat_pct;
}
if (strlen(data.device_id) >= 8) {
const char *suffix = data.device_id + strlen(data.device_id) - 4;
data.short_id = static_cast<uint16_t>(strtoul(suffix, nullptr, 16));
}
idx++;
}
out_count = idx;
return idx > 0;
}