diff --git a/src/main.cpp b/src/main.cpp index 3ad415d..cec2898 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -122,6 +122,8 @@ static uint32_t g_meter_time_prev_seconds = 0; static uint32_t g_meter_time_prev_rx_ms = 0; static bool g_meter_time_jump_pending = false; static bool g_time_acquired = false; +static bool g_sender_faults_reset_after_first_sync = false; +static uint32_t g_sender_faults_reset_hour_utc = UINT32_MAX; static uint32_t g_last_sync_request_ms = 0; static uint32_t g_build_attempts = 0; static uint32_t g_build_valid = 0; @@ -602,6 +604,52 @@ static void note_fault(FaultCounters &counters, FaultType &last_type, uint32_t & last_ts_ms = millis(); } +static void clear_faults(FaultCounters &counters, FaultType &last_type, uint32_t &last_ts_utc, uint32_t &last_ts_ms) { + counters = {}; + last_type = FaultType::None; + last_ts_utc = 0; + last_ts_ms = 0; +} + +static void sender_reset_fault_stats(const char *reason, uint32_t now_utc) { + clear_faults(g_sender_faults, g_sender_last_error, g_sender_last_error_utc, g_sender_last_error_ms); + g_sender_rx_reject_reason = RxRejectReason::None; + display_set_last_error(g_sender_last_error, g_sender_last_error_utc, g_sender_last_error_ms); + if (SERIAL_DEBUG_MODE) { + serial_debug_printf("faults: reset scope=sender reason=%s ts_utc=%lu", + reason ? reason : "unknown", + static_cast(now_utc)); + } +} + +static void sender_reset_fault_stats_on_first_sync(uint32_t synced_utc) { + if (g_sender_faults_reset_after_first_sync || synced_utc < MIN_ACCEPTED_EPOCH_UTC) { + return; + } + sender_reset_fault_stats("first_sync", synced_utc); + g_sender_faults_reset_after_first_sync = true; + g_sender_faults_reset_hour_utc = synced_utc / 3600U; +} + +static void sender_reset_fault_stats_on_hour_boundary() { + if (!g_time_acquired || !g_sender_faults_reset_after_first_sync) { + return; + } + uint32_t now_utc = time_get_utc(); + if (now_utc < MIN_ACCEPTED_EPOCH_UTC) { + return; + } + uint32_t now_hour_utc = now_utc / 3600U; + if (g_sender_faults_reset_hour_utc == UINT32_MAX) { + g_sender_faults_reset_hour_utc = now_hour_utc; + return; + } + if (now_hour_utc > g_sender_faults_reset_hour_utc) { + sender_reset_fault_stats("hourly", now_utc); + g_sender_faults_reset_hour_utc = now_hour_utc; + } +} + static uint32_t age_seconds(uint32_t ts_utc, uint32_t ts_ms) { if (time_is_synced() && ts_utc > 0) { uint32_t now = time_get_utc(); @@ -1241,6 +1289,8 @@ void setup() { g_last_send_ms = millis(); g_last_sync_request_ms = millis() - SYNC_REQUEST_INTERVAL_MS; g_time_acquired = false; + g_sender_faults_reset_after_first_sync = false; + g_sender_faults_reset_hour_utc = UINT32_MAX; update_battery_cache(); } else { power_receiver_init(); @@ -1287,6 +1337,7 @@ static void sender_loop() { meter_reader_pump(now_ms); if (g_time_acquired) { + sender_reset_fault_stats_on_hour_boundary(); while (now_ms - g_last_sample_ms >= METER_SAMPLE_INTERVAL_MS) { g_last_sample_ms += METER_SAMPLE_INTERVAL_MS; MeterData data = {}; @@ -1472,6 +1523,7 @@ static void sender_loop() { if (time_valid == 1 && ack_epoch >= MIN_ACCEPTED_EPOCH_UTC) { time_set_utc(ack_epoch); g_time_acquired = true; + sender_reset_fault_stats_on_first_sync(ack_epoch); set_time = true; } g_last_acked_batch_id = ack_id;