Chat here about code rewrites, mods, etc... with respect to the github project https://github.com/esp8266/Arduino

Moderator: igrr

User avatar
By OldBikerPete
#42740 Here I am again with another conundrum.

I'm writing this watering system controller in such a way that it will be programmable by users using nothing more than a wifi-connected web browser and web forms. All the required code and web forms will be contained within the D1 mini and SD shield that I am using.

Part of the initialisation I want to use is to have the D1 wake up for the first time as an unsecured access point and output a web form asking for the required mode (access point or client), SSID and password that the controller will use from then on.

Now, in program development up to the point of adding the code to implement the above, I have had the controller hard-coded as a client connecting to my own secured access point. That works fine. My problem is that when I run setup() with the new code implementing the unsecured access point at the start up the function - that is BEFORE the ESP8266 sees any of the old code setting up the secure client, I see messages output in the diagnostic window saying that WiFi has reconnected to my secure access point - That is, somewhere it has cached the required mode information, SSID and password to my access point when that information no longer exists in the program I have repeatedly downloaded before and after power-down/power-up cycles etc. etc.

Does the ESP8266 need to be told to FORGET this information like one has to do with smartphones and other WiFi clients?

If so, How do I do it?

Included below is the code I am using for this setup. Note that I am declaring separate WiFi and server class objects for the setup which will be destroyed once the setup completes. The WiFi and server class objects which will be used after setup is done have been declared either in the library or globally in my program but the code to initialise them doesn't run until this initial setup is done.

##############################################################################

ESP8266WebServer server(80);

// ################################################################## HANDLE SETUP
// This function processes the 'content' returned from the setup.htm web form.
bool handleFileSetup(String path){
int i, j;
String modeName = "";

#if defined(_DEBUG_)
DBG_OUTPUT_PORT.println("handleFileSetup: " + path);
#endif // _DEBUG_

if((j=server.args()) < 3) {
#if defined(_DEBUG_)
DBG_OUTPUT_PORT.println("ERROR: Too few arguments returned");
DBG_OUTPUT_PORT.flush();
#endif // _DEBUG_
return FALSE;
}
#if defined(_DEBUG_)
for(i=0; i < j; i++) {
DBG_OUTPUT_PORT.printf("argName(%d) = \"%s\", arg(%d) = \"%s\"\r\n", i, server.argName(i).c_str(), i, server.arg(i).c_str());
}
DBG_OUTPUT_PORT.flush();
#endif // _DEBUG_
if(server.argName(0) == "access" || server.argName(0) == "client") {
modeName = server.arg(0);
} else {
#if defined(_DEBUG_)
DBG_OUTPUT_PORT.println("ERROR: Arg[0] should be \"access\" or \"client\"");
DBG_OUTPUT_PORT.flush();
#endif // _DEBUG_
return FALSE;
}

#if defined(_DEBUG_)
DBG_OUTPUT_PORT.println("Operation File is: " + modeName);
DBG_OUTPUT_PORT.flush();
#endif // _DEBUG_

if(modeName == "") return FALSE;

gotUpdatedTimeFlag = TRUE; // Not a time flag here, just flagging that handleFileSetup() has run.
// This function is not yet completely written
return handleFileGET(modeName);
return TRUE;
}

// ##################################################################
// Re-entrant function to print the directory of the SD card.
// lifted from one of the library examples
#ifdef _DEBUG_
void printDirectory(File dir, int numTabs)
{
while(TRUE) {
File entry = dir.openNextFile();
if (! entry) {
break; // no more files
}
for (uint8_t i=0; i<numTabs; i++) {
DBG_OUTPUT_PORT.print('\t');
}
DBG_OUTPUT_PORT.print(entry.name());
if (entry.isDirectory()) {
DBG_OUTPUT_PORT.println("/");
printDirectory(entry, numTabs+1);
} else {
// files have sizes, directories do not
DBG_OUTPUT_PORT.print("\t\t");
DBG_OUTPUT_PORT.println(entry.size(), DEC);
}
entry.close();
}
}
#endif // _DEBUG_

// ################################################################## SETUP
void setup(void) {
uint16_t i;

#if defined(_DEBUG_)
uint8_t v;
DBG_OUTPUT_PORT.begin(115200);
while( ! DBG_OUTPUT_PORT);
DBG_OUTPUT_PORT.print("\n");
DBG_OUTPUT_PORT.setDebugOutput(true);
DBG_OUTPUT_PORT.printf("Stack now at %09X\r\n", &v);
#endif // _DEBUG_

SD.begin();
#if defined(_DEBUG_)
{
File root = SD.open("/");
printDirectory(root, 0);
}
#endif // _DEBUG_

pinMode(INITIALISE_TEST_PIN, INPUT);
#if defined(_DEBUG_)
DBG_OUTPUT_PORT.printf("SSID = \"%s\"\r\n", ssid.c_str());
#endif // _DEBUG_
if(digitalRead(INITIALISE_TEST_PIN) || ssid == "") {
uint32_t j;
ssid = "";
// Wifi mode and credentials unknown, so use an unsecured access
// point and web server to get the values for those
#if defined(_DEBUG_)
i = 1; DBG_OUTPUT_PORT.println("Configuring setupWiFi mode and credentials");
#endif // _DEBUG_
ESP8266WiFiClass setupWiFi;
setupWiFi.softAP("WaterAP"); // Unsecured connection - no password.
while(setupWiFi.status() != WL_CONNECTED) {
delay(500);
#if defined(_DEBUG_)
DBG_OUTPUT_PORT.print(".");
#endif // _DEBUG_
}
#if defined(_DEBUG_)
DBG_OUTPUT_PORT.println("Setup WiFi connected");
#endif // _DEBUG_
ESP8266WebServer setupServer(80);
setupServer.on("/", HTTP_GET, [](){ if(!handleFileGET("setup.htm")) server.send(404, "text/plain", "FileNotFound"); });
setupServer.on("/setup.htm", HTTP_POST, [](){ if(!handleFileSetup("setup.htm")) server.send(404, "text/plain", "FileNotFound"); });
setupServer.begin();

#if defined(_DEBUG_)
DBG_OUTPUT_PORT.println("HTTPD Setup Server started");
#endif // _DEBUG_

while( ! gotUpdatedTimeFlag) {
setupServer.handleClient(); // NB: This is not a blocking function
}
}
gotUpdatedTimeFlag = FALSE; // Repeat initialisation of this flag.

while(1);
User avatar
By piersfinlayson
#42743 The esp8266 stores off wifi config in the last 0x4000 of flash (from 0x7c000 onwards on a 512KB flash).

Easiest way to get rid of this is just to completely erase the flash:

Code: Select allesptool.py erase_flash


In my app I never let the ESP8266 store station config. This done by using

Code: Select allwifi_station_set_config_current


instead of

Code: Select allwifi_station_set_config


In arduino framework think you use:

Code: Select allESP8266WiFiGenericClass::persistent


I then store the station config off in my own bit of flash, where I can more easily control what's stored there, and erase it myself.

I also don't let the wifi connect til I'm ready. You do this by sticking the following in user_init():

Code: Select allwifi_station_set_auto_connect(0);


Looks like you can do this with arduino using:

Code: Select allESP8266WiFiSTAClass::setAutoConnect


However, I don't know if arduino setup() is run early enough to prevent it from auto connecting.
User avatar
By OldBikerPete
#42809 Great. Thank you for the answers.
Responding to answers in the order they were given.
if I do esptool.py erase_flash, will it erase ALL the flash, including the Arduino bootloader?

But the D1 mini has 1024Kb program flash. Where will the WiFi config be stored in that case? Still in the last 0x4000 bytes of program flash? IE at address 0xFc000 ? What sector number would that be?