ESP32 Save Data Permanently using Preferences Library

This guide shows how to save data permanently on the ESP32 flash memory using the Preferences.h library. The data held in the flash memory persists across resets or power failures. Using the Preferences.h library is useful to save data like network credentials, API keys, threshold values, or even the last state of a GPIO. You’ll learn how to save and read data from flash memory.

ESP32 Save Data Permanently using the Preferences Library

In this tutorial, we’ll cover the following topics:

Preferences.h Library

In a previous tutorial, we recommended using the EEPROM library to save data on flash memory. However, the EEPROM library is deprecated in favor of the Preferences.h library. This library is “installed” automatically when you install the ESP32 boards in your Arduino IDE.

The Preferences.h library is preferably used to store variable values through key:value pairs. Saving data permanently can be important to:

  • remember the last state of a variable;
  • save settings;
  • save how many times an appliance was activated;
  • or any other data type you need to save permanently.

If, instead of variables, you need to save files on the ESP32, we recommend using the filesystem (SPIFFS) instead. To learn how to save files in the ESP32 filesystem, you can read one of the following tutorials:

Save Data Using Preferences.h Library

The data saved using preferences is structured like this:

namespace {
  key:value
}

You can save different keys on the same namespace, for example:

namespace {
  key1: value1
  key2: value2
}

In a practical example, this configuration could be used to save your network credentials:

credentials {
  ssid: "your_ssid"
  pass: "your_pass"
}

In the preceding example, credentials is the namespace, and ssid and pass are the keys.

You can also have multiple namespaces with the same key (but each key with its value):

namespace1{
  key:value1
}
namespace2{
  key:value2
}

When using the Preferences.h library, you should define the data type you want to save. Later, if you want to read that data, you must know the saved data type. In other words, the data type of writing and reading should be the same.

You can save the following data types using Preferences.h: char, Uchar, short, Ushort, int, Uint, long, Ulong, long64, Ulong64, float, double, bool, string and bytes.

For more information, you can access the Preferences.cpp file here.

Preferences.h Library Useful Functions

To use the Preferences.h library to store data, first you need to include it in your sketch:

#include <Preferences.h>

Then, you must initiate an instance of the Preferences library. You can call it preferences, for example:

Preferences preferences;

After this, you can use the following methods to handle data using the Preferences.h library.

Start Preferences

The begin() method opens a “storage space” with a defined namespace. The false argument means that we’ll use it in read/write mode. Use true to open or create the namespace in read-only mode.

preferences.begin("my-app", false); 

In this case, the namespace name is my-app. Namespace name is limited to 15 characters.

Clear Preferences

Use clear() to clear all preferences under the opened namespace (it doesn’t delete the namespace):

preferences.clear();

Remove Key

Remove a key from the opened namespace:

preferences.remove(key);

Close Preferences

Use the end() method to close the preferences under the opened namespace:

preferences.end();

Put a Key Value (Save a value)

You should use different methods depending on the variable type you want to save.

CharputChar(const char* key, int8_t value)
Unsigned CharputUChar(const char* key, int8_t value)
ShortputShort(const char* key, int16_t value)
Unsigned ShortputUShort(const char* key, uint16_t value)
IntputInt(const char* key, int32_t value)
Unsigned IntputUInt(const char* key, uint32_t value)
LongputLong(const char* key, int32_t value)
Unsigned LongputULong(const char* key, uint32_t value)
Long64putLong64(const char* key, int64_t value)
Unsigned Long64putULong64(const char* key, uint64_t value)
FloatputFloat(const char* key, const float_t value)
DoubleputDouble(const char* key, const double_t value)
BoolputBool(const char* key, const bool value)
StringputString(const char* key, const String value)
BytesputBytes(const char* key, const void* value, size_t len)

Get a Key Value (Read Value)

Similarly, you should use different methods depending on the variable type you want to get.

ChargetChar(const char* key, const int8_t defaultValue)
Unsigned ChargetUChar(const char* key, const uint8_t defaultValue)
ShortgetShort(const char* key, const int16_t defaultValue
Unsigned ShortgetUShort(const char* key, const uint16_t defaultValue)
IntgetInt(const char* key, const int32_t defaultValue)
Unsigned IntgetUInt(const char* key, const uint32_t defaultValue)
LonggetLong(const char* key, const int32_t defaultValue)
Unsigned LonggetULong(const char* key, const uint32_t defaultValue)
Long64getLong64(const char* key, const int64_t defaultValue)
Unsigned Long64gettULong64(const char* key, const uint64_t defaultValue)
FloatgetFloat(const char* key, const float_t defaultValue)
DoublegetDouble(const char* key, const double_t defaultValue)
BoolgetBool(const char* key, const bool defaultValue)
StringgetString(const char* key, const String defaultValue)
StringgetString(const char* key, char* value, const size_t maxLen)
BytesgetBytes(const char* key, void * buf, size_t maxLen)

Remove a Namespace

In the Arduino implementation of Preferences, there is no method of completely removing a namespace. As a result, over the course of several projects, the ESP32 non-volatile storage (nvs) Preferences partition may become full. To completely erase and reformat the NVS memory used by Preferences, create a sketch that contains:

#include <nvs_flash.h>

void setup() {
  nvs_flash_erase(); // erase the NVS partition and...
  nvs_flash_init(); // initialize the NVS partition.
  while(true);
}

void loop() {

}

You should download a new sketch to your board immediately after running the above, or it will reformat the NVS partition every time it is powered up.

Preferences.h – Save key:value Pairs

For a simple example on how to save and get data using Preferences.h, in your Arduino IDE, go to File > Examples > Preferences > StartCounter.

/*
 ESP32 startup counter example with Preferences library.

 This simple example demonstrates using the Preferences library to store how many times the ESP32 module has booted. 
 The Preferences library is a wrapper around the Non-volatile storage on ESP32 processor.

 created for arduino-esp32 09 Feb 2017 by Martin Sloup (Arcao)
 
 Complete project details at https://RandomNerdTutorials.com/esp32-save-data-permanently-preferences/
*/

#include <Preferences.h>

Preferences preferences;

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

  // Open Preferences with my-app namespace. Each application module, library, etc
  // has to use a namespace name to prevent key name collisions. We will open storage in
  // RW-mode (second parameter has to be false).
  // Note: Namespace name is limited to 15 chars.
  preferences.begin("my-app", false);

  // Remove all preferences under the opened namespace
  //preferences.clear();

  // Or remove the counter key only
  //preferences.remove("counter");

  // Get the counter value, if the key does not exist, return a default value of 0
  // Note: Key name is limited to 15 chars.
  unsigned int counter = preferences.getUInt("counter", 0);

  // Increase counter by 1
  counter++;

  // Print the counter to Serial Monitor
  Serial.printf("Current counter value: %u\n", counter);

  // Store the counter to the Preferences
  preferences.putUInt("counter", counter);

  // Close the Preferences
  preferences.end();

  // Wait 10 seconds
  Serial.println("Restarting in 10 seconds...");
  delay(10000);

  // Restart ESP
  ESP.restart();
}

void loop() {

}

View raw code

This example increases a variable called counter between resets. This illustrates that the ESP32 “remembers” the value even after a reset.

Upload the previous sketch to your ESP32 board. Open the Serial Monitor at a baud rate of 115200 and press the on-board RST button. You should see the counter variable increasing between resets.

ESP32 Preferences StartCounter Example Serial Monitor

How the Code Works

This example uses the functions we’ve seen in the previous sections.

First, include the Preferences.h library.

#include <Preferences.h>

Then, create an instance of the library called preferences.

Preferences preferences;

In the setup(), initialize the Serial Monitor at a baud rate of 115200.

Serial.begin(115200);

Create a “storage space” in the flash memory called my-app in read/write mode. You can give it any other name.

preferences.begin("my-app", false);

Get the value of the counter key saved on preferences. If it doesn’t find any value, it returns 0 by default (which happens when this code runs for the first time).

unsigned int counter = preferences.getUInt("counter", 0);

The counter variable is increased one unit every time the ESP runs:

counter++;

Print the value of the counter variable:

Serial.printf("Current counter value: %u\n", counter);

Store the new value on the “counter” key:

preferences.putUInt("counter", counter);

Close the Preferences.

preferences.end();

Finally, restart the ESP32 board:

ESP.restart();

ESP32 – Save/Read Network Credentials using the Preferences.h Library

The Preferences.h library is many times used to save your network credentials permanently on the flash memory. This way, you don’t have to hard code the credentials in every sketch that involves connecting the ESP32 to the internet.

In this section, we’ll show you two simple sketches that might be useful in your projects:

To learn more about ESP32 Wi-Fi related functions, read the following article:

Save Network Credentials using Preferences.h

The following sketch saves your network credentials permanently on the ESP32 flash memory using Preferences.h.

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-save-data-permanently-preferences/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <Preferences.h>

Preferences preferences;

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

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

  preferences.begin("credentials", false);
  preferences.putString("ssid", ssid); 
  preferences.putString("password", password);

  Serial.println("Network Credentials Saved using Preferences");

  preferences.end();
}

void loop() {

}

View raw code

Don’t forget to insert your network credentials in the following variables:

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

How the Code Works

Let’s take a quick look at the relevant parts of the code for this example.

In the setup(), create a new storage space on the flash memory with the credentials namespace.

preferences.begin("credentials", false);

Then, create a key called ssid that saves your SSID value (ssid variable) – use the putString() method.

preferences.putString("ssid", ssid); 

Add another key called password to save the password value (password variable):

preferences.putString("password", password);

So, your data is structured in this way:

credentials{
  ssid: your_ssid
  password: your_password
}

Upload the code to your board and this is what you should get on the Serial Monitor:

ESP32 Save Network Credentials using Preferences Library

In the following example, we’ll show you how to read the network credentials from preferences and use them to connect the ESP32 to your network.

Connect to Wi-Fi with Network Credentials Saved on Preferences

The following sketch gets the network credentials’ values and connects to your network using those credentials.

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-save-data-permanently-preferences/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <Preferences.h>
#include "WiFi.h"

Preferences preferences;

String ssid;
String password;

void setup() {
  Serial.begin(115200);
  Serial.println();
  
  preferences.begin("credentials", false);
 
  ssid = preferences.getString("ssid", ""); 
  password = preferences.getString("password", "");

  if (ssid == "" || password == ""){
    Serial.println("No values saved for ssid or password");
  }
  else {
    // Connect to Wi-Fi
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid.c_str(), password.c_str());
    Serial.print("Connecting to WiFi ..");
    while (WiFi.status() != WL_CONNECTED) {
      Serial.print('.');
      delay(1000);
    }
    Serial.println(WiFi.localIP());  
  }
}

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

View raw code

How the Code Works

Let’s take a quick look at the relevant parts of the code for this example.

Open the credentials namespace:

preferences.begin("credentials", false);

Get the SSID and password values using the getString() method. You need to use the key name that you used to save the variables, in this case, ssid and password keys:

ssid = preferences.getString("ssid", ""); 
password = preferences.getString("password", "");

As a second argument to the getString() function, we passed an empty String. This is the returned value in case there aren’t ssid or password keys saved on preferences.

If that’s the case, we print a message indicating that there aren’t any saved values:

if (ssid == "" || password == ""){
  Serial.println("No values saved for ssid or password");
}

Otherwise, we connect to Wi-Fi using the SSID and password saved on preferences.

else {
  // Connect to Wi-Fi
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid.c_str(), password.c_str());
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

Upload this code to your board after the previous one (to ensure that you have the credentials saved). If everything goes as expected, this is what you should get on your Serial Monitor.

ESP32 Connect to Network with Credentials Saved on Preferences

Remember Last GPIO State After RESET

Another application of the Preferences.h library is to save the last state of an output. For example, imagine the following scenario:

  1. You’re controlling an output with the ESP32;
  2. You set your output to turn on;
  3. The ESP32 suddenly loses power;
  4. When the power comes back on, the output stays off – because it didn’t keep its last state.
ESP32 Preferences Library Remember Last GPIO State (without preferences)

You don’t want this to happen. You want the ESP32 to remember what was happening before losing power and return to the last state.

To solve this problem, you can save the lamp’s state in the flash memory. Then, you need to add a condition at the beginning of your sketch to check the last lamp state and turn the lamp on or off accordingly.

The following figure shows what we’re going to do:

ESP32 Preferences Library Remember Last GPIO State

We’ll show you an example using an LED and a pushbutton. The pushbutton controls the LED state. The LED keeps its state between resets. This means that if the LED is lit when you remove power, it will be lit when it gets powered again.

Schematic Diagram

Wire a pushbutton and an LED to the ESP32 as shown in the following schematic diagram.

ESP32 Schematics diagram circuit LED output pushbutton input

Recommended reading: ESP32 Pinout Reference: Which GPIO pins should you use?

Code

This is a debounce code that changes the LED state every time you press the pushbutton. But there’s something special about this code – it remembers the last LED state, even after resetting or removing power from the ESP32. This is possible because we save the led state on Preferences whenever it changes.

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-save-data-permanently-preferences/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <Preferences.h>

Preferences preferences;

const int buttonPin = 4;    
const int ledPin = 5;      

bool ledState;         
bool buttonState;             
int lastButtonState = LOW;

unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

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

  //Create a namespace called "gpio"
  preferences.begin("gpio", false);

  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);

  // read the last LED state from flash memory
  ledState = preferences.getBool("state", false); 
  Serial.printf("LED state before reset: %d \n", ledState);
  // set the LED to the last stored state
  digitalWrite(ledPin, ledState);
}

void loop() {
  int reading = digitalRead(buttonPin);

  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }
  lastButtonState = reading;
  if (digitalRead(ledPin)!= ledState) {  
    Serial.println("State changed");
    // change the LED state
    digitalWrite(ledPin, ledState);
    
    // save the LED state in flash memory
    preferences.putBool("state", ledState);
    
    Serial.printf("State saved: %d \n", ledState);
  }
}

View raw code

How the Code Works

Let’s take a quick look at the relevant parts of code for this example.

In the setup(), start by creating a section in the flash memory to save the GPIO state. In this example, we’ve called it gpio.

preferences.begin("gpio", false);

Get the GPIO state saved on Preferences on the state key. It is a boolean variable, so use the getBool() function. If there isn’t any state key yet (which happens when the ESP32 first runs), return false (the LED will be off).

ledState = preferences.getBool("state", false); 

Print the state and set the LED to the right state:

Serial.printf("LED state before reset: %d \n", ledState);
// set the LED to the last stored state
digitalWrite(ledPin, ledState);

Finally, in the loop() update the state key on Preferences whenever there’s a change.

// save the LED state in flash memory
preferences.putBool("state", ledState);

Serial.printf("State saved: %d \n", ledState);

Demonstration

Upload the code to your board and wire the circuit. Open the Serial Monitor at a baud rate of 115200 and press the on-board RST button.

Press the pushbutton to change the LED state and then remove power or press the RST button.

ESP32 Schematics diagram circuit LED output pushbutton input demonstration testing

When the ESP32 restarts, it will read the last state saved on Preferences and set the LED to that state. It also prints a message on the Serial Monitor whenever there’s a change on the GPIO state.

ESP32 Remember Last LED State Preferences

Wrapping Up

In this tutorial, you’ve learned how to save data permanently on the ESP32 flash memory using the Preferences.h library. This library is handy to save key:value pairs. Data held on the flash memory remains there even after resetting the ESP32 or removing power.

If you need to store bigger amounts of data or files, you should use the ESP32 filesystem (SPIFFS) or a microSD card instead:

We hope you’ve found this tutorial useful.

Learn more about the ESP32 with our resources:



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Recommended Resources

Build a Home Automation System from Scratch » With Raspberry Pi, ESP8266, Arduino, and Node-RED.

Home Automation using ESP8266 eBook and video course » Build IoT and home automation projects.

Arduino Step-by-Step Projects » Build 25 Arduino projects with our course, even with no prior experience!

What to Read Next…


Enjoyed this project? Stay updated by subscribing our newsletter!

97 thoughts on “ESP32 Save Data Permanently using Preferences Library”

  1. Hi Rui and all,
    First, good post! A clear explanation of Preferences and how to use them (especially when preserving WiFi credentials, ESP-NOW node ID information, and so on).
    I used Preferences in a large ESP32 project a while back. It is useful if you have a small’ish number of data items that need to be stored.
    However, I had around a half-dozen or so larger structures, each with a dozen or more fields. I maintained the half-dozen or so keys, using putBytes/getBytes to save/restore data.
    As the project grew, this became cumbersome. New versions of the project had additional data, and I could not use Preferences to maintain stored-data integrity as I moved to new versions (with the larger data blobs). I eventually switched over to SPIFFS and ArduinoJSON. This way, newer code could autodetect missing data, supply defaults, and then save the updated JSON data for later runs.
    For simpler projects, Preferences works well. For larger projects, RandomNerd readers may wish to look into SPIFFS/JSON as a more flexible alternative.
    -Steve

    Reply
    • Hi Steve.
      Thanks for your comment.
      That’s right. Preferences is good to save a small number of values.
      If you need to save huge amounts of data, it is preferable to create a file in SPIFFS and use JSON.
      Thanks for following our work.
      Regards,
      Sara

      Reply
      • how much should be the size of the data for storing user preferences? How many variables can be stored? How many times can I store (write) the data using preference?

        Reply
  2. With EEPROM, we know how much space was allotted. I think it was 500 bytes or 1K. Then, we specified how memory memory we needed. That gave confidence we would not overrun the space and screw up something else, like our program. Is there any such protection with Preferences? What if we save 1000 variables (exaggeration, of course)?

    Reply
  3. Nice tutorial. I hadn’t heard of Preferences.h. It is a wrapper on the Espressif NVS API, which has a few more features. The NVS documentation has a good explanation of how this works: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/storage/nvs_flash.html

    NVS is optimized to store a set of key:value pairs grouped by namespace, and written into flash by appending in 4096 byte pages. When a new value is written the prior value is marked deleted, and new value appended. This way it doesn’t wear out the flash. A RAM hash table helps search for entries (128-640 bytes of RAM per 4096 byte flash page). It’s mainly intended for short values.

    The main difference between Preferences.h and the NVS api is an automatic commit for each write and has error checking and logging. That doesn’t seem to be explained in the Preferences.h file.

    I also just learned about the Arduino error logging, log_e()..log_v(), used by Preferences.cpp. Rui & Sara maybe that would make a nice additional tutorial to explain how logging works and how to control the level selected at compile time. It seems nontrivial, since stdout can be redefined and selecting log levels is slightly different in PlatformIO than basic Arduino IDE.

    Note you can still use JSON with the NVS, storing the JSON as a string or blob. I haven’t figured out the SPIFFS format, but depending on the JSON size, partition sizes, and write frequency, NVS could be better. [Note you can also select the partition in the begin().] NVS writes 32 byte chunks vs 256 byte pages with SPIFFS. Both wear level across 4096 byte blocks in the partition.

    Reply
  4. Hi.

    As usual another nice tutorial was born. Thank you Sara & Rui for your efforts and for the space you provide here for all of us.

    I like key-value access way on this library. I like the automatic variable type recognition, background eeprom addressing. All it’s methods seem simple and useful. But what more about very frequent writes?

    Someone may be concerned about the life and durability of the flash. There are very frequent writes to “eeprom” required also in my projects. Maybe I don’t understand well and maybe I am not alone, so let me have a few questions.

    Carl, you said “This way it doesn’t wear out the flash.” But how is it possible, when there is a commit after each write?

    Carl, did you you mean that the commit will be done only and only on the “4096 byte flash page” (meaning namespace?) and not on the whole partition from the namespace comes? If so, would it be enough to separate commit (remove commit from every write method) and execute it separately? I am not very sure how Preferences lib (nvm.h) shares flash partition.

    The problem of memory life can be solved by rotating partitions using EEPROM32_Rotate library by Xose Péres. Details here https://tinkerman.cat/post/eeprom-rotation-for-esp8266-and-esp32/
    Unfortunately this nice library as it is, despite that it shares same library (nvs.h), it does not allow key-value access. Also it does not support automatic variable type recognition, does not support background addressing in flash space and so on. Please correct me if I am wrong … On the other side this library inherits all well known methods from famous standard library EEPROM.h. And very imortant for me is, that there the commit method may be called once after all data have been prepared previously (written in buffer). So this way does not wear out the flash, because each additional commit reduces it’s life.

    In this sense back to Preferences library.
    Is it possible to consider each open namespace in Preference as a “partition” on which and only which a commit will be performed? If so, memory wear out can be solved by using multiple namespaces and by switching (rotating) between them.

    I am not sure if it works this way. Can anyone answer that, please?

    Reply
  5. I great tutorial for the ESP32. However, because of it’s very small size, I use Node Mini ESP8266 quite often. Does Preferences work on ESP8266?

    Thx, and keep up the great work,
    P

    Reply
  6. How would you use this to store an array of values? It will be 30 x int’s of values between 1 and 500 (approx) that over a period of 30 days each value gets updated/replaced to create a “last 30 days” average?

    Reply
    • If you have ‘int myArr[30]’, you can use ‘myPrefs.putBytes(“tag”, myArr, 30*sizeof(int))’.

      I usually use a typedef for the array, and just use sizeof(theType) instead of the 30*sizeof(int).

      Reply
      • Thank you Steve,
        I’ve got a bit of learning / testing to do to see if I can get this to work. Very much appreciate your guidance.

        I used tinkercad to figure out how to do a “run-once” when the first usage sample is calculated which then populates the averaging array thereafter we step along the array each write and update.

        This does create a new question though, if after the first full set of array usage values and have a complete 30 day average and want to store that as a historical value would it be better to do all the storage in “SPIFFS” or do the averaging in “Preferences” and the logging in “SPIFFS”?

        Cheers

        Reply
        • Hi Ralph,

          I don’t think you can use SPIFFS and Preferences at the same time. I haven’t examined the driver code, but I imagine they read/write raw(ish) flash blocks. (Same with FATFS vs SPIFFS, both use the raw flash space.)

          That’s why I moved to SPIFFS from Preferences for the near term. I may move to FAT at some point, but at least the API is the same!

          Does your node have WiFi access? If so, you can connect, grab the date from an NTP server, and use this to construct the archival filenames under SPIFFS or FAT (at least as far as filename length restrictions). If you’ve done this, you can also set up the real time clock on the ESP as well, should you need to timestamp the datapoints in the data file.

          -Steve

          Reply
          • Sorry Steve, I missed your reply for some reason and I’ve been sidetracked with other things so my progress stopped for a while. Back to it now though………………. After some investigating I found out why no reply, my bad. Should be OK now.

            As you have probably already gathered I’m just a hobbyist and am self learning so sometimes things take me a while to understand.

            Thanks for the compatibility warning.

            Yes I already have NTP running on a weather prediction node that has been running for some time now to debug the modifications I did to the original sketch. The goal is to pass outdoor temp/humidity/water tank level data sent from remote remote node. It’s the remote node where I want to save the array. The remote node will be run taking advantage of “Deep Sleep” power saving and I was thinking of getting it running as a stand-alone “Blynk” instance first to aid development hence the need to save the array. I’ve already got the “Blynk” side running just not with the array and “Deep Sleep”.

            Right or wrong I find it easier to work things out by building in modules and then when each works reliably I combine them.

            Cheers
            Ralph

  7. Hii,
    is it possible to replace “state” in below line with var?
    I try to make recursive routine to get some key
    ex: “state”+ String(i),
    I try but still fail

    ledState = preferences.getBool(“state”, false);

    Reply
      • I am sorry Sara,
        I want to read the bool value from key in namespace.

        bool a;
        for (int x = 1; x < 4 ;x++){
        a = preferences.getBool(“Var_A” + String(x), false);
        Serial.Println(a);
        }

        the will give the read value
        Var_A1
        Var_A2
        Var_A3
        Var_A4

        Reply
        • Hi Sara,
          I already found the solution, thanks for the good tutorial

          for (int x = 1; x < DO_n+1;x++){
          a = preferences.getBool(("AM_S_CH"+String(x)).c_str(), false);
          b = preferences.getBool(("AM_C_CH"+String(x)).c_str(), false);
          c = preferences.getBool(("SCH_"+String(preferences.getInt(("SCH_CH"+String(x)+"_D"+String(c_day)).c_str()))).c_str(), false);
          d = preferences.getBool(("DI1_En_CH"+String(x)).c_str(), false);
          e = preferences.getBool(("DI2_En_CH"+String(x)).c_str(), false);
          f = preferences.getBool(("DI3_En_CH"+String(x)).c_str(), false);

          Reply
          • Hi. Might be a couple of things to check. Outside of this snippet, I’ll assume the namespace was opened with a preferences.begin("namespace", true); statement? Also assuming this namespace has keys created elsewhere that match the descriptions in your statements a = thought to f =?

            When using the preferences.getXXX("keyname", default); form, default is returned if "keyname" does not exist in the currently opened namespace. If you’re sure "keyname" exists, use the preferences.getXXX("keyname"); form.

            Also, keynames are limited to 13 characters maximum. The assignment for c = above might be problematic in that regard.

            There is a pretty detailed explanation in this comment above: https://randomnerdtutorials.com/esp32-save-data-permanently-preferences/#comment-566327

  8. Dear Xylopyrographer,
    the preferences.begin(“namespace”, true); already define above ,
    I just copy some off code,

    thanks for the explanation,

    by the way,
    – is there any way to list/print the available namespace and keys ?
    – and is there any keys limit number we can create?

    Reply
    • It looks like there is a way to list what is in a namespace. That facility isn’t supported in the ESP32 Arduino Preferences implementation but is available using the ESP32 function calls directly. See:
      https://docs.espressif.com/projects/esp-idf/en/release-v4.1/api-reference/storage/nvs_flash.html

      and look near the bottom of that page for the nvs_entry_find() method.

      If I recall the default NVS partition is made up of 4 pages of 4096 bytes each. So that makes about 16k of NVS storage available. This is the limit, not really the number of entries. From that same link, there are the methods that can be used to determine the amount of NVS available.

      In your sketch,

      #include nvs.h
      #include nvs_flash.h

      and you’ll be able to access these methods.

      Reply
      • I try to write 1440 keys with bool type
        but only 500 can be write, then the nvs become hang, cannot write anything, should be format again.
        with i = 1440, is there any other method to store so much keys, >?

        for (int x = 0;x < i;x++){
        Serial.print(“Address : “);
        Serial.print(x);
        Serial.print(” Tags : “);
        Serial.print(“SCH_”+b+”“+String(g+x));
        Serial.print(” yang ditulis : “);
        Serial.println(j);
        preferences.putBool((“SCH
        “+b+”_”+String(g+x)).c_str(),j);
        }
        preferences.end();//Close the Preferences.
        Serial.println(“jadwal berhasil diupdate”);}

        Reply
        • I’d suggest taking a look at this line:

          preferences.putBool((“SCH“+b+”_”+String(g+x)).c_str(),j);

          A namespace key can be a maximum of 15 characters. Is there a chance this could cause that limit to be exceeded? The .putX(); functions will fail if passed a key name longer than 15 characters. (The fail is graceful–writing an entry to the log. The function call returns 0. No value is written.)

          Are all the key names created before the sketch tries to write to them?

          If that isn’t an issue, would suggest writing a test sketch that creates a namespace and then creates the 1440 key names, and then populates them but in a simple format like:

          "A" + String(i)

          so that it’s certain that the 15 character limit won’t be exceeded.

          You could also:

          test the return value after doing a preferences.putBool(). That set of functions returns 0 if the write failed or 1 if successful.
          test the length of the key name to ensure its length is no greater than 15 characters before attempting to do a put.

          Bool’s are written to NVS as uint8_t data type. You could use that t odd a bit of math on the space required for your values.

          Hope that helps.

          Reply
  9. When should I use preferences.end()? There were examples that this command was used and in other examples it was not used.

    Reply
    • Hi Eduardo.
      It is mandatory to call preferences.end(), if you want to open preferences on a different namespace than the previously open namespace.
      Regards,
      Sara

      Reply
  10. I hope I can still use the EEPROM library, I only need to save an array of byte data, this seems far more complex?? (new ESP32 used from Arduino Nano)

    Reply
  11. I gave this a good go last night, could not get it to work…. it compiled fine, but nothing was ever saved. It was only a single byte value I needed saved – lucky that old EEPROM library still works a treat, 5 minutes later all was how I wanted it….

    Reply
  12. Wow just wow great tutorial. i am trying to get the following to work but to no avail. I’m new to Arduino esp32. i am trying to save the state of 7 GPIOs every time getOutputStates() is called
    I am having problems getting the following line to work and not sure how to get it going

    putInt(String(outputGPIOs[i]), int32_t String(digitalRead(outputGPIOs[i])));

    String getOutputStates() {
    JSONVar myArray;
    for (int i = 0; i < NUM_OUTPUTS; i++) {
    myArray[“gpios”][i][“output”] = String(outputGPIOs[i]);

    myArray["gpios"][i]["state"] = String(digitalRead(outputGPIOs[i]));
    Serial.println(String(outputGPIOs[i]) + "=" + String(digitalRead(outputGPIOs[i])));

    putInt(String(outputGPIOs[i]), int32_t String(digitalRead(outputGPIOs[i])));

    //preferences.putBool("state", String(digitalRead(outputGPIOs[i])));

    }

    i get the following error:

    exit status 1
    invalid conversion from ‘int’ to ‘const char*’ [-fpermissive]

    Thank you

    Reply
    • i noticed i cut off preferences. on a couple of lines:

      String getOutputStates() {
      JSONVar myArray;
      for (int i = 0; i < NUM_OUTPUTS; i++) {
      myArray[“gpios”][i][“output”] = String(outputGPIOs[i]);

      myArray[“gpios”][i][“state”] = String(digitalRead(outputGPIOs[i]));
      Serial.println(String(outputGPIOs[i]) + “=” + String(digitalRead(outputGPIOs[i])));

      preferences.putInt(int(outputGPIOs[i]), int32_t (digitalRead(outputGPIOs[i])));

      //preferences.putBool("state", String(digitalRead(outputGPIOs[i])));

      }

      Reply
      • Hi Mark,
        I had the same struggles composing the complex statements. I wanted to build a 30 day averaging array and store an incrementing index value, last sensor read value and the array[30]. The reason to work this way is the use of “Deep Sleep” mode.

        Being a self learning hacker (no formal training) and tinkerer I did a fair bit of research and realized it would be far better to use “SPIFFS” with an abstract layer helper library and stay away from the use of “JSONVar” which can lead to memory leakage issues (or so I read)

        I created an example that uses “daily” random values simulating 22500lts as a full water tank and each reading reduces by what would be a “daily use” and is put into the array[10] to get the average use value. Obviously the array size can be anything you want. Example sketch here https://pastebin.com/jPG5cXBk

        Note: Use the “SPIFFS” format sketch on this site to start over and I discovered even with this you’ll get an incorrect first value so I used the “clear()” class to get round that. You can use “esptool.py” and do an “erase_flash” which will zero the flash but you must do a “SPIFFS format” before loading a new sketch or it will error.

        Hope this helps
        Cheers
        Ralph

        Reply
  13. Ralph,

    Thanks for the pointers. i think i have figured out. the “key” in preferences has to be char can not be any other type.

    I am using SPIFFS for the web stuff to turn on and off the relays manually and set the schedule on and off times for each relay using an RTC.

    I’m not concerned about memory leakage as the eps will be reset every night at midnight. now that i have the preferences working.

    Thanks
    Mark

    Reply
  14. Hi, Im looking for some guidance on getting the preferences library to store the mqtt server for the arduino PubSubClient. I can store wifi ssid, password, mqtt username and password, but I cant figure out how to get the server name stored. Tried as a string value and char value in the preferences library. Anyone out there have a suggestion? i an getting the name of the server (likely the IP address) from a text box on a nextion display then hoping to use the settings to connect to mqtt server. Ive tried converting the string value to a char, etc.. c_str() just cant seem to figure out how to get it to work!
    in my setup i try to get the server name like so:

    (THIS IS JUST THE LASTEST TEST – THIS CODE HAS BEEN WORKED OVER MANY TIMES TRYING TO USE CHAR RATHER THAN STRING, ETC..)

    String mqttserver=”192.168.1.45″;
    String mqttuser= “admin”;
    String mqttpass = “123456”;

    PubSubClient client(mqttserver, 1883, callback, wifiClient); //THIS FAILS
    //PubSubClient client(“192.168.0.45″, 1883, callback, wifiClient); //THIS WORKS FINE

    String Wifissid=”Mango-2.4″;
    String Wifipass=”32012345678”;

    setup() {
    preferences.begin(“myapp”, false);

    preferences.putString(“mqttserver”, mqttserver);
    preferences.putString(“mqttuser”, mqttuser);
    preferences.putString(“mqttpass”, mqttpass);
    preferences.putString(“wifissid”, Wifissid);
    preferences.putString(“wifipass”, Wifipass);

    WiFi.disconnect();
    String p_ssid = preferences.getString(“wifissid”,””);
    String p_pass = preferences.getString(“wifipass”, “”);

    WiFi.begin(p_ssid.c_str(),p_pass.c_str());

    Serial.print(“Connecting to WiFi ..”);

    uint32_t moment=millis();
    while ((WiFi.status()!=WL_CONNECTED) && (millis()-moment<8000)) { // make sure to do a timeout in
    // case of incorrect details to prevent eternal loop
    Serial.print(“.”);
    delay(100); // or yield(); (delay() includes a yield();)
    }

    if (WiFi.status() == WL_CONNECTED) {
    Serial.println(‘Connected’);
    Serial.println(WiFi.localIP());
    Serial.println(mqttserver);
    Serial.println(mqttuser.c_str());
    Serial.println(mqttpass.c_str());
    //PubSubClient client(*mqttserver, 1883, callback, wifiClient);
    }

    //TRYING TO OVERRIDE THE INITIAL DEFINITION HERE
    //const char *mqserver = preferences.getString(“mqttserver”,””).c_str();
    // client.setServer(“192.168.0.45”,1883);
    String mqs = preferences.getString(“mqttserver”,””);
    client.setServer(mqs, 1883);

    }

    Reply
  15. ola, estou tentando atualizar uma chave no preferences pelo webserver. Porem nao consigo fazer o putString dentro do server.on, quando faço a chamada via GET.

    //– ATIVA/DESATIVA (MR1)
    server.on(“/ativaMR1”, HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, “text/html”);
    jso.putString(“teste”, jesio);
    Serial.println();
    Serial.println(“SOLICITAÇÃO OK: ATIVAR (MR1)”);
    Serial.println();
    });

    Pode me ajudar?

    att

    Reply
    • Hi.
      You have to run that command outside of the server.on function.
      Instead, you should have a flag variable that will change its value when it receives that request.
      Then, in the loop(), check that the value of that variable, and if that’s the case, call the putString function.
      I hope this helps.
      Regards,
      Sara

      Reply
  16. Hello,
    I have a problem with preferences.
    I am making an esp ap, with an web interface to change some settiings.
    One of the settings is to change the wifi channel.
    To change the channel I have a dropdown on the interface which changes the index of the url (like: 192.168.4.1/Channel/1)(which works). Then I am getting the index and comparing them in a function and if it’s a special index the preferences get changed with a value
    (like: if (header.indexOf(“GET /Channel/1”) >= 0) { preferences.putInt(“channel”, 1); }) (this works either). But if the value is 10 and over it just takes the 1 and saves it.
    The “channel” preferences is an integer.

    I hope this should be enough and it doesn’t sound too confusing.

    best regards
    Andreas

    Reply
    • Hi.
      The issue that you’re facing is normal because the indexOf locates a string within another string. So, it will find the “1” if you have “10” “11” “1111” and so on.
      So, the best way to do this is to get the number after the last “/”.
      First, locate the last “/” position—you can use the lastIndexOf() function: https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/lastindexof/
      int lastSlash = header.lastIndexOf(“/”);
      Then, calculate the string size:
      int stringLen = header.length()
      And then cut the string to get the number:
      channel = header.subString(lastSlash+1, stringLen);
      I hope this helps.
      Regards,
      Sara

      Reply
      • Heii,
        I’ve tried what you said put I don’t really understand how this works or should work.
        I used indexOf before even with numbers higher than 9 and it worked.
        I don’t want to get the number after the last slash, I just want to check if the header index matches what I have in the if.
        Example:
        if (header.indexOf(“GET /ChannelSet/1”) >= 0)
        {
        preferences.putInt(“channel”, 1);
        }
        else if (header.indexOf(“GET /ChannelSet/2”) >= 0)
        {
        preferences.putInt(“channel”, 2);
        }

        else if (header.indexOf(“GET /ChannelSet/13”) >= 0)
        {
        preferences.putInt(“channel”, 13);
        }
        (I know I could make this somehow shorter but it just has to work, memory and speed is not important, and I’m kinda lazy)

        I used the same for signal strength with numbers like 19, 17 and it works the only difference is the type. I save it as an string (preferences.putString(“outputStateStr”, “18”)) instead of an integer.

        Maybe I don’t understand how the indexOf works, but I don’t know what I’m doing wrong or right.
        Sry if this is annoying.

        Regards,
        Andreas

        Reply
  17. Thank you for this great article comming from PIC with eeprom,
    I have one question regarding the “preferences.end” statement. For me it is not clear when to use that statement. Even with the help of de posting Xylopyrographer did on March 4, i am not sure when to use it.
    Thank you for your time,
    Eric

    Reply
    • Hi Eric. Best answer is, every time your app finishes writing or reading data using the Preferences library, it should use a “preferences.end” to safely close the NVS and to release the preferences object. This ensures the NVS is in a good state and it also releases system memory back to the pool. So sequence would be preferences.begin –> put or get your data –> preferences.end

      Reply
  18. I want to comment on a – in my opinion very bad habit regarding naming objects –
    I think it’s a really bad habit to name an object with a similar name than the library-filename.
    In this tutorial it is
    Preferences preferences;

    Sure the library’s filename starts with a capital letter “P” and the object’s name starts with lowcase “p” in my opinion this difference is too small to demnstrate which names are fixed and which names are user-definable
    In my opinion the name of the object should reflect its nature
    I would prefer
    Preferences myPrefObj;

    Where “my” indicates it IS user-definable
    “Pref” gives the hint what it is
    and “Obj” that it is an “object” that has functions which can be accessed by
    writing “objectName.functionName”
    “objectName.functionName”
    the objects name dot the functions name

    My naming-convention differs from the usual but
    every advanced user and of course every expert will understand my naming instantly. The difference is that BEGINNERS will understand MORE.

    If advanced users and experts understand it immediately and BEGINNERS understand more what arguments are left against such a naming-convention?
    NONE! It is just a bad habit nobody things about.

    Reply
  19. Hello, I will transfer files from a client to ESP32. After the file is transferred, I want to print it to the sd card, how can I do it?

    Reply
    • First get your data over to the ESP32.

      Then in Arduino IDE, checkout Examples->SD(esp32)->SDTest.

      Use
      n = SDFile.read(byte *buffer, BUFSIZE);
      to read,
      n = SDFile.write(byte *buffer, BUFSIZE);
      to write, and
      SDFile.seek(a)
      to set the read/write address in the file.

      Reply
  20. Hello
    Great article. I am using a NodeMCU-32S board and the preference lab doesn’t work for me.
    The counter doesn’t increase when the board resets. If the problem is with my board could you recommend an ESP32 dev board that you would guarantee me that I could read/write to the ESP32 EEPROM on that board.
    Thanks

    Reply
  21. If running battery power only, does using preferences have a significant impact on power consumption? Ideally I would like to save some key parameters in preferences for if/when the battery dies, but not at the expense of consuming more power in the process so that the battery drains even faster!

    Reply
  22. Hello
    Great article.
    I had read on web “Hoever, the good news is that the EEPROM.write() on the ESP32 has the same properties of update. It only writes to EEPROM if we want to write something different.
    Now using the prefences insted of EEPROM library do the preferences.putUInt the same thing? For example, if the new value is equal to the value stored in ESP32 flash memory, then the preferences.putint counts as a write cycle or not.
    Thanks and sorry for my bad english

    Reply
  23. Hi Sara
    Great article
    I read in one of yuor article “Contrary to the Arduino, the ESP32 doesn’t have an EEPROM.update() function.
    however, the good news is that the EEPROM.write() on the ESP32 has the same properties of update. It only writes to EEPROM if we want to write something different.”

    Does the preferences.put command behave the same? So it only writes in the ESP32 flash memory if the new value is not equal to the already stored value. So no write cycle ?

    Thank
    Reinhold

    Reply
  24. Hey, how can I iterate the namespaces? I would like to utilise code in a way that creates separate namespaces like np1, np2, np3 and so on maybe using a loop?

    I would like to create separate namespaces in order to store and manage these namespaces later on….
    Here’s the code I have tried. Feel free to let me know if there is any other way to do it:

    #include<Preferences.h>

    Preferences ok;
    int i = 0;
    void setup() {
    Serial.begin(115200);

    }

    void loop() {

    while (i < 289) {
    char testarr[] = “test 1”;
    Serial.println(testarr);

    ok.begin(testarr, false);
    testarr[5] = int(i);
    Serial.println(testarr);
    ok.putString("rtc", "09/09/2022 09:09:09");
    ok.end();

    }
    while (i < 289) {
    char testarr[] = “test 1”;
    Serial.println(testarr);

    ok.begin(testarr, false);
    testarr[5] = int(i);
    Serial.println(testarr);
    String eh = ok.getString("rtc");
    Serial.println(eh);
    ok.end();

    }
    }

    Feel free to correct me as well.

    Reply
  25. It appears that Preferences does not work on the ESP32-C3 development boards (I’m using an Adafruit ESP32-C3 QT-Py). the StartCounter example does not work – the countr does not increment.

    ESP-ROM:esp32c3-api1-20210207

    Current counter value: 1
    Restarting in 10 seconds…
    ESP-ROM:esp32c3-api1-20210207
    Build:Feb 7 2021
    rst:0x3 (RTC_SW_SYS_RST),boot:0xd (SPI_FAST_FLASH_BOOT)
    Saved PC:0x403816f2
    SPIWP:0xee
    mode:DOUT, clock div:1
    load:0x3fcd6100,len:0x38c
    load:0x403ce000,len:0x6ac
    load:0x403d0000,len:0x2464
    SHA-256 comparison failed:
    Calculated: ae4b6389c51bca37025d68f98f30f6e4b83b375cef091401f27fa9596bdb9ddf
    Expected: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
    Attempting to boot anyway…
    entry 0x403ce000

    Current counter value: 1
    Restarting in 10 seconds…
    ESP-ROM:esp32c3-api1-20210207
    Build:Feb 7 2021
    rst:0x3 (RTC_SW_SYS_RST),boot:0xd (SPI_FAST_FLASH_BOOT)
    Saved PC:0x403816f2
    SPIWP:0xee
    mode:DOUT, clock div:1
    load:0x3fcd6100,len:0x38c
    load:0x403ce000,len:0x6ac
    load:0x403d0000,len:0x2464
    SHA-256 comparison failed:
    Calculated: ae4b6389c51bca37025d68f98f30f6e4b83b375cef091401f27fa9596bdb9ddf
    Expected: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
    Attempting to boot anyway…
    entry 0x403ce000

    Current counter value: 1
    Restarting in 10 seconds…

    Does any know what the issue is with boards based on these chips? Id there an alternative storage method/library I can use in the meantime?

    Reply
  26. I made a comment yesterday – not yet displayed, thank goodness, about string lengths. Please ignore it. My ‘long’ strings of 21 characters were being handled fine except in the printf statements I’d used for debugging. Reading that keys were limited in length, I jumped to the wrong conclusion.

    Reply
      • (Writing through a translator) Hi Sarah, I found a way to store an array of any type in memory, the way is strange but I hope you understand.
        A little explanation if we do this
        Serial.println(“qwerty”+1);
        Then we’ll see werty the first letter will disappear and I used it like this, please write what you think.

        #include <Preferences.h>
        Preferences preferences;
        int MyArray[3];

        void setup() {
        Serial.begin(9600);
        preferences.begin(“MyArray”, false);

        for (int i = 0; i <= 2; i++) {
        MyArray[i] = preferences.getInt(“123MyArray[]” + i, 0);
        }

        MyArray[0]++;
        MyArray[1]++;
        MyArray[2]++;

        Serial.print(“MyArray[0] “); Serial.println(MyArray[0]);
        Serial.print(“MyArray[1] “); Serial.println(MyArray[1]);
        Serial.print(“MyArray[2] “); Serial.println(MyArray[2]);

        for (int i = 0; i <= 2; i++) {
        preferences.putInt(“123MyArray[]” + i, MyArray[i]);
        }
        preferences.end();

        Serial.println(“Restarting in 10 seconds…”);
        delay(10000);

        ESP.restart();
        }

        void loop() {

        }

        Reply
  27. Hi,

    Nice article. I’ve learned a lot!
    Is there a way to store and then read an IP address?

    Thanks for anyone who can answer this.

    Reply
    • Yes, this is how:

      1 – write
      preferences.begin(“networkdata”, false);

      IPAddress staticIP(192,168,1,61);
      uint32_t stip = (uint32_t) staticIP;
      preferences.putUInt(“staticIP”, stip);

      2 – read back
      IPAddress stip2 = preferences.getULong(“staticIP”, 0);

      Reply
  28. I have been trying to develop a small program to test wifi on a suspect ESP-12S (ESP8266) but I have a preferences.h error on compilation using Arduino IDE 2.0.4 on Linux Kubuntu 22.04 . The program was put together from a tutorial by ‘Liz’ online:

    The error is
    ” Detecting libraries used…
    /home/peterm/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/3.1.0-gcc10.3-e5f9fec/bin/xtensa-lx106-elf-g++ -D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ -D_GNU_SOURCE -DESP8266 @/tmp/arduino/sketches/740C962767F64087D11CBB11505D7FAC/core/build.opt -I/home/peterm/.arduino15/packages/esp8266/hardware/esp8266/3.1.2/tools/sdk/include -I/home/peterm/.arduino15/packages/esp8266/hardware/esp8266/3.1.2/tools/sdk/lwip2/include -I/home/peterm/.arduino15/packages/esp8266/hardware/esp8266/3.1.2/tools/sdk/libc/xtensa-lx106-elf/include -I/tmp/arduino/sketches/740C962767F64087D11CBB11505D7FAC/core -c @/home/peterm/.arduino15/packages/esp8266/hardware/esp8266/3.1.2/tools/warnings/none-cppflags -Os -g -free -fipa-pta -Werror=return-type -mlongcalls -mtext-section-literals -fno-rtti -falign-functions=4 -std=gnu++17 -ffunction-sections -fdata-sections -fno-exceptions -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 -w -x c++ -E -CC -DNONOSDK22x_190703=1 -DF_CPU=80000000L -DLWIP_OPEN_SRC -DTCP_MSS=536 -DLWIP_FEATURES=1 -DLWIP_IPV6=0 -DARDUINO=10607 -DARDUINO_ESP8266_GENERIC -DARDUINO_ARCH_ESP8266 “-DARDUINO_BOARD=\”ESP8266_GENERIC\”” “-DARDUINO_BOARD_ID=\”generic\”” -DLED_BUILTIN=2 -DFLASHMODE_DOUT -I/home/peterm/.arduino15/packages/esp8266/hardware/esp8266/3.1.2/cores/esp8266 -I/home/peterm/.arduino15/packages/esp8266/hardware/esp8266/3.1.2/variants/generic /tmp/arduino/sketches/740C962767F64087D11CBB11505D7FAC/sketch/Liz-Wifi.ino.cpp -o /dev/null
    Alternatives for Esp32WifiManager.h: [[email protected]]
    ResolveLibrary(Esp32WifiManager.h)
    -> candidates: [[email protected]]
    /home/peterm/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/3.1.0-gcc10.3-e5f9fec/bin/xtensa-lx106-elf-g++ -D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ -D_GNU_SOURCE -DESP8266 @/tmp/arduino/sketches/740C962767F64087D11CBB11505D7FAC/core/build.opt -I/home/peterm/.arduino15/packages/esp8266/hardware/esp8266/3.1.2/tools/sdk/include -I/home/peterm/.arduino15/packages/esp8266/hardware/esp8266/3.1.2/tools/sdk/lwip2/include -I/home/peterm/.arduino15/packages/esp8266/hardware/esp8266/3.1.2/tools/sdk/libc/xtensa-lx106-elf/include -I/tmp/arduino/sketches/740C962767F64087D11CBB11505D7FAC/core -c @/home/peterm/.arduino15/packages/esp8266/hardware/esp8266/3.1.2/tools/warnings/none-cppflags -Os -g -free -fipa-pta -Werror=return-type -mlongcalls -mtext-section-literals -fno-rtti -falign-functions=4 -std=gnu++17 -ffunction-sections -fdata-sections -fno-exceptions -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 -w -x c++ -E -CC -DNONOSDK22x_190703=1 -DF_CPU=80000000L -DLWIP_OPEN_SRC -DTCP_MSS=536 -DLWIP_FEATURES=1 -DLWIP_IPV6=0 -DARDUINO=10607 -DARDUINO_ESP8266_GENERIC -DARDUINO_ARCH_ESP8266 “-DARDUINO_BOARD=\”ESP8266_GENERIC\”” “-DARDUINO_BOARD_ID=\”generic\”” -DLED_BUILTIN=2 -DFLASHMODE_DOUT -I/home/peterm/.arduino15/packages/esp8266/hardware/esp8266/3.1.2/cores/esp8266 -I/home/peterm/.arduino15/packages/esp8266/hardware/esp8266/3.1.2/variants/generic -I/home/peterm/Arduino/libraries/Esp32WifiManager/src /tmp/arduino/sketches/740C962767F64087D11CBB11505D7FAC/sketch/Liz-Wifi.ino.cpp -o /dev/null
    Alternatives for Preferences.h: []
    ResolveLibrary(Preferences.h)
    -> candidates: []
    In file included from /home/peterm/Arduino/libraries/Esp32WifiManager/src/Esp32WifiManager.h:2,
    from /home/peterm/Arduino/Liz-Wifi/Liz-Wifi.ino:1:
    /home/peterm/Arduino/libraries/Esp32WifiManager/src/wifi/WifiManager.h:11:10: fatal error: Preferences.h: No such file or directory
    11 | #include <Preferences.h>
    | ^~~~~~~~~~~~~~~

    The program library WifiManager.h is the one that calls preferences.h
    “/*
    * WifiManager.h
    *
    * Created on: Jun 13, 2018
    * Author: hephaestus
    */

    #ifndef LIBRARIES_ESP32SIMPLEPACKETCOMS_SRC_WIFI_WIFIMANAGER_H_
    #define LIBRARIES_ESP32SIMPLEPACKETCOMS_SRC_WIFI_WIFIMANAGER_H_
    #include <Arduino.h>
    #include <Preferences.h>
    #include <WiFi.h>
    #include <esp_wifi.h>
    #define rescanIncrement 2
    #define timeoutTime 10000
    #define PASS_LEN_KEY 12
    enum connectionState {
    firstStart,
    Disconnected,
    InitialConnect,
    apconnected,
    Connected,
    HaveSSIDSerial, ….. and it goes on

    and my program:
    #include <Esp32WifiManager.h>

    #include <ESP8266WiFi.h>

    /ADD YOUR PASSWORD BELOW/
    const char *ssid = “Ashmeads-downstairs”;
    const char *password = “”;

    WiFiClient client;

    /*
    * Connect your controller to WiFi
    */
    void connectToWiFi() {
    //Connect to WiFi Network
    Serial.println();
    Serial.println();
    Serial.print(“Connecting to WiFi”);
    Serial.println(“…”);
    WiFi.begin(ssid, password);
    int retries = 0;
    while ((WiFi.status() != WL_CONNECTED) && (retries < 15)) {
    retries++;
    delay(500);
    Serial.print(“.”);
    }
    if (retries > 14) {
    Serial.println(F(“WiFi connection FAILED”));
    }
    if (WiFi.status() == WL_CONNECTED) {
    Serial.println(F(“WiFi connected!”));
    Serial.println(“IP address: “);
    Serial.println(WiFi.localIP());
    }
    Serial.println(F(“Setup ready”));
    }

    /*
    * call connectToWifi() in setup()
    */
    void setup(){
    //…other setup code here…
    connectToWiFi();
    }

    But this is a new installation of the IDE and I cannot figure out how to get/create/find this preferences.h file.

    Any guidance appreciated.

    Reply
    • Hi.
      This code only works for ESP32 boards.
      Make sure you have an ESP32 board in the Tools > Boards menu.
      It’s not compatible with the ESP8266.
      Regards,
      Sara

      Reply
  29. Hello Sara Thank you for all your work
    I have a problem with the preference function
    I just want to save a value received via Bluetooth and recover that value on reboot

    I receive the value by BT (2 characters) But when restarting, it keeps only the first character

    Exact off code:
    unsigned int DureeArrosage;// durée envoyée depuis BT

    ///////////////////In the void SETUP

    preferences.begin(“my-app”, false);
    //////////////
    DureeArrosage = preferences.getInt(“DureeArrosage”, 0);

    ////////////////In the void loop

    // Partie BT
    if (SerialBT.available())
    {
    char incomingChar = SerialBT.read();
    if (incomingChar != ‘\n’)
    {

    message += String(incomingChar);
    Serial.print("message : ");
    Serial.println(message);
    messageInt = message.toInt();
    DureeArrosage=messageInt;

    preferences.putInt("DureeArrosage", DureeArrosage);
    // Close the Preferences
    preferences.end();

    Bonjour Sara Thank you for all your work I have a problem with the preference function I just want to save a value received via Bluetooth and recover that value on reboot I receive the value by BT (2 characters) But when restarting, it keeps only the first character

    Can you help me?

    Bonjour Sara Thank you for all your work I have a problem with the preference function I just want to save a value received via Bluetooth and recover that value on reboot I receive the value by BT (2 characters) But when restarting, it keeps only the first character Can you help me?
    Thanks in advance

    Reply
  30. Not sure if you guys have the answer to my question but I’m wondering if using the Preferences library is better than using RTC_DATA_ATTR in terms of power consumption during deep sleep.

    Reply
  31. Olá, durante o decorrer de um código, se houver múltiplas escritas para o mesmo namespace e mesma variável, podem ocorrer falhas? É preciso colocar um delay?

    Reply
  32. Hello,
    thank you for good lessons. I am very happy with your site, learned a lot for ESP32.
    I found a miss in this lesson. Please mention that key is 15 bytes max plus ‘\0’, i.e. total 16 bytes.
    Also you can mention that putXXX functions return 0 in case of not set the data.

    Thanks and best regards.
    Ilija Iliev

    Reply
  33. Hi Sara and Roi. I have been using preferences extensively but am a bit concerned about it’s limits. How do I determine what the memory limits are? Also in your preferences guide, you mention the use of preferences.end();. I am not sure when to use it.
    Thanks so much.

    Reply
    • Hello Mal Oldis,
      When you use Arduino IDE, there is configuration options for the device. By default 4MB are splitted in 2 parts: for NVM and for code flash. Usually 1.5 MB is NVM emulation but you can extend or remove it depend on your needs. Also can burn bootloader, add OTA, etc.

      Reply
  34. Very nice tutorial.
    I have one question: Do the stored data survive an OTA update where both the program and files stored in littleFS are updated?

    Reply
  35. Antes que nada gracias por todos sus aportes, siempre son el impulso suficiente para desarrollar proyectos con cada nueva tecnología que ocupo, asi que de nuevo muchas gracias!! Hoy recurro a ustedes para obtener ayuda respecto a la compilación de la biblioteca en VisualStudioCode, ya que no encuentro solución en ningún sitio. El problema es que al compilar aparece el error “For ESP32 devices, please use the native Preferences library”. Este error se presenta con la versión de biblioteca 2.1.0 y 2.0.0, las dos únicas versiones de esta. Tambien probé cambiar la version de framework, desde la 6.5 hasta la 4.4, y da el error con todas las combinaciones entre versiones de framework y biblioteca.

    Reply

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.