adjust batch ack timing and rename e_wh field
This commit is contained in:
@@ -207,7 +207,7 @@ MeterBatch JSON (compressed over LoRa) uses per-field arrays with integer units
|
||||
"t_last": 1738288030,
|
||||
"dt_s": 1,
|
||||
"n": 3,
|
||||
"energy_wh": [123456700, 123456701, 123456701],
|
||||
"e_wh": [123456700, 123456701, 123456701],
|
||||
"p_w": [930, 940, 950],
|
||||
"p1_w": [480, 490, 500],
|
||||
"p2_w": [450, 450, 450],
|
||||
|
||||
@@ -205,7 +205,7 @@ bool meterBatchToJson(const MeterData *samples, size_t count, uint16_t batch_id,
|
||||
doc["bat_v"] = serialized(bat_buf);
|
||||
}
|
||||
|
||||
JsonArray energy = doc.createNestedArray("energy_wh");
|
||||
JsonArray energy = doc.createNestedArray("e_wh");
|
||||
JsonArray p_w = doc.createNestedArray("p_w");
|
||||
JsonArray p1_w = doc.createNestedArray("p1_w");
|
||||
JsonArray p2_w = doc.createNestedArray("p2_w");
|
||||
@@ -258,7 +258,7 @@ bool jsonToMeterBatch(const String &json, MeterData *out_samples, size_t max_cou
|
||||
uint32_t t_first = doc["t_first"] | t0;
|
||||
uint32_t t_last = doc["t_last"] | t_first;
|
||||
uint32_t dt_s = doc["dt_s"] | 1;
|
||||
JsonArray energy = doc["energy_wh"].as<JsonArray>();
|
||||
JsonArray energy = doc["e_wh"].as<JsonArray>();
|
||||
JsonArray p_w = doc["p_w"].as<JsonArray>();
|
||||
JsonArray p1_w = doc["p1_w"].as<JsonArray>();
|
||||
JsonArray p2_w = doc["p2_w"].as<JsonArray>();
|
||||
|
||||
38
src/main.cpp
38
src/main.cpp
@@ -81,6 +81,7 @@ static uint16_t g_last_sent_batch_id = 0;
|
||||
static uint16_t g_last_acked_batch_id = 0;
|
||||
static uint8_t g_batch_retry_count = 0;
|
||||
static bool g_batch_ack_pending = false;
|
||||
static uint32_t g_batch_ack_timeout_ms = BATCH_ACK_TIMEOUT_MS;
|
||||
static MeterData g_inflight_samples[METER_BATCH_MAX_SAMPLES];
|
||||
static uint8_t g_inflight_count = 0;
|
||||
static uint16_t g_inflight_batch_id = 0;
|
||||
@@ -294,6 +295,17 @@ static uint32_t compute_batch_rx_timeout_ms(uint16_t total_len, uint8_t chunk_co
|
||||
return timeout_ms < 10000 ? 10000 : timeout_ms;
|
||||
}
|
||||
|
||||
static uint32_t compute_batch_ack_timeout_ms(size_t payload_len) {
|
||||
if (payload_len == 0) {
|
||||
return 10000;
|
||||
}
|
||||
uint8_t chunk_count = static_cast<uint8_t>((payload_len + BATCH_CHUNK_PAYLOAD - 1) / BATCH_CHUNK_PAYLOAD);
|
||||
size_t packet_len = 5 + BATCH_HEADER_SIZE + (payload_len > BATCH_CHUNK_PAYLOAD ? BATCH_CHUNK_PAYLOAD : payload_len) + 2;
|
||||
uint32_t per_chunk_toa_ms = lora_airtime_ms(packet_len);
|
||||
uint32_t timeout_ms = static_cast<uint32_t>(chunk_count) * per_chunk_toa_ms + BATCH_RX_MARGIN_MS;
|
||||
return timeout_ms < 10000 ? 10000 : timeout_ms;
|
||||
}
|
||||
|
||||
static bool inject_batch_meta(String &json, int16_t rssi_dbm, float snr_db, uint32_t rx_ts_utc) {
|
||||
DynamicJsonDocument doc(8192);
|
||||
DeserializationError err = deserializeJson(doc, json);
|
||||
@@ -423,6 +435,7 @@ static bool send_inflight_batch(uint32_t ts_for_display) {
|
||||
if (SERIAL_DEBUG_MODE && compress_ms > 200) {
|
||||
serial_debug_printf("tx: compress took %lums", static_cast<unsigned long>(compress_ms));
|
||||
}
|
||||
g_batch_ack_timeout_ms = compute_batch_ack_timeout_ms(compressed_len);
|
||||
|
||||
uint32_t send_start = millis();
|
||||
bool ok = send_batch_payload(compressed, compressed_len, ts_for_display, g_inflight_batch_id);
|
||||
@@ -668,6 +681,29 @@ static void sender_loop() {
|
||||
send_meter_batch(last_sample_ts());
|
||||
}
|
||||
|
||||
if (g_batch_ack_pending) {
|
||||
uint32_t end_ms = millis() + 400;
|
||||
while (millis() < end_ms) {
|
||||
LoraPacket ack_pkt = {};
|
||||
if (!lora_receive(ack_pkt, 0) || ack_pkt.protocol_version != PROTOCOL_VERSION) {
|
||||
delay(5);
|
||||
continue;
|
||||
}
|
||||
if (ack_pkt.payload_type == PayloadType::Ack && ack_pkt.payload_len >= 6 && ack_pkt.role == DeviceRole::Receiver) {
|
||||
uint16_t ack_id = read_u16_le(ack_pkt.payload);
|
||||
uint16_t ack_sender = read_u16_le(&ack_pkt.payload[2]);
|
||||
uint16_t ack_receiver = read_u16_le(&ack_pkt.payload[4]);
|
||||
if (ack_sender == g_short_id && ack_receiver == ack_pkt.device_id_short &&
|
||||
g_batch_ack_pending && ack_id == g_last_sent_batch_id) {
|
||||
g_last_acked_batch_id = ack_id;
|
||||
serial_debug_printf("ack: ok batch_id=%u", ack_id);
|
||||
finish_inflight_batch();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LoraPacket rx = {};
|
||||
if (lora_receive(rx, 0) && rx.protocol_version == PROTOCOL_VERSION) {
|
||||
if (rx.payload_type == PayloadType::TimeSync) {
|
||||
@@ -685,7 +721,7 @@ static void sender_loop() {
|
||||
}
|
||||
}
|
||||
|
||||
if (g_batch_ack_pending && (now_ms - g_last_batch_send_ms >= BATCH_ACK_TIMEOUT_MS)) {
|
||||
if (g_batch_ack_pending && (now_ms - g_last_batch_send_ms >= g_batch_ack_timeout_ms)) {
|
||||
if (g_batch_retry_count < BATCH_MAX_RETRIES) {
|
||||
g_batch_retry_count++;
|
||||
serial_debug_printf("ack: timeout batch_id=%u retry=%u", g_inflight_batch_id, g_batch_retry_count);
|
||||
|
||||
Reference in New Issue
Block a user