Hi, I am relatively new in Arduino programming. I want to connect my ESP32 board as a station to a WiFi network. The SSID and password are available in the files inputSSID.txt and inputPassword.txt in the SPIFFS. Reading the values into variables (storedSSID and storedPassword) with a readFile procedure and using those in the WiFi initialization routine does not work. When I print the variables, it appears that they are empty. This part is commented out in the code below.
When I use the call to the readFile procedure within the WiFi initalization call, everything works fine. I do not understand why the I can't assign the values in the files to the variables. Does anyone have suggestions how I can use the storedSSID variable?
Thanks, Fred
String readFile(fs::FS &fs, const char * path){
//Serial.printf("Reading file: %s\r\n", path);
File file = fs.open(path, "r");
if(!file || file.isDirectory()){
Serial.println("- empty file or failed to open file");
return String();
}
//Serial.println("- read from file:");
String fileContent;
while(file.available()){
fileContent+=String((char)file.read());
}
//Serial.println(fileContent);
return fileContent;
}
//const char* readFile(SPIFFS, "/inputSSID.txt").c_str();
//const char* readFile(SPIFFS, "/inputPassword.txt").c_str());
//Serial.print("Connecting to WiFi (DHCP) .."); Serial.println(soredSSID); //prints empty
//WiFi.begin(storedSSID, storedPassword); //does not work
Serial.print("Connecting to WiFi (DHCP) .."); Serial.println(readFile(SPIFFS, "/inputSSID.txt").c_str());
WiFi.begin(readFile(SPIFFS, "/inputSSID.txt").c_str(), readFile(SPIFFS, "/inputPassword.txt").c_str());
Forget about WiFi until you can read the 2 variables from SPIFFS satisfactorily. Write a simple sketch that does only that. Once you have it working you can put the majority of it in a function in your main sketch
If you are having difficulty using SPIFFS you might want to try using either Preferences.h or EEPROM.h. They both provide simple access to NVS and they are both libraries included in the Arduino core for the ESP32.
@cattledog, thanks! I will consider that as I have more parameters that must be initialized. Nevertheless I want to understand what is going wrong.
@UKHeliBob, here is the output when I run the original code. I send this again as I had to adapt some things....but the problem remains the same.
The code in readFile reproduces the file contents (De Riesen for SSID and empty string for password. The println outside the readFile does NOT print the file contents.
//------ SPIFFS file access procedures ------
String readFile(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\r\n", path);
File file = fs.open(path, "r");
if(!file || file.isDirectory()){
Serial.println("- empty file or failed to open file");
return String();
}
Serial.println("- read from file:");
String fileContent;
while(file.available()){
fileContent+=String((char)file.read());
}
Serial.println(fileContent);
return fileContent;
}
const char* storedSSID = readFile(SPIFFS, "/inputSSID.txt").c_str();
const char* storedPassword = readFile(SPIFFS, "/inputPassword.txt").c_str();
Serial.print("Connecting to WiFi (DHCP) .."); Serial.println(storedSSID); //prints empty
WiFi.begin(storedSSID, storedPassword); //does not work
/*
Serial.print("Connecting to WiFi (DHCP) .."); Serial.println(readFile(SPIFFS, "/inputSSID.txt").c_str());
WiFi.begin(readFile(SPIFFS, "/inputSSID.txt").c_str(), readFile(SPIFFS, "/inputPassword.txt").c_str());
*/
//"busy" indicator
//add a time-out
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Output:
Reading file: /inputSSID.txt
read from file:
De Riesen
Reading file: /inputPassword.txt
I'm not exactly clear on why only one of your pointers to a returned String converted to .c_str() is working correctly. I would expect both to either fail or work.
The solution is to use memcpy() to transfer the .c_str() converted returns to char arrays. The Null terminator is added by the .c_str conversion.
Both conversions behave the same. The printout of the password does not show anything as the file content is an empty string in the current case (open network).
I tried your suggestion to use memcpy() to convert String to const char*. I tried some variations, but without success. Here is my last codet:
//const char* storedSSID = readFile(SPIFFS, "/inputSSID.txt").c_str();
String inputSSID = readFile(SPIFFS, "/inputSSID.txt");
Serial.print("inputSSID = ");Serial.println(inputSSID); //prints the correct inputSSID, so reading SPIFFS works fine
//convert input String to const char*, as apparently WiFi.begin requires const char*
const char* storedSSID;
memcpy(storedSSID, inputSSID, strlen(inputSSID)+1); //memcpy(destination, source, num)
Serial.print("storedSSID = ");Serial.println(storedSSID); //check
Result: cannot convert 'String' to 'const char*' for argument '1' to 'size_t strlen(const char*)'
Reading the SPIFFS file is OK . I checked it by printing the SSID string. So it is really in the conversion from String to const char*.
I tried to look things up on the web, but did not find a nice tutorial with examples. Reference pages are precise, but complex and often lack examples.
Result: cannot convert ‘String’ to ‘const char*’ for argument ‘1’ to ‘size_t strlen(const char*)’
You did not follow the example I gave. Don't use the char*. I believe that it is a null pointer the way you have declared it and If either dest or src is an invalid or null pointer the behavior is undefined, even if count is zero.
This way of using memcpy gives a code that is doing the job! Thanks.
One question: in the declaration of the variables you mention "size appropriately". Does this mean that I have to size it large enough to hold the max. length of the expected SSID and password?
I do not quite understand what char* means and why my way of defining it yields a null pointer.
I have to read about that
I have to look at the place where I "stole" this code (probably in Random Nerd Tutorials). For some reason it was proposed over there. And for some reason I mis-treated the proposal.