WiFiManager: WiFi config does not persist after multiple failed connection attempts

Hi Guys,

Firstly, I’m a big fan of this library, thanks @tzapu and @kentaylor

I’m currently running the @kentaylor version of the manager, but I believe this issue is relevant for @tzapu version too.

I’ve found that the WiFi config does not persist across multiple restarts. That is, WiFi.SSID() returns nothing after a couple of failed connection attempts/timeouts and hence gets into a state where it will never connect to the last known WiFi and needs to be manually reconfigured. Note that this can also be observed by looking at the output from WiFi.printDiag(Serial); and turning off the AP you are trying to connect to, restart x2.

I have tried a few things to get this going in a simple way such as calling WiFi.persistent(true); and ensuring WiFi.disconnect(true); (which clears settings) is not run, but none of these things seem to have any effect.

So, in my efforts to get this going, I’ve essentially implemented my own SSID and Password persist code and thought I’d share.

The code below are extracts from my working code to show just essential functions.

Firstly I modified the WiFiManager function startConfigPortal to allow the caller to optionally specify a Station SSID and Password to be used only if the timeout is reached (does not run if normal connect occurs).

WiFiManager.h:

boolean       startConfigPortal(char const *apName, char const *apPassword = NULL, char const *stnSSIDDefault = NULL, char const *stnPasswordDefault = NULL);

And added this into startConfigPortal just where it drops out from the while loop.

WiFiManager.cpp

  if (_configPortalTimeout) {
    DEBUG_WM(F("Timout... try saved credentials.") );
    // using user-provided  _ssid, _pass in place of system-stored ssid and pass
    if (connectWifi(stnSSIDDefault, stnPasswordDefault) != WL_CONNECTED) {
      DEBUG_WM(F("Failed to connect.") );
      WiFi.mode(WIFI_AP); // Dual mode becomes flaky if not connected to a WiFi network.
      // I think this might be because too much of the processor is being utilised
      //trying to connect to the network.
    } else {
      //notify that configuration has changed and any optional parameters should be saved
      if (_savecallback != NULL) {
        //todo: check if any custom parameters actually exist, and check if they really changed maybe
        _savecallback();
      }
      //break;
    }
  }

Then, I added the following to my module (but maybe this could be encapsulated in the WiFiManager?

#includes ...

#define EEPROM_size              512   // EEPROM map for persisting strings (need null termination, so 20 char string = 21 bytes)
#define EEPROM_PROGRAMMED1       0
#define EEPROM_PROGRAMMED2       EEPROM_PROGRAMMED1 + 1
#define EEPROM_WIFISSID_start    EEPROM_PROGRAMMED2 + 1
#define EEPROM_WIFISSID_len      33
#define EEPROM_WIFISSID_end      EEPROM_WIFISSID_start + EEPROM_WIFISSID_len
#define EEPROM_WIFIPW_start      EEPROM_WIFISSID_end + 1
#define EEPROM_WIFIPW_len        33
#define EEPROM_WIFIPW_end        EEPROM_WIFIPW_start + EEPROM_WIFIPW_len

char         EEPROM_WIFISSID[EEPROM_WIFISSID_len] = "";                            // Data structure to hold the stuff persisted in EEPROM
String       s_EEPROM_WIFISSID                    = "";
String       s_Current_WIFISSID                   = "";
char         EEPROM_WIFIPW[EEPROM_WIFIPW_len]     = "";                            // Data structure to hold the stuff persisted in EEPROM
String       s_EEPROM_WIFIPW                      = "";
String       s_Current_WIFIPW                     = "";

void setup() {
  readEEPROM();
  getWIFIConfig();
  WiFiManager wifiManager;
  wifiManager.startConfigPortal(APName.c_str(), APPassword.c_str(), s_EEPROM_WIFISSID.c_str(), s_EEPROM_WIFIPW.c_str() );
}

void getWIFIConfig() {
  struct station_config conf;
  wifi_station_get_config(&conf);
  const char            * ssidcstr = reinterpret_cast<const char*>(conf.ssid);
  s_Current_WIFISSID = String(ssidcstr);
  const char            * passphrasecstr = reinterpret_cast<const char*>(conf.password);
  s_Current_WIFIPW = String(passphrasecstr);
  Serial.print("getWIFIConfig: ssid: [");
  Serial.print(s_Current_WIFISSID);
  Serial.print("] password: [");
  Serial.print(s_Current_WIFIPW);
  Serial.println("]");

  if (s_Current_WIFISSID != "") {
    Serial.println("wifiConnectionManagerKT: pre-connection check Found SSID in last wifi config, save to EEPROM...");
    strlcpy(EEPROM_WIFISSID, s_Current_WIFISSID.c_str(), sizeof (EEPROM_WIFISSID) );
    strlcpy(EEPROM_WIFIPW, s_Current_WIFIPW.c_str(), sizeof (EEPROM_WIFIPW) );
    Serial.println("wifiConnectionManagerKT: pre-connection check Save_System_EEPROM...");
    Save_System_EEPROM();
    //Load_System_EEPROM();          // TESTING
  } else if (s_EEPROM_WIFISSID != "") {
    Serial.println("wifiConnectionManagerKT: pre-connection check found values in EEPROM but not in last WIFI config??? Try to set WiFi config from EEPROM...");
    //WiFi.begin(s_EEPROM_WIFISSID.c_str(), s_EEPROM_WIFIPW.c_str() );
    //WiFi.printDiag(Serial);      //Remove this line if you do not want to see WiFi password printed
  } else {
    Serial.println("wifiConnectionManagerKT: no WIFI config found in either last config or EEPROM.");
  }
}

bool Is_System_EEPROM_programmed() {
  return ( (EEPROM.read(EEPROM_PROGRAMMED1) == 42) && (EEPROM.read(EEPROM_PROGRAMMED2) == 24) );
}

void Load_System_EEPROM() {
  if ( (EEPROM.read(EEPROM_PROGRAMMED1) == 42) && (EEPROM.read(EEPROM_PROGRAMMED2) == 24) ) {
    EEPROM_load_string( (byte *) EEPROM_WIFISSID, EEPROM_WIFISSID_start, EEPROM_WIFISSID_end);
    EEPROM_load_string( (byte *) EEPROM_WIFIPW, EEPROM_WIFIPW_start, EEPROM_WIFIPW_end);

    s_EEPROM_WIFISSID = String(EEPROM_WIFISSID);
    Serial.print("Load_System_EEPROM: s_EEPROM_WIFISSID: ");
    Serial.println(s_EEPROM_WIFISSID);

    s_EEPROM_WIFIPW = String(EEPROM_WIFIPW);
    Serial.print("Load_System_EEPROM: s_EEPROM_WIFIPW: ");
    Serial.println(s_EEPROM_WIFIPW);
  }
}

void Save_System_EEPROM() {
  EEPROM_save_string( (byte *) EEPROM_WIFISSID, EEPROM_WIFISSID_start, EEPROM_WIFISSID_end);
  EEPROM_save_string( (byte *) EEPROM_WIFIPW, EEPROM_WIFIPW_start, EEPROM_WIFIPW_end);
  EEPROM.write(EEPROM_PROGRAMMED1, 42);   // easy but hack way to see if EEPROM was initialized, must be a smarter approach
  EEPROM.write(EEPROM_PROGRAMMED2, 24);   // 42 24 - thanks Douglas Adams!
  EEPROM.commit();

  s_EEPROM_WIFISSID = String(EEPROM_WIFISSID);
  Serial.print("Load_System_EEPROM: s_EEPROM_WIFISSID: ");
  Serial.println(s_EEPROM_WIFISSID);

  s_EEPROM_WIFIPW = String(EEPROM_WIFIPW);
  Serial.print("Load_System_EEPROM: s_EEPROM_WIFIPW: ");
  Serial.println(s_EEPROM_WIFIPW);
}

void EEPROM_load_string(byte string[], int str_start, int str_end) {
  int i;
  for (i = str_start; i < str_end; i++) {
    string[i - str_start] = EEPROM.read(i);
  }
}


void EEPROM_save_string(byte string[], int str_start, int str_end) {
  int i;
  for (i = str_start; i < str_end; i++) {
    EEPROM.write(i, string[i - str_start]);
  }
}

void readEEPROM() {
  EEPROM.begin(EEPROM_size);  //needed by the ESP lib - specify the size of EEPROM space accessible

  Serial.println("readEEPROM: start...");
  if (Is_System_EEPROM_programmed() ) {
    Serial.println("readEEPROM: Is_System_EEPROM_programmed: YES");
    Serial.println("readEEPROM: Load_System_EEPROM...");
    Load_System_EEPROM();
  } else {
    Serial.println("readEEPROM: Is_System_EEPROM_programmed: NO");
    Serial.println("readEEPROM: Save_System_EEPROM with nothing...");
    Save_System_EEPROM();
  }
}

About this issue

Most upvoted comments

sigh, what a damn waste of time, scannetworks calls disconnect! I thought I added debug there but I must have reverted it. Well there you go.

    int status = wifi_station_get_connect_status();
    if(status != STATION_GOT_IP && status != STATION_IDLE) {
        WiFi.disconnect(false);
    }

kens branch is unstable for me, my esp fails to connect after every boot, then flash gets wiped. There is something going on with memory, i think it has something to do with doing the scannetworks while the esp is connecting. I can reproduce with his branch, no idea why he is doing a WiFi.scanNetworks(); on constructor.

I have a feeling there is something wrong with that code, or there is another memory overflow, cause as soon as I put his branch on my board it went to crap. exceptions all over the place. Gonna try erasing flash and doing some memory dumps

I still cannot narrow down, wtf is causing it to not connect, and what is subsequently wiping config.

are you guys settings timeouts on configportal ? wifiManager.setConfigPortalTimeout(60);

If you don’t the default it to wait for config indefinitely on connect failure.

Also consider increasing setConnectTimeout value also