Add WiFi reconnection retry logic to recover from unreliable WiFi
- Implement periodic WiFi reconnection attempts when stuck in AP mode - Add WIFI_RECONNECT_INTERVAL_MS config (default 60s) for configurable retry frequency - Prevent data loss by automatically attempting to switch back to STA mode - Maintain AP mode for manual configuration if reconnection fails - Track WiFi config and last reconnection attempt time in shared state - Add wifi_try_reconnect_sta() and wifi_restore_ap_mode() helper functions - Log reconnection attempts and results for debugging
This commit is contained in:
@@ -63,6 +63,7 @@ constexpr uint8_t METER_BATCH_MAX_SAMPLES = 30;
|
|||||||
constexpr uint8_t BATCH_QUEUE_DEPTH = 10;
|
constexpr uint8_t BATCH_QUEUE_DEPTH = 10;
|
||||||
constexpr BatchRetryPolicy BATCH_RETRY_POLICY = BatchRetryPolicy::Keep;
|
constexpr BatchRetryPolicy BATCH_RETRY_POLICY = BatchRetryPolicy::Keep;
|
||||||
constexpr uint32_t WATCHDOG_TIMEOUT_SEC = 120;
|
constexpr uint32_t WATCHDOG_TIMEOUT_SEC = 120;
|
||||||
|
constexpr uint32_t WIFI_RECONNECT_INTERVAL_MS = 60000; // WiFi reconnection retry interval (1 minute)
|
||||||
constexpr bool ENABLE_HA_DISCOVERY = true;
|
constexpr bool ENABLE_HA_DISCOVERY = true;
|
||||||
#ifndef SERIAL_DEBUG_MODE_FLAG
|
#ifndef SERIAL_DEBUG_MODE_FLAG
|
||||||
#define SERIAL_DEBUG_MODE_FLAG 0
|
#define SERIAL_DEBUG_MODE_FLAG 0
|
||||||
|
|||||||
@@ -25,3 +25,5 @@ bool wifi_connect_sta(const WifiMqttConfig &config, uint32_t timeout_ms = 10000)
|
|||||||
void wifi_start_ap(const char *ap_ssid, const char *ap_pass);
|
void wifi_start_ap(const char *ap_ssid, const char *ap_pass);
|
||||||
bool wifi_is_connected();
|
bool wifi_is_connected();
|
||||||
String wifi_get_ssid();
|
String wifi_get_ssid();
|
||||||
|
bool wifi_try_reconnect_sta(const WifiMqttConfig &config, uint32_t timeout_ms = 5000);
|
||||||
|
void wifi_restore_ap_mode(const char *ap_ssid, const char *ap_pass);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "data_model.h"
|
#include "data_model.h"
|
||||||
|
#include "wifi_manager.h"
|
||||||
|
|
||||||
struct ReceiverSharedState {
|
struct ReceiverSharedState {
|
||||||
SenderStatus sender_statuses[NUM_SENDERS];
|
SenderStatus sender_statuses[NUM_SENDERS];
|
||||||
@@ -24,5 +25,11 @@ struct ReceiverSharedState {
|
|||||||
uint32_t receiver_last_error_ms;
|
uint32_t receiver_last_error_ms;
|
||||||
bool receiver_discovery_sent;
|
bool receiver_discovery_sent;
|
||||||
bool ap_mode;
|
bool ap_mode;
|
||||||
|
|
||||||
|
// WiFi configuration and reconnection tracking
|
||||||
|
WifiMqttConfig wifi_config;
|
||||||
|
uint32_t last_wifi_reconnect_attempt_ms;
|
||||||
|
char ap_ssid[32]; // AP SSID for restoring AP mode if reconnection fails
|
||||||
|
char ap_password[32]; // AP password for restoring AP mode
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
12
src/main.cpp
12
src/main.cpp
@@ -112,6 +112,11 @@ void setup() {
|
|||||||
display_set_sender_statuses(g_receiver_shared.sender_statuses, NUM_SENDERS);
|
display_set_sender_statuses(g_receiver_shared.sender_statuses, NUM_SENDERS);
|
||||||
|
|
||||||
bool has_cfg = wifi_load_config(g_cfg);
|
bool has_cfg = wifi_load_config(g_cfg);
|
||||||
|
|
||||||
|
// Store WiFi config in shared state for later reconnection attempts
|
||||||
|
g_receiver_shared.wifi_config = g_cfg;
|
||||||
|
g_receiver_shared.last_wifi_reconnect_attempt_ms = 0;
|
||||||
|
|
||||||
if (has_cfg && wifi_connect_sta(g_cfg)) {
|
if (has_cfg && wifi_connect_sta(g_cfg)) {
|
||||||
g_receiver_shared.ap_mode = false;
|
g_receiver_shared.ap_mode = false;
|
||||||
time_receiver_init(g_cfg.ntp_server_1.c_str(), g_cfg.ntp_server_2.c_str());
|
time_receiver_init(g_cfg.ntp_server_1.c_str(), g_cfg.ntp_server_2.c_str());
|
||||||
@@ -124,6 +129,13 @@ void setup() {
|
|||||||
char ap_ssid[32];
|
char ap_ssid[32];
|
||||||
snprintf(ap_ssid, sizeof(ap_ssid), "%s%04X", AP_SSID_PREFIX, g_short_id);
|
snprintf(ap_ssid, sizeof(ap_ssid), "%s%04X", AP_SSID_PREFIX, g_short_id);
|
||||||
wifi_start_ap(ap_ssid, AP_PASSWORD);
|
wifi_start_ap(ap_ssid, AP_PASSWORD);
|
||||||
|
|
||||||
|
// Store AP credentials in shared state for potential reconnection fallback
|
||||||
|
strncpy(g_receiver_shared.ap_ssid, ap_ssid, sizeof(g_receiver_shared.ap_ssid) - 1);
|
||||||
|
g_receiver_shared.ap_ssid[sizeof(g_receiver_shared.ap_ssid) - 1] = '\0';
|
||||||
|
strncpy(g_receiver_shared.ap_password, AP_PASSWORD, sizeof(g_receiver_shared.ap_password) - 1);
|
||||||
|
g_receiver_shared.ap_password[sizeof(g_receiver_shared.ap_password) - 1] = '\0';
|
||||||
|
|
||||||
if (g_cfg.ntp_server_1.isEmpty()) {
|
if (g_cfg.ntp_server_1.isEmpty()) {
|
||||||
g_cfg.ntp_server_1 = "pool.ntp.org";
|
g_cfg.ntp_server_1 = "pool.ntp.org";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ static void write_u32_be(uint8_t *dst, uint32_t value) {
|
|||||||
dst[3] = static_cast<uint8_t>(value & 0xFF);
|
dst[3] = static_cast<uint8_t>(value & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t read_u32_be(const uint8_t *src) {
|
uint32_t read_u32_be(const uint8_t *src) {
|
||||||
return (static_cast<uint32_t>(src[0]) << 24) |
|
return (static_cast<uint32_t>(src[0]) << 24) |
|
||||||
(static_cast<uint32_t>(src[1]) << 16) |
|
(static_cast<uint32_t>(src[1]) << 16) |
|
||||||
(static_cast<uint32_t>(src[2]) << 8) |
|
(static_cast<uint32_t>(src[2]) << 8) |
|
||||||
@@ -303,6 +303,51 @@ static bool process_batch_packet(const LoraPacket &pkt, BatchInput &out_batch, b
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to attempt WiFi reconnection when stuck in AP mode
|
||||||
|
// Retries WiFi connection periodically (configurable WIFI_RECONNECT_INTERVAL_MS)
|
||||||
|
// to recover from temporary WiFi outages
|
||||||
|
static void try_wifi_reconnect_if_in_ap_mode() {
|
||||||
|
if (!g_ap_mode) {
|
||||||
|
// Already in STA mode, no need to reconnect
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_shared || g_shared->wifi_config.ssid.length() == 0) {
|
||||||
|
// No valid WiFi config to reconnect with
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t now_ms = millis();
|
||||||
|
|
||||||
|
if (g_shared->last_wifi_reconnect_attempt_ms == 0 ||
|
||||||
|
now_ms - g_shared->last_wifi_reconnect_attempt_ms >= WIFI_RECONNECT_INTERVAL_MS) {
|
||||||
|
|
||||||
|
// Update the last attempt time
|
||||||
|
g_shared->last_wifi_reconnect_attempt_ms = now_ms;
|
||||||
|
|
||||||
|
if (SERIAL_DEBUG_MODE) {
|
||||||
|
serial_debug_printf("wifi_reconnect: attempting to reconnect from AP mode");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to reconnect with 10 second timeout
|
||||||
|
if (wifi_try_reconnect_sta(g_shared->wifi_config, 10000)) {
|
||||||
|
// Reconnection successful!
|
||||||
|
g_ap_mode = false;
|
||||||
|
if (SERIAL_DEBUG_MODE) {
|
||||||
|
serial_debug_printf("wifi_reconnect: reconnection successful, switching from AP to STA mode");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Reconnection failed, restore AP mode to ensure web interface is available
|
||||||
|
if (g_shared->ap_ssid[0] != '\0') {
|
||||||
|
wifi_restore_ap_mode(g_shared->ap_ssid, g_shared->ap_password);
|
||||||
|
if (SERIAL_DEBUG_MODE) {
|
||||||
|
serial_debug_printf("wifi_reconnect: reconnection failed, restored AP mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void receiver_loop() {
|
static void receiver_loop() {
|
||||||
watchdog_kick();
|
watchdog_kick();
|
||||||
LoraPacket pkt = {};
|
LoraPacket pkt = {};
|
||||||
@@ -468,6 +513,9 @@ static void receiver_loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
receiver_loop_done:
|
receiver_loop_done:
|
||||||
|
// Try to reconnect to WiFi if stuck in AP mode due to unreliable WiFi
|
||||||
|
try_wifi_reconnect_if_in_ap_mode();
|
||||||
|
|
||||||
mqtt_loop();
|
mqtt_loop();
|
||||||
web_server_loop();
|
web_server_loop();
|
||||||
if (ENABLE_HA_DISCOVERY && !g_receiver_discovery_sent) {
|
if (ENABLE_HA_DISCOVERY && !g_receiver_discovery_sent) {
|
||||||
|
|||||||
@@ -143,3 +143,52 @@ bool wifi_is_connected() {
|
|||||||
String wifi_get_ssid() {
|
String wifi_get_ssid() {
|
||||||
return WiFi.SSID();
|
return WiFi.SSID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to reconnect to WiFi with a shorter timeout (for periodic reconnection attempts)
|
||||||
|
// Called when device is stuck in AP mode and we want to try switching back to STA
|
||||||
|
bool wifi_try_reconnect_sta(const WifiMqttConfig &config, uint32_t timeout_ms) {
|
||||||
|
// Only attempt if not already connected and config is valid
|
||||||
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if config is valid
|
||||||
|
if (config.ssid.length() == 0 || config.mqtt_host.length() == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch to STA mode and attempt connection with shorter timeout
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(config.ssid.c_str(), config.password.c_str());
|
||||||
|
|
||||||
|
uint32_t start = millis();
|
||||||
|
while (WiFi.status() != WL_CONNECTED && millis() - start < timeout_ms) {
|
||||||
|
delay(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool connected = WiFi.status() == WL_CONNECTED;
|
||||||
|
if (connected) {
|
||||||
|
esp_wifi_set_ps(WIFI_PS_MIN_MODEM);
|
||||||
|
if (SERIAL_DEBUG_MODE) {
|
||||||
|
Serial.printf("wifi_reconnect: success, connected to %s\n", config.ssid.c_str());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (SERIAL_DEBUG_MODE) {
|
||||||
|
Serial.printf("wifi_reconnect: failed, remaining in STA mode\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to restore AP mode when reconnection attempt has failed
|
||||||
|
void wifi_restore_ap_mode(const char *ap_ssid, const char *ap_pass) {
|
||||||
|
if (WiFi.status() != WL_CONNECTED) {
|
||||||
|
// We're not connected to WiFi, restore AP mode
|
||||||
|
WiFi.mode(WIFI_AP);
|
||||||
|
WiFi.softAP(ap_ssid, ap_pass);
|
||||||
|
if (SERIAL_DEBUG_MODE) {
|
||||||
|
Serial.printf("wifi_restore_ap: AP mode restored\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user