read/write ESP8266 EEPROM for saving WiFi SSID / PW / IP-Adr.

Hallo,

im trying to write some functions helping me to save WiFi configurations for some IoT projekt.
I havent got an ESP8266 here for testing today, so i just started coding.

To make things easier, i want to declare all Strings i want to read/write with a constant max. lenth.
I know this code is full of errors, but i hope you can give me some good advice

#include <EEPROM.h>

char wifi_ssid_private[32];
char wifi_password_private[32];
char clientName[10] = "newClient";
char ipAddr[11] = "172.24.1.1";//Pi Access Point IP-Adr.

//startAdr: offset (bytes), writeString: String to be written to EEPROM
void writeEEPROM(int startAdr, String writeString) {
  EEPROM.begin(512); //Max bytes of eeprom to use
  delay(3000);
  Serial.println();
  Serial.println("Startup");
  //write to eeprom
  int charLength=writeString.length();
 
  Serial.println("writing eeprom:");
          for (int i = 0; i < charLength; ++i)
            {
              EEPROM.write(startAdr + i, writeString[i]);
              Serial.print("Wrote: ");
              Serial.println(writeString[i]);
            }
}

char* readEEPROM(int startAdr, int maxLength, char* dest) {
  Serial.println("Reading EEPROM");
  EEPROM.begin(512);
  for (int i = 0; i < maxLength; ++i)
    {
      dest += char(EEPROM.read(startAdr + i));
      if(dest[i]='\0') break;//break when end of sting is reached before maxLength
    }
  //esid.trim();
  Serial.print("ready reading:");
  Serial.println(dest);

  return dest;
}
  
void setup() {
  Serial.begin(9600);
  delay(100);
  
  strcat(wifi_ssid_private, "myWiFiSSID");
  strcat(wifi_password_private, "myWiFiPW");

  writeEEPROM(0,wifi_ssid_private);//32 byte max length
  writeEEPROM(32,wifi_password_private);//32 byte max length
  writeEEPROM(64,clientName);//10 byte max length
  writeEEPROM(74,ipAddr);//11 byte max length
  /*85 byte saved in total?*/  
  Serial.println("everything saved...");
  //get SSID max 32byte
  readEEPROM(0,32,wifi_ssid_private);
  /*i dont know whats the better way, but the next line is not compiling*/
  //get PW max 32byte
  wifi_password_private[] = readEEPROM(32,32,wifi_password_private);
  
}

void loop() {
  // put your main code here, to run repeatedly:

}
/*
examples/sources
http://forum.arduino.cc/index.php?topic=428836.0
https://gist.github.com/dogrocker/f998dde4dbac923c47c1
void setup() {
  Serial.begin(115200);
  EEPROM.begin(512);
  delay(3000);
  Serial.println();
  Serial.println();
  Serial.println("Startup");
 

//write to eeprom
  String qsid="Global";
  int charLength=qsid.length();
 
  Serial.println("writing eeprom ssid:");
          for (int i = 0; i < qsid.length(); ++i)
            {
              EEPROM.write(i, qsid[i]);
              Serial.print("Wrote: ");
              Serial.println(qsid[i]);
            }


//read to eeprom
 
  Serial.println("Reading EEPROM ssid");
  String esid;
  for (int i = 0; i < charLength; ++i)
    {
      esid += char(EEPROM.read(i));
    }
    //esid.trim();
    Serial.println(esid.length());
  Serial.print("SSID: ");
  Serial.println(esid);

*/

thanks

Whats the best way to get the readed chars out of my readEEPROM() function back to my global char array variables?

Edit:
So my code now looks like this. Still had no chance to test it on an ESP but its compiling, yeay :smiling_imp:
Seems like i need EEPROM.commit(); to write my strings buffered in the RAM to the EEPROM.
Ive seen EEPROM.end(); too, can anyone tell me the difference?
Seems like there are differences between EEPROM writing of an regular arduino and the ESP8266.
Is the #include <EEPROM.h> the right one for the ESP?

#include <ESP8266WiFiScan.h>
#include <WiFiUdp.h>
#include <WiFiClientSecure.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WiFiGeneric.h>
#include <ESP8266WiFiType.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266WiFiAP.h>
#include <WiFiServer.h>
#include <ESP8266WiFiSTA.h>
/*are there libs i can exclude? like the WiFiAP cause i do not use ESP as an AccessPoint?*/

#include <EEPROM.h>

char wifi_ssid_private[32];
char wifi_password_private[32];
char clientName[10] = "newClient";
char ipAddr[16] = "172.024.001.001";//Pi Access Point IP-Adr.

//startAdr: offset (bytes), writeString: String to be written to EEPROM
void writeEEPROM(int startAdr, String writeString) {
  EEPROM.begin(512); //Max bytes of eeprom to use
  yield();
  yield();
  Serial.println();
  Serial.println("Startup");
  //write to eeprom
  int charLength=writeString.length();
  Serial.println("writing eeprom:");
          for (int i = 0; i < charLength; ++i)
            {
              EEPROM.write(startAdr + i, writeString[i]);
              Serial.print("Wrote: ");
              Serial.println(writeString[i]);
            }
}

void readEEPROM(int startAdr, int maxLength, char* dest) {
  Serial.println("Reading EEPROM");
  EEPROM.begin(512);
  for (int i = 0; i < maxLength; ++i)
    {
      dest += char(EEPROM.read(startAdr + i));
      if(dest[i]='\0') break;//break when end of sting is reached before maxLength
    }
  //esid.trim();
  Serial.print("ready reading:");
  Serial.println(dest);
}
  
void setup() {
  Serial.begin(9600);
  yield();
  yield();
  strcat(wifi_ssid_private, "myWiFiSSID");
  strcat(wifi_password_private, "myWiFiPW");

  writeEEPROM(0,wifi_ssid_private);//32 byte max length
  writeEEPROM(32,wifi_password_private);//32 byte max length
  writeEEPROM(64,clientName);//10 byte max length
  writeEEPROM(74,ipAddr);//17 byte max length
  EEPROM.commit();
  /*85 byte saved in total?*/  
  Serial.println("everything saved...");
  yield();
  //get SSID max 32byte
  readEEPROM(0,32,wifi_ssid_private);
  //get PW max 32byte
  wifi_password_private = readEEPROM(32,32,wifi_password_private);
  //get clientName max 10byte
  wifi_password_private = readEEPROM(64,10,clientName);  
  //get ipAddr max 16byte
  wifi_password_private = readEEPROM(74,16,ipAddr);   
}

void loop() {
  // put your main code here, to run repeatedly:
  yield();
}
/*
examples/sources
http://forum.arduino.cc/index.php?topic=428836.0
https://gist.github.com/dogrocker/f998dde4dbac923c47c1
*/

Did you take a look at the examples that come with the ESP8266 core?
Store and read Wi-Fi credentials to/from EEPROM.

Pieter

P.s: you might be interested in my Beginner's guide to the ESP8266 as well.

Whats the data type of the ssid and password in the example?

Lots of information about the ESP in this beginners Guide, but im just intrested in my topic thanks.

JimmyPesto:
Whats the data type of the ssid and password in the example?

wifi_ssid_private and wifi_password_private are pointers to arrays of chars.

What's wrong with the Example I linked to in my previous post? Isn't that exactly what you are trying to do?

/** Load WLAN credentials from EEPROM */
void loadCredentials() {
  EEPROM.begin(512);
  EEPROM.get(0, ssid);
  EEPROM.get(0+sizeof(ssid), password);
  char ok[2+1];
  EEPROM.get(0+sizeof(ssid)+sizeof(password), ok);
  EEPROM.end();
  if (String(ok) != String("OK")) {
    ssid[0] = 0;
    password[0] = 0;
  }
  Serial.println("Recovered credentials:");
  Serial.println(ssid);
  Serial.println(strlen(password)>0?"********":"<no password>");
}

/** Store WLAN credentials to EEPROM */
void saveCredentials() {
  EEPROM.begin(512);
  EEPROM.put(0, ssid);
  EEPROM.put(0+sizeof(ssid), password);
  char ok[2+1] = "OK";
  EEPROM.put(0+sizeof(ssid)+sizeof(password), ok);
  EEPROM.commit();
  EEPROM.end();
}

Pieter

i know my own code, thanks for that.
whats the type of "ssid" and "password" in YOUR example.

I dont stop believing that here are some poeple who listen to my words and maybe can give a little advice.
So i found out that EEPROM.put/get suppose to work with objects.
Ive tried a little example but that didnt work.

back to my own code:

#include <EEPROM.h>

char wifi_ssid_private[32];
char wifi_password_private[32];
char clientName[10] = "newClient";
char ipAddr[16] = "172.024.001.001";//Pi Access Point IP-Adr.

//startAdr: offset (bytes), writeString: String to be written to EEPROM
void writeEEPROM(int startAdr, int laenge, char* writeString) {
  EEPROM.begin(512); //Max bytes of eeprom to use
  yield();
  Serial.println();
  //write to eeprom 
  Serial.println("writing eeprom:");
          for (int i = 0; i < laenge; i++)
            {
              EEPROM.write(startAdr + i, writeString[i]);
              Serial.print(writeString[i]);
            }
  EEPROM.commit();
  Serial.println(); 
  delay(10);
  Serial.println(char(EEPROM.read(startAdr)));
  EEPROM.end();           
}

void readEEPROM(int startAdr, int maxLength, char* dest) {
  Serial.println("Reading EEPROM");
  EEPROM.begin(512);
  delay(10);
  for (int i = 0; i < maxLength; i++)
    {
      *dest += char(EEPROM.read(startAdr + i));
      //if(dest[i]='\0') break;//break when end of sting is reached before maxLength
    }
  EEPROM.end();    
  //esid.trim();
  Serial.print("ready reading:");
  Serial.println(dest);
}
  
void setup() {
  Serial.begin(9600);
  delay(100);
  
  strcat(wifi_ssid_private, "SSID1234");
  strcat(wifi_password_private, "PW1234");

  writeEEPROM(0,32,wifi_ssid_private);//32 byte max length
  writeEEPROM(32,32, wifi_password_private);//32 byte max length
  //writeEEPROM(64,10, clientName);//10 byte max length
  //writeEEPROM(74,16, ipAddr);//16 byte max length
  /*85 byte saved in total?*/  
  Serial.println("everything saved...");
  readEEPROM(0,32,wifi_ssid_private);
  readEEPROM(32,32,wifi_password_private);
  //readEEPROM(64,10,clientName);
  //readEEPROM(74,16,ipAddr);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println("Loop");
  delay(1000);
  EEPROM.begin(512);
  Serial.println(char(EEPROM.read(0)));
  Serial.println(char(EEPROM.read(32)));
  EEPROM.end();
}

but Serial Monitor says:

writing eeprom:
SSID1234
S

writing eeprom:
PW1234
P
everything saved...
Reading EEPROM
ready reading:PSID1234
Reading EEPROM
ready reading:�W1234
Loop
S
P
Loop
S
P

Those "S"/"P"s are just to show that saving chars in EEPROM seems to work but always the first char i read with my read function is wrong.

EDIT:
changing this line of read function and it works great even fpr the first char in ssid and password:
    dest[i] = char(EEPROM.read(startAdr + i));
so dest += fucks up the first char
Does anyone know the reason?

JimmyPesto:
i know my own code, thanks for that.
whats the type of "ssid" and "password" in YOUR example.

It's not my example, it's from the ESP8266 Arduino Core. If you would have opened it, you'd know that ssid and password are normal null terminated character arrays as well:

char ssid[32] = "";
char password[32] = "";

JimmyPesto:
[...]

      *dest += char(EEPROM.read(startAdr + i));

[...]

Have you tried:

      dest[i] = char(EEPROM.read(startAdr + i));

Pieter

I thought you get that i was adressing you since no one else has posted anything.

The file youve linked was just those two functions no declaration of ssid and password. Okay you can find that in this github repo. more information on these eeprom functions

Funny that they used the same sice for ssid and password as me.

And yes, your idea is working great. Ive just tried that before you posted it.
Any idea what += does, so that the first char fails?

"dest" is a pointer to the character array. (The location of the first character of the array). "*dest" is the value that is stored at this location. It is the same as writing dest[0].

What your program was doing was just adding the read character to the first value of the string: it originally was the letter 'S', which is ASCII 83. Then it read the entire string, so adding the ASCII values of SSID1234: 83+83+83+73+68+49+50+51+52 = 592, you've only got one byte of data, so the most significant bits get cut off: 592 % 256 = 80 = ASCII 'P'.

All other characters were never changed by your read function, so they remained "SID1234".
That's because you were reusing "wifi_ssid_private" as "dest", so both of these variables are pointers to the same array, "SSID1234".

To change the other chars in the array, you have to index it using square brackets.

Pieter

Link1
Link2
OKay so its just working with Strings but not with char arrays?

Yes, a String is an object (note the capital S), and has an append operator. A char array on the other hand, is just that, an array of chars. The addition operator just adds values together.

Pieter

Okay that makes sense thanks :wink:

For everyone whos interested, heres my working code.
Note that i later get the ssid, pw etc via MQTT and my MQTT-Server already checked whether or not they are valid strings of the max length the arduino programm has allocated.

#include <EEPROM.h>

char wifi_ssid_private[32];
char wifi_password_private[32];
char clientName[10] = "newClient";
char ipAddr[16] = "172.024.001.001";//Pi Access Point IP-Adr.

//startAdr: offset (bytes), writeString: String to be written to EEPROM
void writeEEPROM(int startAdr, int laenge, char* writeString) {
  EEPROM.begin(512); //Max bytes of eeprom to use
  yield();
  Serial.println();
  Serial.print("writing EEPROM: ");
  //write to eeprom 
  for (int i = 0; i < laenge; i++)
    {
      EEPROM.write(startAdr + i, writeString[i]);
      Serial.print(writeString[i]);
    }
  EEPROM.commit();
  EEPROM.end();           
}

void readEEPROM(int startAdr, int maxLength, char* dest) {
  EEPROM.begin(512);
  delay(10);
  for (int i = 0; i < maxLength; i++)
    {
      dest[i] = char(EEPROM.read(startAdr + i));
    }
  EEPROM.end();    
  Serial.print("ready reading EEPROM:");
  Serial.println(dest);
}
  
void setup() {
  Serial.begin(9600);
  delay(100);
  
  strcat(wifi_ssid_private, "SSID1234");
  strcat(wifi_password_private, "PW1234");

  writeEEPROM(0,32,wifi_ssid_private);//32 byte max length
  writeEEPROM(32,32, wifi_password_private);//32 byte max length
  writeEEPROM(64,10, clientName);//10 byte max length
  writeEEPROM(74,16, ipAddr);//16 byte max length
  /*85 byte saved in total?*/  
  Serial.println("everything saved...");
  readEEPROM(0,32,wifi_ssid_private);
  readEEPROM(32,32,wifi_password_private);
  readEEPROM(64,10,clientName);
  readEEPROM(74,16,ipAddr);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println("Loop");
  delay(1000);
}

For posterity, you had an error in IF statement, from the beginning. #1 post

then you commented this line.

if (dest = '\ 0') break; // break when end of sting is reached before maxLength
only =
not ==
finally you clear dest
Regards.