Merge pull request #157 from kharnt0x/wifi-fix

Better handling of wifi events, by @kharnt0x
This commit is contained in:
rjsc 2024-02-07 13:27:35 +00:00 committed by GitHub
commit a1b6652b50
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 128 additions and 69 deletions

View file

@ -36,15 +36,21 @@ const char index_html[] PROGMEM = R"rawliteral(
</html> </html>
)rawliteral"; )rawliteral";
String wifi_state;
bool wifi_connected;
// Wifi connect time declarations and definition // Wifi connect time declarations and definition
unsigned long wifi_connect_start_time; const unsigned long MAX_WIFI_RECONNECT_BACKOFF_TIME = 60000; // Maximum backoff time of 1 minute
unsigned long wifi_connect_current_time; const unsigned long DEFAULT_WIFI_RECONNECT_BACKOFF_TIME =
unsigned long wifi_connect_timeout = 5000; // Timeout for WiFi connect in milliseconds 1000; // Default wifi reconnect backoff time. Start with 1 second
unsigned long wifi_monitor_loop_time = 30000; // Will check if WiFi is connected and try reconnect every x milliseconds const unsigned long WIFI_CONNECT_TIMEOUT = 10000; // Timeout for WiFi connect in milliseconds
const unsigned long WIFI_MONITOR_LOOP_TIME =
1000; // Will check if WiFi is connected and try reconnect every x milliseconds
unsigned long last_wifi_monitor_run = 0; unsigned long last_wifi_monitor_run = 0;
unsigned long wifi_connect_start_time;
unsigned long wifi_reconnect_backoff_time = DEFAULT_WIFI_RECONNECT_BACKOFF_TIME;
enum WiFiState { DISCONNECTED, CONNECTING, CONNECTED };
WiFiState wifi_state =
DISCONNECTED; //the esp library has no specific state to indicate if its connecting (only WL_IDLE_STATUS) so we keep track of it here
void init_webserver() { void init_webserver() {
// Configure WiFi // Configure WiFi
@ -249,79 +255,123 @@ void init_webserver() {
#endif #endif
} }
void print_wifi_status_message(wl_status_t status) {
switch (status) {
case WL_CONNECTED:
Serial.println("Connected to WiFi network: " + String(ssid));
Serial.println("IP address: " + WiFi.localIP().toString());
Serial.println("Signal Strength: " + String(WiFi.RSSI()) + " dBm");
break;
case WL_CONNECT_FAILED:
Serial.println("Failed to connect to WiFi network: " + String(ssid));
break;
case WL_CONNECTION_LOST:
Serial.println("Connection to WiFi network: " + String(ssid) + " lost");
break;
case WL_DISCONNECTED:
Serial.println("Disconnected from WiFi network: " + String(ssid));
break;
case WL_NO_SSID_AVAIL:
Serial.println("Could not find network with SSID: " + String(ssid));
break;
case WL_IDLE_STATUS:
Serial.println("WiFi is in idle status. This can indicate it is currently trying to connect.");
break;
case WL_SCAN_COMPLETED:
Serial.println("WiFi scan completed");
break;
case WL_NO_SHIELD:
Serial.println("No WiFi shield detected");
break;
default:
Serial.println("Unknown WiFi status: " + String(status));
break;
}
}
// Function to handle WiFi reconnection. Use some timeouts and backoffs here to avoid flooding reconnection attempts/spamming the serial console
void handle_WiFi_reconnection(unsigned long currentMillis, wl_status_t status) {
if (wifi_state == CONNECTING && currentMillis - wifi_connect_start_time > WIFI_CONNECT_TIMEOUT) {
// we are here if we were trying to connect to wifi, but it took too long (more than configured timeout)
Serial.println("Failed to connect to WiFi network before timeout");
print_wifi_status_message(status);
WiFi.disconnect(); //disconnect to clear any previous settings
wifi_state = DISCONNECTED;
wifi_connect_start_time = currentMillis; //reset the start time to now so backoff is respected on next try
// We use a backoff time before trying to connect again. Increase backoff time, up to a maximum
wifi_reconnect_backoff_time = min(wifi_reconnect_backoff_time * 2, MAX_WIFI_RECONNECT_BACKOFF_TIME);
Serial.println("Will try again in " + String(wifi_reconnect_backoff_time / 1000) + " seconds.");
} else if (wifi_state != CONNECTING && currentMillis - wifi_connect_start_time > wifi_reconnect_backoff_time) {
// we are here if the connection failed for some reason and the backoff time has now passed
print_wifi_status_message(status);
init_WiFi_STA(ssid, password);
}
}
// Function to handle WiFi connection
void WiFi_monitor_loop() { void WiFi_monitor_loop() {
unsigned long currentMillis = millis(); unsigned long currentMillis = millis();
if (currentMillis - last_wifi_monitor_run > wifi_monitor_loop_time) { if (currentMillis - last_wifi_monitor_run > WIFI_MONITOR_LOOP_TIME) {
last_wifi_monitor_run = currentMillis; last_wifi_monitor_run = currentMillis;
if (WiFi.status() != WL_CONNECTED && wifi_state != "Connecting") { wl_status_t status = WiFi.status();
wifi_connected = false; switch (status) {
wifi_state = "Not connected"; case WL_CONNECTED:
Serial.print("Wifi disconnected. Attempting reconnection"); if (wifi_state != CONNECTED) { //we need to update our own wifi state to indicate we are connected
init_WiFi_STA(ssid, password); wifi_reconnect_backoff_time =
} else if (WiFi.status() == WL_CONNECTED && wifi_state != "Connected") { DEFAULT_WIFI_RECONNECT_BACKOFF_TIME; // Reset backoff time after maintaining connection
wifi_connected = true; wifi_state = CONNECTED;
wifi_state = "Connected"; print_wifi_status_message(status);
Serial.println("Wifi reconnected"); }
break;
case WL_CONNECT_FAILED:
case WL_CONNECTION_LOST:
case WL_DISCONNECTED:
case WL_NO_SSID_AVAIL:
handle_WiFi_reconnection(currentMillis, status);
break;
case WL_IDLE_STATUS: //this means the wifi is not ready to process any commands (it's probably trying to connect). do nothing
case WL_SCAN_COMPLETED: //this will only be set when scanning for networks. We don't do that yet
case WL_NO_SHIELD: //should not happen, this means no wifi chip detected, so we can't do much
break;
} }
} }
} }
// Function to initialize WiFi in Station Mode (i.e. connect to another access point)
void init_WiFi_STA(const char* ssid, const char* password) {
Serial.println("Connecting to: " + String(ssid));
wifi_state = CONNECTING;
WiFi.begin(ssid, password);
WiFi.setAutoReconnect(true);
wifi_connect_start_time = millis();
}
// Function to convert WiFiState enum to String
String wifi_state_to_string(WiFiState state) {
switch (state) {
case DISCONNECTED:
return "Disconnected";
case CONNECTING:
return "Connecting";
case CONNECTED:
return "Connected";
default:
return "Unknown";
}
}
// Function to initialize WiFi in Access Point Mode
void init_WiFi_AP() { void init_WiFi_AP() {
Serial.print("Creating Access Point: "); Serial.println("Creating Access Point: " + String(ssidAP));
Serial.println(ssidAP); Serial.println("With password: " + String(passwordAP));
Serial.print("With password: ");
Serial.println(passwordAP);
WiFi.softAP(ssidAP, passwordAP); WiFi.softAP(ssidAP, passwordAP);
IPAddress IP = WiFi.softAPIP(); IPAddress IP = WiFi.softAPIP();
Serial.println("Access Point created."); Serial.println("Access Point created.");
Serial.print("IP address: "); Serial.println("IP address: " + IP.toString());
Serial.println(IP);
}
void init_WiFi_STA(const char* ssid, const char* password) {
// If we're already connected, there's nothing to do
if (WiFi.status() == WL_CONNECTED) {
if (wifi_state != "Connected") {
wifi_connected = true;
wifi_state = "Connected";
// Print local IP address and start web server
Serial.println("");
Serial.print("Connected to WiFi network: ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
return;
}
// If we're not currently trying to connect, start the connection process
if (wifi_state != "Connecting") {
Serial.print("Connecting to: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
wifi_state = "Connecting";
wifi_connect_start_time = millis();
return;
}
// If we've been trying to connect for more than 5000ms, give up
if (millis() - wifi_connect_start_time > wifi_connect_timeout) {
wifi_state = "Not connected";
Serial.print("Failed to connect to WiFi network: ");
Serial.println(ssid);
Serial.println("Please check WiFi network name and password, and if WiFi network is available.");
Serial.print("Will try again in ");
Serial.print((wifi_monitor_loop_time - (millis() - last_wifi_monitor_run)) / 1000);
Serial.println(" seconds.");
return;
}
// Otherwise, just print a dot to indicate that we're still trying to connect
Serial.print(".");
} }
// Function to initialize ElegantOTA
void init_ElegantOTA() { void init_ElegantOTA() {
ElegantOTA.begin(&server); // Start ElegantOTA ElegantOTA.begin(&server); // Start ElegantOTA
// ElegantOTA callbacks // ElegantOTA callbacks
@ -367,8 +417,8 @@ String processor(const String& var) {
} }
// Display ssid of network connected to and, if connected to the WiFi, its own IP // Display ssid of network connected to and, if connected to the WiFi, its own IP
content += "<h4>SSID: " + String(ssid) + "</h4>"; content += "<h4>SSID: " + String(ssid) + "</h4>";
content += "<h4>Wifi status: " + wifi_state + "</h4>"; content += "<h4>Wifi status: " + wifi_state_to_string(wifi_state) + "</h4>";
if (wifi_connected == true) { if (WiFi.status() == WL_CONNECTED) {
content += "<h4>IP: " + WiFi.localIP().toString() + "</h4>"; content += "<h4>IP: " + WiFi.localIP().toString() + "</h4>";
// Get and display the signal strength (RSSI) // Get and display the signal strength (RSSI)
content += "<h4>Signal Strength: " + String(WiFi.RSSI()) + " dBm</h4>"; content += "<h4>Signal Strength: " + String(WiFi.RSSI()) + " dBm</h4>";

View file

@ -90,6 +90,15 @@ void init_WiFi_STA(const char* ssid, const char* password);
*/ */
void WiFi_monitor_loop(); void WiFi_monitor_loop();
// /**
// * @brief Function to handle WiFi reconnection.
// *
// * @param[in] void
// *
// * @return void
// */
// void handle_WiFi_reconnection(unsigned long currentMillis);
/** /**
* @brief Initialization function for ElegantOTA. * @brief Initialization function for ElegantOTA.
* *