Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calling autoConnect() in loop() causes lag #1383

Closed
OekoSolveMG opened this issue Mar 29, 2022 · 10 comments
Closed

Calling autoConnect() in loop() causes lag #1383

OekoSolveMG opened this issue Mar 29, 2022 · 10 comments

Comments

@OekoSolveMG
Copy link

OekoSolveMG commented Mar 29, 2022

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());
}
@tablatronix
Copy link
Collaborator

tablatronix commented 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

tablatronix added a commit that referenced this issue Mar 29, 2022
@tablatronix
Copy link
Collaborator

tablatronix commented Mar 29, 2022

Try that

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

@OekoSolveMG
Copy link
Author

OekoSolveMG commented 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

@tablatronix
Copy link
Collaborator

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.

@OekoSolveMG
Copy link
Author

OekoSolveMG commented 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.

@tablatronix
Copy link
Collaborator

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

@tablatronix
Copy link
Collaborator

ill create a new issue for autoreconnect testing and solutions

@OekoSolveMG
Copy link
Author

OekoSolveMG commented 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.

@tablatronix
Copy link
Collaborator

tablatronix commented 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..

@tablatronix
Copy link
Collaborator

I fixed this wrong, and backwards. oops

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants