Description
This has been an issue for quite some time and also lots of issues have been reported which are probably related to this incorrect state of the WiFi.
So this is merely a collection issue to gather all insights and link topics, as I keep finding my own replies in lost of those topics over and over again, but still feeling lost in this problem.
Related issues:
- Issues with both documentation and implementation of WiFi.status() in ESP8266WiFi library #7005
- WiFi.status shows connected when connection is lost #5912
- Wifi Client is not connected but wifi.status() ==3 #5239
- wifi_station_get_connect_status() doesn't handle connection lost under several circumstances #4810
- WIFI.isconnected stil false after router reboot but ping requests reponse etc works #4210
- View specific wrong password error upon connecting to network #4152
And lots more.
In essence all calls that may check the WiFi.status()
and base their actions on it may run into these problems.
First let's have a look at the enum-mapping performed here:
wl_status_t ESP8266WiFiSTAClass::status() {
station_status_t status = wifi_station_get_connect_status();
switch(status) {
case STATION_GOT_IP:
return WL_CONNECTED;
case STATION_NO_AP_FOUND:
return WL_NO_SSID_AVAIL;
case STATION_CONNECT_FAIL:
case STATION_WRONG_PASSWORD:
return WL_CONNECT_FAILED;
case STATION_IDLE:
return WL_IDLE_STATUS;
default:
return WL_DISCONNECTED;
}
}
typedef enum {
STATION_IDLE = 0,
STATION_CONNECTING,
STATION_WRONG_PASSWORD,
STATION_NO_AP_FOUND,
STATION_CONNECT_FAIL,
STATION_GOT_IP
} station_status_t;
Note that the case of STATION_CONNECTING
results in WL_DISCONNECTED
What I'm observing on some nodes (really hard to reproduce on some and happening almost always on others) is this:
Initial attempt to connect is stuck forever, as the WiFi status never gets to WL_CONNECTED
I checked by calling wifi_station_get_connect_status()
and see the state is stuck at STATION_CONNECTING
.
However the web server may serve pages and the WiFiEventStationModeGotIP
event has fired.
So all seems to be working already, but the state is not updated.
In one issue it was mentioned to call WiFi.setAutoReconnect(true);
to fix this, but that's not the magic fix here.
My work-around for this is to keep track of how long it takes to get a successful connection and if that times out, I call my own resetWiFi()
function.
void resetWiFi() {
WifiDisconnect();
initWiFi();
}
void initWiFi()
{
#ifdef ESP8266
// See https://github.com/esp8266/Arduino/issues/5527#issuecomment-460537616
// FIXME TD-er: Do not destruct WiFi object, it may cause crashes with queued UDP traffic.
// WiFi.~ESP8266WiFiClass();
// WiFi = ESP8266WiFiClass();
#endif // ifdef ESP8266
WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters
WiFi.setAutoReconnect(false);
// The WiFi.disconnect() ensures that the WiFi is working correctly. If this is not done before receiving WiFi connections,
// those WiFi connections will take a long time to make or sometimes will not work at all.
WiFi.disconnect();
setWifiMode(WIFI_OFF);
#if defined(ESP32)
WiFi.onEvent(WiFiEvent);
#else
// WiFi event handlers
stationConnectedHandler = WiFi.onStationModeConnected(onConnected);
stationDisconnectedHandler = WiFi.onStationModeDisconnected(onDisconnect);
stationGotIpHandler = WiFi.onStationModeGotIP(onGotIP);
stationModeDHCPTimeoutHandler = WiFi.onStationModeDHCPTimeout(onDHCPTimeout);
APModeStationConnectedHandler = WiFi.onSoftAPModeStationConnected(onConnectedAPmode);
APModeStationDisconnectedHandler = WiFi.onSoftAPModeStationDisconnected(onDisconnectedAPmode);
#endif
}
// ********************************************************************************
// Disconnect from Wifi AP
// ********************************************************************************
void WifiDisconnect()
{
#if defined(ESP32)
WiFi.disconnect();
#else // if defined(ESP32)
ETS_UART_INTR_DISABLE();
wifi_station_disconnect();
ETS_UART_INTR_ENABLE();
#endif // if defined(ESP32)
}
The initWiFi()
is also called as one of the first functions in my setup()
The WiFi status is also incorrect when the unit gets disconnected.
For example when the ESP node is kicked from the access point (MikroTik AP allows you to disconnect a specific client via the web interface) or whatever other reason there may be to disconnect a node.
This is the code I use to detect if I have an IP-address:
#ifdef CORE_POST_2_5_0
# include <AddrList.h>
#endif // ifdef CORE_POST_2_5_0
bool hasIPaddr() {
#ifdef CORE_POST_2_5_0
bool configured = false;
for (auto addr : addrList) {
if ((configured = (!addr.isLocal() && (addr.ifnumber() == STATION_IF)))) {
/*
Serial.printf("STA: IF='%s' hostname='%s' addr= %s\n",
addr.ifname().c_str(),
addr.ifhostname(),
addr.toString().c_str());
*/
break;
}
}
return configured;
#else // ifdef CORE_POST_2_5_0
return WiFi.isConnected();
#endif // ifdef CORE_POST_2_5_0
}
N.B. the CORE_POST_2_5_0
define is set by me when compiling with a specific core version.
Some times, when the node gets disconnected, the WiFiEventStationModeDisconnected
event is fired, but the WiFi state and/or the presence of the IP-address remains.
The only way to get out of this, is to call my resetWiFi()
function and start over to create a connection.
For some reason, TCP/IP traffic is not causing crashes in this WiFi limbo state, but UDP is causing crashes.
So it would be really helpful if we could either fix this or at least explain it so we can use work-around which don't feel like "don't know why but it makes issues harder to reproduce", which has been the main modus operandi for the last 2 years with these WiFi issues.