Arduino-esp32: Wifi.persistent(true) is not working

Created on 31 Jul 2017  路  9Comments  路  Source: espressif/arduino-esp32

I tried doing a WiFi.persistent(true); before my WiFi.begin and unfortunately when I restart my device Wifi.SSID() is still empty. This behavior is different to what I am used to with the ESP8266. Has WiFi.persistent basically not been implemented yet?

stale

Most helpful comment

Sure. Here are some apis I wrote for myself to save and load strings that works for both ESPs:

bool IsStringSaved(uint16_t startAt)
{
#ifdef ESP32
  Preferences* preferences = new Preferences();
  preferences->begin("my-app", false);
  String token = preferences->getString((String("") + startAt).c_str());
  preferences->end();
  delete preferences;
  if (token.length() == 0) {
    return false;
  }
#else
  EEPROM.begin(EEPROM_SIZE);
  char s = EEPROM.read(startAt);
  char c = EEPROM.read(startAt+1);
  EEPROM.end();
  return s == 'S' && c == ':';
#endif
}

// Saves string to EEPROM. Returns index position after end of string.
int SaveString(uint16_t startAt, const String& id)
{
#ifdef ESP32
  Preferences* preferences = new Preferences();
  preferences->begin("my-app", false);
  int ret = preferences->putString((String("") + startAt).c_str(), id.c_str());
  preferences->end();
  delete preferences;
  return ret;
#else
  uint16_t len = id.length();
  EEPROM.begin(EEPROM_SIZE);
  EEPROM.write(startAt, 'S');
  EEPROM.write(startAt + 1, ':');
  for (uint16_t i = 0; i <= len; i++)
  {
    EEPROM.write(i + startAt + 2, (uint8_t) id.c_str()[i]);
  }
  EEPROM.write(startAt + len + 2, 0);
  EEPROM.end();
  return startAt + len + 2;
#endif
}

// Loads string from EEPROM. Returns length of string read.
int LoadString(uint16_t startAt, char* buffer, size_t maxLen)
{
#ifdef ESP32
  Preferences* preferences = new Preferences();
  preferences->begin("my-app", false);
  auto ret = preferences->getString((String("") + startAt).c_str(), buffer, maxLen);
  preferences->end();
  delete preferences;
  return ret > 0 ? ret : -1;
#else
  EEPROM.begin(EEPROM_SIZE);
  uint16_t i = 0;
  if ((char) EEPROM.read(startAt) != 'S' || (char) EEPROM.read(startAt+1) != ':') {
    return -1;
  }
  do
  {
    buffer[i] = (char)EEPROM.read(startAt + i + 2); // +2 is to skip the prefix
  } while(i < maxLen && buffer[i++] != 0);
  EEPROM.end();
  if (i >= maxLen) {
    return -1;
  }
  return i;
#endif
}

All 9 comments

pretty much :)

Ok thanks for the update; I've worked around the problem using Preferences. Keeping the issue open until it gets fixed.

any news about this ?

@salqadri do you have an example for Preferences ?A workaround should be nice.

Sure. Here are some apis I wrote for myself to save and load strings that works for both ESPs:

bool IsStringSaved(uint16_t startAt)
{
#ifdef ESP32
  Preferences* preferences = new Preferences();
  preferences->begin("my-app", false);
  String token = preferences->getString((String("") + startAt).c_str());
  preferences->end();
  delete preferences;
  if (token.length() == 0) {
    return false;
  }
#else
  EEPROM.begin(EEPROM_SIZE);
  char s = EEPROM.read(startAt);
  char c = EEPROM.read(startAt+1);
  EEPROM.end();
  return s == 'S' && c == ':';
#endif
}

// Saves string to EEPROM. Returns index position after end of string.
int SaveString(uint16_t startAt, const String& id)
{
#ifdef ESP32
  Preferences* preferences = new Preferences();
  preferences->begin("my-app", false);
  int ret = preferences->putString((String("") + startAt).c_str(), id.c_str());
  preferences->end();
  delete preferences;
  return ret;
#else
  uint16_t len = id.length();
  EEPROM.begin(EEPROM_SIZE);
  EEPROM.write(startAt, 'S');
  EEPROM.write(startAt + 1, ':');
  for (uint16_t i = 0; i <= len; i++)
  {
    EEPROM.write(i + startAt + 2, (uint8_t) id.c_str()[i]);
  }
  EEPROM.write(startAt + len + 2, 0);
  EEPROM.end();
  return startAt + len + 2;
#endif
}

// Loads string from EEPROM. Returns length of string read.
int LoadString(uint16_t startAt, char* buffer, size_t maxLen)
{
#ifdef ESP32
  Preferences* preferences = new Preferences();
  preferences->begin("my-app", false);
  auto ret = preferences->getString((String("") + startAt).c_str(), buffer, maxLen);
  preferences->end();
  delete preferences;
  return ret > 0 ? ret : -1;
#else
  EEPROM.begin(EEPROM_SIZE);
  uint16_t i = 0;
  if ((char) EEPROM.read(startAt) != 'S' || (char) EEPROM.read(startAt+1) != ':') {
    return -1;
  }
  do
  {
    buffer[i] = (char)EEPROM.read(startAt + i + 2); // +2 is to skip the prefix
  } while(i < maxLen && buffer[i++] != 0);
  EEPROM.end();
  if (i >= maxLen) {
    return -1;
  }
  return i;
#endif
}

I have looked at the code for WiFi.persistent(). All this seems to do right now is set a protected member variable WifiGeneric::_persistent which is never used. So no point in calling it, either way :(

Further investigation actually shows that the WiFI settings _are_ getting persisted, regardless of whether you want this or not. However, unlike WiFi.psk() (which returns the previously used password) WiFi.SSID() is coded to return an empty string if the WiFi is not currently connected to an AP.

Here's some code you can use to read the previously used SSID and password if case its useful:

#include <esp_wifi.h>

...

    WiFi.enableSTA(true);
    wifi_config_t conf;
    esp_wifi_get_config(WIFI_IF_STA, &conf);
    Serial.printf("WiFi.SSID:%s\n", F(conf.sta.ssid));
    Serial.printf("WiFi.psk:%s\n", F(conf.sta.password));

I've successfully used this to test if I'm connecting to the same AP as last time, so that I can work around another bug in the library that basically stops the esp32 from connecting to a new AP unless you reboot it a couple of times:

    // Check if the ssid and password to connect to are the same as last time
    if (ssid == F(conf.sta.ssid) && password == F(conf.sta.password)) {
        Serial.println("Connecting to previous AP");
        WiFi.begin();
    }
    else {
        // If not, force an STA disconnect (which clears the data) and connect to 
        // the new AP. Note that without this enableSTA(false) call, a bug in the 
        // esp32 library means the call to "begin(ssid, password)" will never connect
        Serial.println("Connecting to new AP");
        WiFi.enableSTA(false);
        WiFi.begin(ssid.c_str(), password.c_str());
    }

I don't want to constantly nuke the config settings by simply following the lower branch each time because I'm connecting every 5 minutes from deep sleep, so I'm worried about wearing out the EEPROM by constantly writing new data to the NVM.

@salqadri , thanks for the work around API,but unfortunately i was unable to us this APIs in arduino to make esp32 do the same Wifi.persistent(true) functionality so it remember to connect to same AP it was connected before deepsleep.
can you please tell me how do you incorporate this API in arduino and how should i save AP "ssid" and "Pass" and my sta static "ip" information in NVS by this APIs, thanks.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

This stale issue has been automatically closed. Thank you for your contributions.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

maxgerhardt picture maxgerhardt  路  3Comments

DrewHoyt picture DrewHoyt  路  4Comments

ComputerLag picture ComputerLag  路  3Comments

mpatafio picture mpatafio  路  4Comments

huming2207 picture huming2207  路  4Comments