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.
In this tutorial, we’ll cover the following topics:
- Save key:value pairs;
- Read a key value;
- Example 1: Save key:value pairs;
- Example 2: ESP32 – Save/Read Network Credentials using the Preferences.h Library;
- Example 3: ESP32 – Remember Last GPIO State After RESET;
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:
- Install ESP32 Filesystem Uploader in Arduino IDE
- ESP32 with VS Code and PlatformIO: Upload Files to Filesystem (SPIFFS)
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.
Char | putChar(const char* key, int8_t value) |
Unsigned Char | putUChar(const char* key, int8_t value) |
Short | putShort(const char* key, int16_t value) |
Unsigned Short | putUShort(const char* key, uint16_t value) |
Int | putInt(const char* key, int32_t value) |
Unsigned Int | putUInt(const char* key, uint32_t value) |
Long | putLong(const char* key, int32_t value) |
Unsigned Long | putULong(const char* key, uint32_t value) |
Long64 | putLong64(const char* key, int64_t value) |
Unsigned Long64 | putULong64(const char* key, uint64_t value) |
Float | putFloat(const char* key, const float_t value) |
Double | putDouble(const char* key, const double_t value) |
Bool | putBool(const char* key, const bool value) |
String | putString(const char* key, const String value) |
Bytes | putBytes(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.
Char | getChar(const char* key, const int8_t defaultValue) |
Unsigned Char | getUChar(const char* key, const uint8_t defaultValue) |
Short | getShort(const char* key, const int16_t defaultValue |
Unsigned Short | getUShort(const char* key, const uint16_t defaultValue) |
Int | getInt(const char* key, const int32_t defaultValue) |
Unsigned Int | getUInt(const char* key, const uint32_t defaultValue) |
Long | getLong(const char* key, const int32_t defaultValue) |
Unsigned Long | getULong(const char* key, const uint32_t defaultValue) |
Long64 | getLong64(const char* key, const int64_t defaultValue) |
Unsigned Long64 | gettULong64(const char* key, const uint64_t defaultValue) |
Float | getFloat(const char* key, const float_t defaultValue) |
Double | getDouble(const char* key, const double_t defaultValue) |
Bool | getBool(const char* key, const bool defaultValue) |
String | getString(const char* key, const String defaultValue) |
String | getString(const char* key, char* value, const size_t maxLen) |
Bytes | getBytes(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() {
}
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.
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:
- Save Network Credentials using Preferences.h
- Connect to Wi-Fi with Network Credentials Saved on Preferences
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() {
}
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:
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:
}
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.
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:
- You’re controlling an output with the ESP32;
- You set your output to turn on;
- The ESP32 suddenly loses power;
- When the power comes back on, the output stays off – because it didn’t keep its last state.
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 output’s state in the flash memory. Then, you need to add a condition at the beginning of your sketch to check the last output state and turn it on or off accordingly.
The following figure shows what we’re going to do:
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.
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);
}
}
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.
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.
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:
- Install ESP32 Filesystem Uploader in Arduino IDE
- ESP32 with VS Code and PlatformIO: Upload Files to Filesystem (SPIFFS)
- ESP32 Data Logging Temperature to MicroSD Card
We hope you’ve found this tutorial useful.
Learn more about the ESP32 with our resources:
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
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
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?
SPIFFS is deprecated. You should be promoting LittleFS now.
I don’t think SPIFFS is deprecated for the ESP32.
It is deprecated for the ESP8266.
Regards,
Sara
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)?
Is this available through MicroPython? It looks very useful but I can’t find it in MP docs.
Hi.
I don’t think so.
To save data permanently, you can create a file on the ESP32 flash to store data.
See this: https://forum.micropython.org/viewtopic.php?t=1620
Regards,
Sara
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.
Muy buena aportación Carl Hage !!!!
Lo tendré en cuenta, sobre todo en el tema de la encriptación para todo el tipo de credenciales en donde veo que NVS mejora a Preferences.
Para casos simples de variables de estado creo que Preferences es más simple de utilizar ¿no?
Thanks for the extra info Carl!
I invite you to take a look at an article I wrote a while back about the new logging API at https://thingpulse.com/esp32-logging/.
That is awesome I’ve been looking at how to save files to SD card .
Hi James.
We’ll post a tutorial about SD card soon.
Regards,
Sara
As always, a very good guide
Many Thanks
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?
Short discussion on wear levelling: https://esp32.com/viewtopic.php?t=3380
If that is an issue, probably best to use the FAT or SPIFF implementation.
In the Arduino implementation, a commit is performed with each “.put”.
All the nitty-gritty on NVS implementation: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/storage/nvs_flash.html
Good to know. I was not even aware of ths library. didnt see it in between the ‘examples’
Hi Rui and Sara,
Thank you very much for this tutorial. It will solve my long standing ESP8266 problem. Now, I have to switch to ESP32.
[UPDATE]
Please check comment: https://randomnerdtutorials.com/esp32-save-data-permanently-preferences/#comment-734357
Hi.
Thank you so much for sharing your knowledge.
I’ve updated the tutorial with some of your tips.
Thanks for taking the time to do this.
Regards,
Sara
Hi Sara. Didn’t realize that markdown is supported by default when posting. Is there a way to edit a post so I can clean up the formatting? Thanks.
Hey, quick note to say I just read through your long comment and found it very useful. Basically most of the way through reading the article I was thinking “yeh this is great but it’s a bit simple – I’ll definitely need to have some way of writing initial factory default values to memory, which also means I will need to create a bool flag called firstRun or somesuch”. Not difficult in any way but was really useful to see all your detailed comments. Must have taken a good couple of hours writing that comment – it definitely helps me as I’m writing my first firmware for an ESP32 and trying to figure these things out. Cheers!
Mat, glad it was of use. Was also writing my first Arduino sketch at the time and figured this might help others fill a few gaps I found in the docs. All the best.
Sara: I wrote a lengthy [comment] (https://randomnerdtutorials.com/esp32-save-data-permanently-preferences/#comment-566327) a while back to the [ESP32 Preferences] (https://randomnerdtutorials.com/esp32-save-data-permanently-preferences/) tutorial. Since then I’ve found that some of the information in that post is quite incorrect — mostly in the way I described how keys within a namespace are created.
I’ve now corrected all this and have had published in the official arduino-esp32 project documentation the [Preferences API] (https://docs.espressif.com/projects/arduino-esp32/en/latest/api/preferences.html) and a [Tutorial] (https://docs.espressif.com/projects/arduino-esp32/en/latest/tutorials/preferences.html) to match.
If it doesn’t cause too much trouble, could you flag my original post on your site with a disclaimer (or delete it completely in lieu of this note) and point to the official documents instead.
Thanks again for a great site and all the work you put into it.
Hi.
Thanks for sharing your documentation.
I’ve updated your previous comment.
Regards,
Sara
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
Hi Paul.
Unfortunately, I don’t think it is compatible with the ESP8266.
Regards,
Sara
For those who are stock with ESP8266 (like me!) I have found a library which passed the simple read and write test on my board. Here is the URL:
https://github.com/maarten-pennings/Nvm
You need to add the extracted zip file to Ardiono IDE’s “libraries” directory.
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?
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).
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
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
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
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);
Hi.
I’m sorry, but I didn’t understand your question.
Regards,
Sara
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
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);
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 statementsa =
thought tof =
?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 thepreferences.getXXX("keyname");
form.Also,
keynames
are limited to 13 characters maximum. The assignment forc =
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
Great!
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?
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.
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”);}
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 returns0
. 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 returns0
if the write failed or1
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.
When should I use preferences.end()? There were examples that this command was used and in other examples it was not used.
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
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)
Hi.
Yes, I think you can still use it.
Here is the tutorial for EEPROM: https://randomnerdtutorials.com/esp32-flash-memory/
Regards,
Sara
Thanks….. I’ve decided I can simply put these bytes in the EEPROM that’s already on board the DS3231 in the circuit… just Wire.h needed, nice and easy…. 🙂
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….
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
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])));
}
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
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
Could this library work on a sensor DataLogger? Saving the data given from sensor in the flash memory…
Hi.
Yes, it would work.
But, I recommend using a microSD card instead.
You can use this tutorial as a reference: https://randomnerdtutorials.com/esp32-microsd-card-arduino/
Regards,
Sara
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);
}
Hi.
Can you better describe what is exactly the error that you get?
Regards,
Sara
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
Jesio,
You need to read up on the difference between HTTP_GET and HTTP_POST
From your HTML you send data to to be processed by the ESP with a HTTP_POST command and if you want to bring data into your HTML you use the HTTP_GET.
Might be worth having a look at an example like this https://randomnerdtutorials.com/esp32-http-get-post-arduino/#http-post
Cheers
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
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
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
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
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
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
Great. Thanks for this clear answer.
Hi, I would ti save data received over BLE ti memory e then send this data over WiFi, how can I do It?
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.
Hi.
Yes. You are right.
I used the convention on the Preferences library example.
Regards,
Sara
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?
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.
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
Hi.
Do you get any errors?
Do you have another ESP32 board to experiment with?
Regards.
Sara
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!
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
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
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.
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?
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.
Ok.
It’s deleted.
Regards,
Sara
(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() {
}
Thanks for sharing this snipet.
Regards,
Sara
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.
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);
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.
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
Oops, left the wifi credentials in there. Please can you edit/delete them.
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
Hi Soenen. Couple of things. The immediate problem is improper type usage between
char
andint
. (We’ve all done it 😄).Better solution: the Preferences library directly supports a wide variety of data types. No need to convert between
int
andchar
.See the latest API documentation : https://github.com/espressif/arduino-esp32/blob/master/docs/source/api/preferences.rst
And tutorial: https://github.com/espressif/arduino-esp32/blob/master/docs/source/tutorials/preferences.rst
Not sure if you guys have the answer to my question but I’m wondering if using the
Preferences
library is better than usingRTC_DATA_ATTR
in terms of power consumption during deep sleep.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?
Hi,
In putString(“xxx”, myString), what is the maximum size for myString ?
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
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.
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.
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?
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.
This article is a little old and these things change fast. Using the Arduino IDE and setting “Erase all flash before sketch upload” to enabled now (May 2024) deletes the preferences.
Thanks again for all your work.
Preferences uses a portion of the on-board flash as its namespace. Thus when the flash is erased, so is the space used by the Preferences library. This is how it has always been.
For more detail, see the Resources section at the end of the Preferences Tutorial on the arduino-esp32 GitHub site at: https://docs.espressif.com/projects/arduino-esp32/en/latest/tutorials/preferences.html
I would like to ask how much read/write cycle is ESP is capable of?
Because i am planning to make a product counter with ESP
daily count: 1800 pcs
trigger :1 million pcs
My concer is how to ensure the data is preserved
Thanks