Track receiver duplicate batches in web and OLED
This commit is contained in:
@@ -47,6 +47,9 @@ struct MeterData {
|
|||||||
struct SenderStatus {
|
struct SenderStatus {
|
||||||
MeterData last_data;
|
MeterData last_data;
|
||||||
uint32_t last_update_ts_utc;
|
uint32_t last_update_ts_utc;
|
||||||
|
uint32_t rx_batches_total;
|
||||||
|
uint32_t rx_batches_duplicate;
|
||||||
|
uint32_t rx_last_duplicate_ts_utc;
|
||||||
bool has_data;
|
bool has_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -356,22 +356,29 @@ static void render_receiver_sender(uint8_t index) {
|
|||||||
display.setCursor(0, 32);
|
display.setCursor(0, 32);
|
||||||
display.printf("L2 %dW", static_cast<int>(round_power_w(status.last_data.phase_power_w[1])));
|
display.printf("L2 %dW", static_cast<int>(round_power_w(status.last_data.phase_power_w[1])));
|
||||||
display.setCursor(0, 42);
|
display.setCursor(0, 42);
|
||||||
display.printf("L3 %dW", static_cast<int>(round_power_w(status.last_data.phase_power_w[2])));
|
display.printf("L3 %dW P%dW",
|
||||||
|
static_cast<int>(round_power_w(status.last_data.phase_power_w[2])),
|
||||||
|
static_cast<int>(round_power_w(status.last_data.total_power_w)));
|
||||||
display.setCursor(0, 52);
|
display.setCursor(0, 52);
|
||||||
display.print("P");
|
uint32_t total_batches = status.rx_batches_total;
|
||||||
char p_buf[16];
|
uint32_t duplicate_batches = status.rx_batches_duplicate;
|
||||||
snprintf(p_buf, sizeof(p_buf), "%dW", static_cast<int>(round_power_w(status.last_data.total_power_w)));
|
float duplicate_pct = 0.0f;
|
||||||
int16_t x1 = 0;
|
if (total_batches > 0) {
|
||||||
int16_t y1 = 0;
|
duplicate_pct = (static_cast<float>(duplicate_batches) * 100.0f) / static_cast<float>(total_batches);
|
||||||
uint16_t w = 0;
|
|
||||||
uint16_t h = 0;
|
|
||||||
display.getTextBounds(p_buf, 0, 0, &x1, &y1, &w, &h);
|
|
||||||
int16_t x = static_cast<int16_t>(display.width() - w);
|
|
||||||
if (x < 0) {
|
|
||||||
x = 0;
|
|
||||||
}
|
}
|
||||||
display.setCursor(x, 52);
|
char dup_time[6];
|
||||||
display.print(p_buf);
|
strncpy(dup_time, "--:--", sizeof(dup_time));
|
||||||
|
dup_time[sizeof(dup_time) - 1] = '\0';
|
||||||
|
if (status.rx_last_duplicate_ts_utc > 0 && time_is_synced()) {
|
||||||
|
time_t t = static_cast<time_t>(status.rx_last_duplicate_ts_utc);
|
||||||
|
struct tm timeinfo;
|
||||||
|
localtime_r(&t, &timeinfo);
|
||||||
|
snprintf(dup_time, sizeof(dup_time), "%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
|
||||||
|
}
|
||||||
|
display.printf("Dup %.1f%%(%lu) %s",
|
||||||
|
static_cast<double>(duplicate_pct),
|
||||||
|
static_cast<unsigned long>(duplicate_batches),
|
||||||
|
dup_time);
|
||||||
display.display();
|
display.display();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
19
src/main.cpp
19
src/main.cpp
@@ -274,6 +274,9 @@ static void init_sender_statuses() {
|
|||||||
g_sender_statuses[i] = {};
|
g_sender_statuses[i] = {};
|
||||||
g_sender_statuses[i].has_data = false;
|
g_sender_statuses[i].has_data = false;
|
||||||
g_sender_statuses[i].last_update_ts_utc = 0;
|
g_sender_statuses[i].last_update_ts_utc = 0;
|
||||||
|
g_sender_statuses[i].rx_batches_total = 0;
|
||||||
|
g_sender_statuses[i].rx_batches_duplicate = 0;
|
||||||
|
g_sender_statuses[i].rx_last_duplicate_ts_utc = 0;
|
||||||
g_sender_statuses[i].last_data.short_id = EXPECTED_SENDER_IDS[i];
|
g_sender_statuses[i].last_data.short_id = EXPECTED_SENDER_IDS[i];
|
||||||
snprintf(g_sender_statuses[i].last_data.device_id, sizeof(g_sender_statuses[i].last_data.device_id), "dd3-%04X", EXPECTED_SENDER_IDS[i]);
|
snprintf(g_sender_statuses[i].last_data.device_id, sizeof(g_sender_statuses[i].last_data.device_id), "dd3-%04X", EXPECTED_SENDER_IDS[i]);
|
||||||
g_sender_faults_remote[i] = {};
|
g_sender_faults_remote[i] = {};
|
||||||
@@ -1261,6 +1264,22 @@ static void receiver_loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool duplicate = sender_idx >= 0 && g_last_batch_id_rx[sender_idx] == batch_id;
|
bool duplicate = sender_idx >= 0 && g_last_batch_id_rx[sender_idx] == batch_id;
|
||||||
|
if (sender_idx >= 0) {
|
||||||
|
SenderStatus &status = g_sender_statuses[sender_idx];
|
||||||
|
if (status.rx_batches_total < UINT32_MAX) {
|
||||||
|
status.rx_batches_total++;
|
||||||
|
}
|
||||||
|
if (duplicate) {
|
||||||
|
if (status.rx_batches_duplicate < UINT32_MAX) {
|
||||||
|
status.rx_batches_duplicate++;
|
||||||
|
}
|
||||||
|
uint32_t duplicate_ts = time_get_utc();
|
||||||
|
if (duplicate_ts == 0) {
|
||||||
|
duplicate_ts = batch.t_last;
|
||||||
|
}
|
||||||
|
status.rx_last_duplicate_ts_utc = duplicate_ts;
|
||||||
|
}
|
||||||
|
}
|
||||||
send_batch_ack(batch_id, batch.n);
|
send_batch_ack(batch_id, batch.n);
|
||||||
if (duplicate) {
|
if (duplicate) {
|
||||||
goto receiver_loop_done;
|
goto receiver_loop_done;
|
||||||
|
|||||||
@@ -412,6 +412,17 @@ static String render_sender_block(const SenderStatus &status) {
|
|||||||
String(round_power_w(status.last_data.phase_power_w[2])) + " W<br>";
|
String(round_power_w(status.last_data.phase_power_w[2])) + " W<br>";
|
||||||
s += "Battery: " + String(status.last_data.battery_percent) + "% (" + String(status.last_data.battery_voltage_v, 2) + " V)";
|
s += "Battery: " + String(status.last_data.battery_percent) + "% (" + String(status.last_data.battery_voltage_v, 2) + " V)";
|
||||||
}
|
}
|
||||||
|
uint32_t total_batches = status.rx_batches_total;
|
||||||
|
uint32_t duplicate_batches = status.rx_batches_duplicate;
|
||||||
|
float duplicate_pct = 0.0f;
|
||||||
|
if (total_batches > 0) {
|
||||||
|
duplicate_pct = (static_cast<float>(duplicate_batches) * 100.0f) / static_cast<float>(total_batches);
|
||||||
|
}
|
||||||
|
s += "<br>Dup batches: " + String(duplicate_batches) + "/" + String(total_batches) + " (" + String(duplicate_pct, 1) + "%)";
|
||||||
|
s += " last: " + format_utc_timestamp(status.rx_last_duplicate_ts_utc);
|
||||||
|
if (time_is_synced() && status.rx_last_duplicate_ts_utc > 0) {
|
||||||
|
s += " (" + String(timestamp_age_seconds(status.rx_last_duplicate_ts_utc)) + "s ago)";
|
||||||
|
}
|
||||||
s += "</div>";
|
s += "</div>";
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user