[GH-ISSUE #1383] Calling autoConnect() in loop() causes lag #1185

Closed
opened 2026-02-28 01:28:54 +03:00 by kerem · 10 comments
Owner

Originally created by @OekoSolveMG on GitHub (Mar 29, 2022).
Original GitHub issue: https://github.com/tzapu/WiFiManager/issues/1383

Basic Infos

Hardware

WiFiManager Branch/Release: Master 2.0.5-beta
Esp8266/Esp32: ESP32
Hardware: M5 Core 2

Description

When attempting to reconect in the loop, for the case that the device loses WiFi connection and automatically attempts to reconnect (with delays or not) the device becomes laggy and blocks input after a while.

The main reason from what I could debug is that the autoConnect() subscribes to a callback in WiFi_autoReconnect(). In this case that would the the WiFi.onEvent.

void WiFiManager::WiFi_autoReconnect(){
  #ifdef ESP8266
    WiFi.setAutoReconnect(_wifiAutoReconnect);
  #elif defined(ESP32)
    // if(_wifiAutoReconnect){
      // @todo move to seperate method, used for event listener now
      #ifdef WM_DEBUG_LEVEL
      DEBUG_WM(DEBUG_VERBOSE,F("ESP32 event handler enabled"));
      #endif
      using namespace std::placeholders;
      wm_event_id = WiFi.onEvent(std::bind(&WiFiManager::WiFiEvent,this,_1,_2)); // <---------- This Line here
    // }
  #endif
}

The problem is this subscription get's pushed back to a vector of callbacks in the WiFiGeneric class.

wifi_event_id_t WiFiGenericClass::onEvent(WiFiEventFuncCb cbEvent, system_event_id_t event)
{
    if(!cbEvent) {
        return 0;
    }
    WiFiEventCbList_t newEventHandler;
    newEventHandler.cb = NULL;
    newEventHandler.fcb = cbEvent;
    newEventHandler.scb = NULL;
    newEventHandler.provcb = NULL;
    newEventHandler.event = event;
    cbEventList.push_back(newEventHandler); // <---------- This Line here
    return newEventHandler.id;
}

Meaning that if you call autoConnect() in a loop then over a shorter or longer period depeding on how fast you recall autoConnect(), the system will be subscribed to that many callbacks that the rest of the system starts to lag.

Possible fixes

  1. Make WiFiManager::WiFiEvent actually reconnect to the WiFi when using the ESP32. This does not seem to be the case right now

  2. Make autoConnect() removeEvent instead of just the deconstructor.

WiFi.removeEvent(wm_event_id);
  1. Add a check that only subscribed to the callback if it isn't subscribed already.

  2. A method like wifiConnectDefault() could be made public instead of private so that this method could be used to reconnect

Sketch (Quite big so only relevant wifi parts have been included)

#BEGIN

void loop {
  if (WiFi.status() != wl_status_t::WL_CONNECTED) {
    wm.autoConnect();
  }
}
#END

Sketch with fix

Both wifiConnectDefault() and waitForConnectResult() have been made public to ensure this fix works.

const wl_status_t reconnect_to_saved_access_point() {
    if (WiFi.isConnected()) {
        return wl_status_t::WL_CONNECTED;
    }
    else if (!wm.getWiFiIsSaved()) {
        return wl_status_t::WL_NO_SSID_AVAIL;
    }

    wm.wifiConnectDefault();
    return static_cast<wl_status_t>(wm.waitForConnectResult());
}
Originally created by @OekoSolveMG on GitHub (Mar 29, 2022). Original GitHub issue: https://github.com/tzapu/WiFiManager/issues/1383 ### Basic Infos #### Hardware WiFiManager Branch/Release: Master 2.0.5-beta Esp8266/Esp32: ESP32 Hardware: M5 Core 2 ### Description When attempting to reconect in the loop, for the case that the device loses WiFi connection and automatically attempts to reconnect (with delays or not) the device becomes laggy and blocks input after a while. The main reason from what I could debug is that the ```autoConnect()``` subscribes to a callback in ```WiFi_autoReconnect()```. In this case that would the the ```WiFi.onEvent```. ```cpp void WiFiManager::WiFi_autoReconnect(){ #ifdef ESP8266 WiFi.setAutoReconnect(_wifiAutoReconnect); #elif defined(ESP32) // if(_wifiAutoReconnect){ // @todo move to seperate method, used for event listener now #ifdef WM_DEBUG_LEVEL DEBUG_WM(DEBUG_VERBOSE,F("ESP32 event handler enabled")); #endif using namespace std::placeholders; wm_event_id = WiFi.onEvent(std::bind(&WiFiManager::WiFiEvent,this,_1,_2)); // <---------- This Line here // } #endif } ``` The problem is this subscription get's pushed back to a ```vector``` of callbacks in the ```WiFiGeneric``` class. ```cpp wifi_event_id_t WiFiGenericClass::onEvent(WiFiEventFuncCb cbEvent, system_event_id_t event) { if(!cbEvent) { return 0; } WiFiEventCbList_t newEventHandler; newEventHandler.cb = NULL; newEventHandler.fcb = cbEvent; newEventHandler.scb = NULL; newEventHandler.provcb = NULL; newEventHandler.event = event; cbEventList.push_back(newEventHandler); // <---------- This Line here return newEventHandler.id; } ``` Meaning that if you call ```autoConnect()``` in a loop then over a shorter or longer period depeding on how fast you recall ```autoConnect()```, the system will be subscribed to that many callbacks that the rest of the system starts to lag. ### Possible fixes 1. Make WiFiManager::WiFiEvent actually reconnect to the WiFi when using the ESP32. This does not seem to be the case right now 2. Make ```autoConnect()``` removeEvent instead of just the deconstructor. ```cpp WiFi.removeEvent(wm_event_id); ``` 3. Add a check that only subscribed to the callback if it isn't subscribed already. 4. A method like ```wifiConnectDefault()``` could be made public instead of private so that this method could be used to reconnect ### Sketch (Quite big so only relevant wifi parts have been included) ```cpp #BEGIN void loop { if (WiFi.status() != wl_status_t::WL_CONNECTED) { wm.autoConnect(); } } #END ``` ### Sketch with fix Both ```wifiConnectDefault()``` and ```waitForConnectResult()``` have been made public to ensure this fix works. ```cpp const wl_status_t reconnect_to_saved_access_point() { if (WiFi.isConnected()) { return wl_status_t::WL_CONNECTED; } else if (!wm.getWiFiIsSaved()) { return wl_status_t::WL_NO_SSID_AVAIL; } wm.wifiConnectDefault(); return static_cast<wl_status_t>(wm.waitForConnectResult()); } ```
kerem closed this issue 2026-02-28 01:28:54 +03:00
Author
Owner

@tablatronix commented on GitHub (Mar 29, 2022):

hmm, I did not expect people to call autoconnect in a loop
We can just check wm_event_id and avoid recreating multiple events

<!-- gh-comment-id:1082202569 --> @tablatronix commented on GitHub (Mar 29, 2022): hmm, I did not expect people to call autoconnect in a loop We can just check `wm_event_id` and avoid recreating multiple events
Author
Owner

@tablatronix commented on GitHub (Mar 29, 2022):

Try that

I can add a better auto reconnect, ideally esp32 and 8266 are supposed to do this automatically.

<!-- gh-comment-id:1082239460 --> @tablatronix commented on GitHub (Mar 29, 2022): Try that I can add a better auto reconnect, ideally esp32 and 8266 are supposed to do this automatically.
Author
Owner

@OekoSolveMG commented on GitHub (Mar 30, 2022):

Thanks a lot, my use case stems from me wanting to uphold the connection for a long time and because it is an enduser device the wifi could be turned off / not have enough signal strength for a while and lost the connection etc.

In this case I want to reconnect the device, as soon as possible because I am uploading data over MQTT.

I am still wondering if there is a cleaner way to reconnect the device at runtime if it ever looses connection, additionally do I have to turn on any features with the setters to make sure it reconnects or should that be done automatically anyway? Because setWiFiAutoReconnect(true) seems to set a boolean that is never used. Only with the ESP8266, does it actually set the autoReconnect of the underlying WiFiSTA.h.

This is not done however for the ESP32 which only subscribed to the WiFiEvent, which also does not seem to reconnect.

void WiFiManager::WiFi_autoReconnect(){
  #ifdef ESP8266
    WiFi.setAutoReconnect(_wifiAutoReconnect);
  #elif defined(ESP32)
    // if(_wifiAutoReconnect){
      // @todo move to seperate method, used for event listener now
      #ifdef WM_DEBUG_LEVEL
      DEBUG_WM(DEBUG_VERBOSE,F("ESP32 event handler enabled"));
      #endif
      using namespace std::placeholders;
      wm_event_id = WiFi.onEvent(std::bind(&WiFiManager::WiFiEvent,this,_1,_2));
    // }
  #endif
}

Perhaps using something like wifiConnectDefault() could be used in the Event callback when the connection has been lost, when using ESP32 or if possible WiFi.setAutoReconnect() could be set for the ESP32 as well?


I'll add my settings as well perhaps I missed one that needs to be set so that reconnection works?

wm.setMinimumSignalQuality(30); // min percentage to be seen in the selectable wifi dropdown
wm.setConfigPortalTimeout(6000);
wm.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));  //set custom ip for portal
wm.setShowInfoUpdate(false); // don't show update button on info page
wm.setWiFiAutoReconnect(true);
wm.setConnectRetries(5U); // Number of retries to reconnect
wm.setSaveConnectTimeout(5U); // how long we try to connect before continuing
#ifndef DEBUG_LOG
wm.setDebugOutput(false); // disables logging output
#endif // DEBUG_LOG
wm.setShowInfoErase(false); // don't show erase wifi config button on info page
wm.setShowStaticFields(false); // don't show static fields on wifi page (ignored if custom static ips are passed)
wm.setShowDnsFields(false); // don't show dns fields on wifi page (ignored if custom dns is passed)
wm.setDarkMode(true); // force browser website to be in darkmode
wm.setConfigPortalBlocking(false); // doesn't block while waiting for the user to enter a ap password and name into the wifimanager (in exchange process() has to be called to handle messages)

Because using autoConnect() does not seem to actually reconnect after the inital attempt, when the AP is connectable again. This happened even when both setConnectRetries and setConnectTImeout were commented out.

Example build output of the WifiEvent, as we can see the WiFiEvent clearly realises the wifi is theoretically existing again and could be connected too. But the WiFiManager does not do that atleast for me.

*wm:[2] [EVENT] WIFI_REASON: NO_AP_FOUND
*wm:[2] [EVENT] WIFI_REASON:  201
*wm:[2] [EVENT] WIFI_REASON: NO_AP_FOUND
*wm:[2] [EVENT] WIFI_REASON:  201
*wm:[2] [EVENT] WIFI_REASON: NO_AP_FOUND
*wm:[2] [EVENT] WIFI_REASON:  201
*wm:[2] [EVENT] WIFI_REASON: NO_AP_FOUND
*wm:[2] [EVENT] WIFI_REASON:  201
*wm:[2] [EVENT] WIFI_REASON: NO_AP_FOUND
*wm:[2] [EVENT] WIFI_REASON:  2
*wm:[2] [EVENT] WIFI_REASON:  15
<!-- gh-comment-id:1082652994 --> @OekoSolveMG commented on GitHub (Mar 30, 2022): Thanks a lot, my use case stems from me wanting to uphold the connection for a long time and because it is an enduser device the wifi could be turned off / not have enough signal strength for a while and lost the connection etc. In this case I want to reconnect the device, as soon as possible because I am uploading data over MQTT. I am still wondering if there is a cleaner way to reconnect the device at runtime if it ever looses connection, additionally do I have to turn on any features with the setters to make sure it reconnects or should that be done automatically anyway? Because ```setWiFiAutoReconnect(true)``` seems to set a boolean that is never used. Only with the ESP8266, does it actually set the ```autoReconnect``` of the underlying ```WiFiSTA.h```. This is not done however for the ESP32 which only subscribed to the WiFiEvent, which also does not seem to reconnect. ```cpp void WiFiManager::WiFi_autoReconnect(){ #ifdef ESP8266 WiFi.setAutoReconnect(_wifiAutoReconnect); #elif defined(ESP32) // if(_wifiAutoReconnect){ // @todo move to seperate method, used for event listener now #ifdef WM_DEBUG_LEVEL DEBUG_WM(DEBUG_VERBOSE,F("ESP32 event handler enabled")); #endif using namespace std::placeholders; wm_event_id = WiFi.onEvent(std::bind(&WiFiManager::WiFiEvent,this,_1,_2)); // } #endif } ``` Perhaps using something like ```wifiConnectDefault()``` could be used in the Event callback when the connection has been lost, when using ESP32 or if possible ```WiFi.setAutoReconnect()``` could be set for the ESP32 as well? -------------------------------------- I'll add my settings as well perhaps I missed one that needs to be set so that reconnection works? ```cpp wm.setMinimumSignalQuality(30); // min percentage to be seen in the selectable wifi dropdown wm.setConfigPortalTimeout(6000); wm.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); //set custom ip for portal wm.setShowInfoUpdate(false); // don't show update button on info page wm.setWiFiAutoReconnect(true); wm.setConnectRetries(5U); // Number of retries to reconnect wm.setSaveConnectTimeout(5U); // how long we try to connect before continuing #ifndef DEBUG_LOG wm.setDebugOutput(false); // disables logging output #endif // DEBUG_LOG wm.setShowInfoErase(false); // don't show erase wifi config button on info page wm.setShowStaticFields(false); // don't show static fields on wifi page (ignored if custom static ips are passed) wm.setShowDnsFields(false); // don't show dns fields on wifi page (ignored if custom dns is passed) wm.setDarkMode(true); // force browser website to be in darkmode wm.setConfigPortalBlocking(false); // doesn't block while waiting for the user to enter a ap password and name into the wifimanager (in exchange process() has to be called to handle messages) ```` Because using ```autoConnect()``` does not seem to actually reconnect after the inital attempt, when the AP is connectable again. This happened even when both ```setConnectRetries``` and ```setConnectTImeout``` were commented out. Example build output of the WifiEvent, as we can see the WiFiEvent clearly realises the wifi is theoretically existing again and could be connected too. But the WiFiManager does not do that atleast for me. ```cpp *wm:[2] [EVENT] WIFI_REASON: NO_AP_FOUND *wm:[2] [EVENT] WIFI_REASON: 201 *wm:[2] [EVENT] WIFI_REASON: NO_AP_FOUND *wm:[2] [EVENT] WIFI_REASON: 201 *wm:[2] [EVENT] WIFI_REASON: NO_AP_FOUND *wm:[2] [EVENT] WIFI_REASON: 201 *wm:[2] [EVENT] WIFI_REASON: NO_AP_FOUND *wm:[2] [EVENT] WIFI_REASON: 201 *wm:[2] [EVENT] WIFI_REASON: NO_AP_FOUND *wm:[2] [EVENT] WIFI_REASON: 2 *wm:[2] [EVENT] WIFI_REASON: 15 ```
Author
Owner

@tablatronix commented on GitHub (Mar 30, 2022):

Well my point is that the esp libraries are supposed to have autoreconnect enabled by default but I have found they are not always working in the background, not sure why.

<!-- gh-comment-id:1083475845 --> @tablatronix commented on GitHub (Mar 30, 2022): Well my point is that the esp libraries are supposed to have autoreconnect enabled by default but I have found they are not always working in the background, not sure why.
Author
Owner

@OekoSolveMG commented on GitHub (Mar 31, 2022):

Okay thanks a lot for your help. I'll probably try to add a custom reconnect that you can enable with setWiFiAutoReconnect() and a comment to the method that explains that you should enable it if the auto reconnect doesn't work for the ESP32.

To do that I'll probably use the WiFiEvent method to check if the WiFi is disconnected and the error isn't AP NOT FOUND, I should be able to then simply use connectToDefaultAP() to reconnect to the saved access point if there is any and if there isn't reconnecting will be skipped.

I'm currently busy with other stuff but as soon as I tested it on my device and implemented it I will make a pr with a reference to this issue and close this issue if that is fine for you :D.

Thanks a lot for your fast response.

<!-- gh-comment-id:1084718732 --> @OekoSolveMG commented on GitHub (Mar 31, 2022): Okay thanks a lot for your help. I'll probably try to add a custom reconnect that you can enable with ```setWiFiAutoReconnect()``` and a comment to the method that explains that you should enable it if the auto reconnect doesn't work for the ESP32. To do that I'll probably use the ```WiFiEvent``` method to check if the WiFi is disconnected and the error isn't ```AP NOT FOUND```, I should be able to then simply use ```connectToDefaultAP()``` to reconnect to the saved access point if there is any and if there isn't reconnecting will be skipped. I'm currently busy with other stuff but as soon as I tested it on my device and implemented it I will make a pr with a reference to this issue and close this issue if that is fine for you :D. Thanks a lot for your fast response.
Author
Owner

@tablatronix commented on GitHub (Mar 31, 2022):

Thats what i do, I have not really had time to look into it, I usually just add a timer and check if wifi is connected and try a simple WiFi.reconnect(); if not, or reboot after a timeout

<!-- gh-comment-id:1084763271 --> @tablatronix commented on GitHub (Mar 31, 2022): Thats what i do, I have not really had time to look into it, I usually just add a timer and check if wifi is connected and try a simple WiFi.reconnect(); if not, or reboot after a timeout
Author
Owner

@tablatronix commented on GitHub (Apr 7, 2022):

ill create a new issue for autoreconnect testing and solutions

<!-- gh-comment-id:1091766795 --> @tablatronix commented on GitHub (Apr 7, 2022): ill create a new issue for autoreconnect testing and solutions
Author
Owner

@OekoSolveMG commented on GitHub (Apr 8, 2022):

After looking into the WiFiClient / WiFiClientGeneric it seems that the WiFi.setAutoReconnect() does do something, if you loose connection because of authentication or a lot of other reasons etc. You seem to automatically reconnect. This is not the case tough for the case where the access point is turned off and then turned on again. Because it doesn't register a WiFiEvent when an access point that was previously turned off is turned on again.

Meaning this case needs to be polled by the end user to reconnect yourself. Additionaly the WiFiEvent of the WiFiManager doesn't seem to register any WiFiEvents even if setWiFiAutoReconnect() was set.

<!-- gh-comment-id:1092582395 --> @OekoSolveMG commented on GitHub (Apr 8, 2022): After looking into the WiFiClient / WiFiClientGeneric it seems that the ```WiFi.setAutoReconnect()``` does do something, if you loose connection because of authentication or a lot of other reasons etc. You seem to automatically reconnect. This is not the case tough for the case where the access point is turned off and then turned on again. Because it doesn't register a ```WiFiEvent``` when an access point that was previously turned off is turned on again. Meaning this case needs to be polled by the end user to reconnect yourself. Additionaly the ```WiFiEvent``` of the WiFiManager doesn't seem to register any WiFiEvents even if ```setWiFiAutoReconnect()``` was set.
Author
Owner

@tablatronix commented on GitHub (Apr 8, 2022):

Ahh that makes sense, it should still emit a disconnected event , to at least start a reconnect loop, so maybe I can improve this. For some reason I forgot it only does a single reconnect attempt I think.

Should be easy to add to non blocking, since we already have a process..

<!-- gh-comment-id:1093144421 --> @tablatronix commented on GitHub (Apr 8, 2022): Ahh that makes sense, it should still emit a disconnected event , to at least start a reconnect loop, so maybe I can improve this. For some reason I forgot it only does a single reconnect attempt I think. Should be easy to add to non blocking, since we already have a process..
Author
Owner

@tablatronix commented on GitHub (Apr 12, 2022):

I fixed this wrong, and backwards. oops

<!-- gh-comment-id:1095775247 --> @tablatronix commented on GitHub (Apr 12, 2022): I fixed this wrong, and backwards. oops
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/WiFiManager#1185
No description provided.