WiFiManager icon indicating copy to clipboard operation
WiFiManager copied to clipboard

OTA update forgets wifi credentials

Open josejsarmento opened this issue 3 years ago • 3 comments

Basic Infos

Hardware

WiFimanager Branch/Release: Master

Esp8266/Esp32: Esp8266

Hardware: ESP-07S

Core Version: 3.0.2

Description

After an OTA update, the wifi credentials are forgotten. This is odd as I've seen searching through the web that many users have complained about the opposite, and wanted to actually erase wifi creds after an update. Maybe there's a way to store and load the credentials from SPIFFS?

Settings in IDE

Module: Generic ESP8266 module

Additional libraries:

Sketch

#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPClient.h>
#include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager
#include <ArduinoJson.h>

#define HTTP_OTA

#ifdef HTTP_OTA
  #include <ESP8266httpUpdate.h>

  #define HTTP_OTA_ADDRESS      "dummy_address"   // Address of OTA update server
  #define HTTP_OTA_PATH         "path" // Path to update firmware
  #define HTTP_OTA_PORT         port_number                    // Port of update server
                                                         // Name of firmware
  #define HTTP_OTA_VERSION      String(__FILE__).substring(String(__FILE__).lastIndexOf('/')+1) + ".generic" 
#endif


void setup() {
    /* usual WiFiManager setup here */
    WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP

    // put your setup code here, to run once:
    Serial.begin(115200);
    
    // WiFi.mode(WiFi_STA); // it is a good practice to make sure your code sets wifi mode how you want it.

    //WiFiManager, Local intialization. Once its business is done, there is no need to keep it around
    WiFiManager wm;

    //reset settings - wipe credentials for testing
    //wm.resetSettings();

    // Automatically connect using saved credentials,
    // if connection fails, it starts an access point with the specified name ( "AutoConnectAP"),
    // if empty will auto generate SSID, if password is blank it will be anonymous AP (wm.autoConnect())
    // then goes into a blocking loop awaiting configuration and will return success result

    bool res;
    // res = wm.autoConnect(); // auto generated AP name from chipid
    // res = wm.autoConnect("AutoConnectAP"); // anonymous ap
    res = wm.autoConnect("AutoConnectAP","password"); // password protected ap

    if(!res) {
        Serial.println("Failed to connect");
        // ESP.restart();
    } 
    else {
        //if you get here you have connected to the WiFi    
        Serial.println("connected...yeey :)");
    }
}

int updateOTACheckTimer = 28;

void loop() {
     updateOTACheckTimer++;
     if(updateOTACheckTimer > 30){
         updateOTACheckTimer = 0;
         doOTAUpdate();
     }
}

void doOTAUpdate(){
  #ifdef HTTP_OTA
  WiFiClient client;
  // Check server for firmware updates
  Serial.print("Checking for firmware updates from server http://");
  Serial.print(HTTP_OTA_ADDRESS);
  Serial.print(":");
  Serial.print(HTTP_OTA_PORT);
  Serial.println(HTTP_OTA_PATH);
  switch(ESPhttpUpdate.update(client, HTTP_OTA_ADDRESS, HTTP_OTA_PORT, HTTP_OTA_PATH, HTTP_OTA_VERSION)) {
    case HTTP_UPDATE_FAILED:
      Serial.printf("HTTP update failed: Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
      break;

    case HTTP_UPDATE_NO_UPDATES:
      Serial.println(F("No updates"));
      break;

    case HTTP_UPDATE_OK:
      Serial.println(F("Update OK"));
      break;
    }
  #endif
}

Debug Messages

...
11:42:37.471 -> connected...yeey :)
11:42:37.506 -> *WM: [3] unloading 
11:42:45.716 -> Checking for firmware updates from server dummyserver.com
11:43:00.504 -> H!⸮⸮⸮⸮@H⸮⸮⸮f⸮⸮Serial Online
11:43:09.888 -> *WM: [1] AutoConnect 
11:43:09.888 -> *WM: [1] No Credentials are Saved, skipping connect 
11:43:09.957 -> *WM: [2] Starting Config Portal 
11:43:09.994 -> *WM: [2] AccessPoint set password is VALID 
11:43:10.027 -> *WM: [1] password 
11:43:10.062 -> *WM: [3] WIFI station disconnect 
11:43:10.096 -> *WM: [3] WiFi station enable 
11:43:10.129 -> *WM: [2] Disabling STA 
11:43:10.162 -> *WM: [2] Enabling AP 
11:43:10.200 -> *WM: [1] StartAP with SSID:  AutoConnectAP
11:43:11.488 -> *WM: [1] SoftAP Configuration 
11:43:11.526 -> *WM: [1] -------------------- 
11:43:11.562 -> *WM: [1] ssid:             AutoConnectAP
11:43:11.596 -> *WM: [1] password:         password
...

josejsarmento avatar Aug 25 '21 10:08 josejsarmento

I've managed to have something working by writing and loading from the SPIFFS:

char userSSID[32] = "null";
char userwifiPasswd[32];

void setupSpiffs(){
  //clean FS, for testing
  // SPIFFS.format();

  //read configuration from FS json
  Serial.println("mounting FS...");

  if (SPIFFS.begin()) {
    Serial.println("mounted file system");
    if (SPIFFS.exists("/config.json")) {
      //file exists, reading and loading
      Serial.println("reading config file");
      File configFile = SPIFFS.open("/config.json", "r");
      if (configFile) {
        Serial.println("opened config file");
        size_t size = configFile.size();
        // Allocate a buffer to store contents of the file.
        std::unique_ptr<char[]> buf(new char[size]);

        configFile.readBytes(buf.get(), size);
        DynamicJsonDocument jsonDoc(512);
        auto deserializeError = deserializeJson(jsonDoc, buf.get());
        serializeJsonPretty(jsonDoc, Serial);
        
        if (!deserializeError && jsonDoc.containsKey("wifi_ssid") && jsonDoc.containsKey("wifi_pass")) {
          Serial.println("\nparsed json");

          strcpy(userSSID,        jsonDoc["wifi_ssid"]);
          strcpy(userwifiPasswd,  jsonDoc["wifi_pass"]);

        } else {
          if(deserializeError) Serial.println("deserializeError");
          Serial.println("failed to load json config");
        }
      }
    }
  } else {
    Serial.println("failed to mount FS");
  }
  //end read
}

void setup(){
    Serial.begin(115200);

    setupSpiffs();

      if((strcmp(userSSID, "null")) != 0){
    Serial.println("Loading stored WiFi credentials...");
    WiFi.begin(userSSID, userwifiPasswd);
  }
  else{
    <same setup() as before here but add the following lines:>
    //save the custom parameters to FS
    if (shouldSaveConfig) {
      Serial.println("saving config");
      DynamicJsonDocument doc(512);
      doc["wifi_ssid"] = WiFi.SSID();
      doc["wifi_pass"] = WiFi.psk();
  
      File configFile = SPIFFS.open("/config.json", "w");
      if (!configFile) {
        Serial.println("failed to open config file for writing");
      }
  
      serializeJsonPretty(doc, Serial);
      serializeJson(doc, configFile);
      configFile.close();
      //end save
  }
}

void loop(){
...
}

Maybe there could be a feature in WiFiManager so that you could load/store wifi credentials to the SPIFFS?

josejsarmento avatar Aug 25 '21 15:08 josejsarmento

I have seen this happen on some esps and some libs, no idea what causes it probably bad memory guards in ota or cross versions. This really should not happen anymore as the sdk has not changed

tablatronix avatar Aug 25 '21 21:08 tablatronix

I've noticed this issue on my sketch (ESP8266 based), it's really annoying. Will be great to get it fixed.

sensboston avatar Dec 17 '21 21:12 sensboston