ja.
Die Speicherung erfolgt organisiert in Pages und Entries (innerhalb der 20KB preferences), ist auf der espressif Seite auch ausführlich beschrieben im Kapitel zu NVS Non-volatile Storage Library - ESP32 - — ESP-IDF Programming Guide v5.1.2 documentation
Da stehen dann auch Informationen ala:
String values are currently limited to 4000 bytes. This includes the null terminator. Blob values are limited to 508,000 bytes or 97.6% of the partition size - 4000 bytes, whichever is lower.
Mein letzter Testsketch zum Experimentieren:
// https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/api/preferences.html#freeentries
// https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/storage/nvs_flash.html
#include <Preferences.h>
Preferences preferences;
// print used entries
void info(size_t written = -1)
{
static size_t previousValue = 0;
size_t value = preferences.freeEntries();
Serial.print(F("preferences free:")); Serial.print(value);
Serial.print(F(" - used entries since last call:")); Serial.print(previousValue - value);
if (written == 0) Serial.print(F(" - 0 byte written!"));
Serial.println();
previousValue = value;
}
// delete complete NVS if you have unknown namespaces (brings back around 629 free key pairs)
#include <nvs_flash.h>
void resetNVS() {
nvs_flash_erase(); // erase the NVS partition and...
nvs_flash_init(); // initialize the NVS partition.
//
}
void setup() {
Serial.begin(115200);
delay(500);
Serial.println("\nStart ...");
info();
//resetNVS(); // reset NVS once to delete all namespaces
size_t written = 0; // written bytes
if (preferences.begin("credentials"))
{
Serial.println("begin erfolgreich");
}
info();
if (preferences.clear())
{
Serial.println("clear erfolgreich");
}
info();
char name[16];
for (int i = 1; i <= 20; i++)
{
strcpy (name, "auto1024 ");
char buf[16];
itoa(i, buf, 10);
strcat (name, buf);
Serial.println(F("1024 chars"));
written = preferences.putString(name, "1234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678");
info(written);
if (written == 0)
{
Serial.print(F("write error at iteration "));
Serial.println(i);
break; // lets break out of for loop, it's unlikely that next write attempt would be successful
}
}
for (int i = 1; i <= 2; i++)
{
strcpy (name, "auto512 ");
char buf[16];
itoa(i, buf, 10);
strcat (name, buf);
Serial.println(F("512 chars"));
size_t written = preferences.putString(name, "12345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678");
info(written);
if (written == 0)
{
Serial.print(F("write error at iteration "));
Serial.println(i);
break;
}
}
Serial.println(F("256 chars"));
written = preferences.putString("char256", "1234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678");
info(written);
Serial.println(F("128 chars"));
written = preferences.putString("char128", "12345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678");
info(written);
Serial.println(F("64 chars"));
written = preferences.putString("char64", "1234567812345678123456781234567812345678123456781234567812345678");
info(written);
Serial.println(F("32 chars"));
written = preferences.putString("char32", "12345678123456781234567812345678");
info(written);
Serial.println(F("16 chars"));
written = preferences.putString("my SSID", "1234567812345678");
info(written);
Serial.println(F("8 chars"));
preferences.putString("my password", "12345678");
info(written);
Serial.println(F("4 chars"));
preferences.putString("char4", "1234");
info(written);
Serial.println(F("2 chars"));
preferences.putString("char2", "12");
info(written);
// this is just to fill up nvs
/*
for (int i = 1; i < 20; i++)
{
strcpy (name, "auto32 ");
char buf[16];
itoa(i, buf, 10);
strcat (name, buf);
Serial.println(F("32 chars"));
size_t written = preferences.putString(name, "12345678123456781234567812345678");
info(written);
if (written == 0)
{
Serial.print(F("write error at iteration "));
Serial.println(i);
break;
}
}
*/
//size_t putInt(const char* key, int32_t value)
Serial.println(F("store a"));
written = preferences.putInt("a", 42);
info(written);
Serial.println(F("store bb"));
written = preferences.putInt("bb", 42);
info(written);
Serial.println(F("store ccc"));
written = preferences.putInt("ccc", 42);
info(written);
Serial.println(F("store Char 1"));
written = preferences.putChar("c", 'a');
info(written);
Serial.println(F("store Char 2 "));
written = preferences.putChar("another char", 'a');
info(written);
Serial.println(F("store Char 3"));
written = preferences.putChar("yet another char", 'a');
info(written);
Serial.println(F("store Char 4"));
written = preferences.putChar("a char with a remarkable key", 'a');
info(written);
// end test and clear used namespace
if (preferences.clear())
{
Serial.println("clear ok");
}
info();
preferences.end();
}
void loop() {}
gibt bei mir folgendes aus
Start ...
preferences free:629 - used entries since last call:4294966667
begin erfolgreich
preferences free:629 - used entries since last call:0
clear erfolgreich
preferences free:629 - used entries since last call:0
1024 chars
preferences free:595 - used entries since last call:34
1024 chars
preferences free:561 - used entries since last call:34
1024 chars
preferences free:527 - used entries since last call:34
1024 chars
preferences free:493 - used entries since last call:34
1024 chars
preferences free:459 - used entries since last call:34
1024 chars
preferences free:425 - used entries since last call:34
1024 chars
preferences free:391 - used entries since last call:34
1024 chars
preferences free:357 - used entries since last call:34
1024 chars
preferences free:323 - used entries since last call:34
1024 chars
preferences free:289 - used entries since last call:34
1024 chars
preferences free:255 - used entries since last call:34
1024 chars
preferences free:221 - used entries since last call:34
1024 chars
preferences free:221 - used entries since last call:0 - 0 byte written!
write error at iteration 13
512 chars
preferences free:203 - used entries since last call:18
512 chars
preferences free:185 - used entries since last call:18
256 chars
preferences free:175 - used entries since last call:10
128 chars
preferences free:169 - used entries since last call:6
64 chars
preferences free:165 - used entries since last call:4
32 chars
preferences free:162 - used entries since last call:3
16 chars
preferences free:160 - used entries since last call:2
8 chars
preferences free:158 - used entries since last call:2
4 chars
preferences free:156 - used entries since last call:2
2 chars
preferences free:154 - used entries since last call:2
store a
preferences free:153 - used entries since last call:1
store bb
preferences free:152 - used entries since last call:1
store ccc
preferences free:151 - used entries since last call:1
store Char 1
preferences free:150 - used entries since last call:1
store Char 2
preferences free:149 - used entries since last call:1
store Char 3
preferences free:149 - used entries since last call:0 - 0 byte written!
store Char 4
preferences free:149 - used entries since last call:0 - 0 byte written!
clear ok
preferences free:629 - used entries since last call:4294966816
Was wie viele Entries verbraucht, oder wann ein Schreiben fehl schlägt ist schon interessant.
Was ich mir aktuell denke:
- man hat Anfangs 629 Keypaare
- man bekommt den 20K Speicher mit großen Strings voll, ob das aber noch reale Relevanz hat, muss jeder selber entscheiden. Im Beispiel habe ich z.B. 12 mal 1kB Strings schreiben können. Wie viele derartige Wertpaare braucht man denn wirklich in einer Applikation *)
- es ist ratsam auf die Free Entries zu achten
- man soll überprüfen ob das Speichern erfolgreich war, bei großen Anwendungen auf alle Fälle.
*) OT:
Genausowenig wie man "640 kB ought to be enough for anybody" Gates zuschreiben darf, sag ich auch nicht dass 20kB preferences für jeden Anwendungsfall genug sind ... aber fürs durchschnittliche LED Geblinke wirds oft reichen.