Everything in a variable vanishes when the power goes — and in India, the power goes. A tank alarm’s thresholds, a light’s schedule, a calibration value: they need to live in flash memory.
Preferences: key–value storage
The ESP32 core includes Preferences (no install). Think of it as a cupboard with named drawers:
prefs.begin("lesson21", false); // open the "lesson21" drawer, read/write
uint32_t ms = prefs.getUInt("blink", 500); // read "blink", or 500 if it was never saved
prefs.putUInt("blink", ms); // save it
There are matching get/put pairs for Int, UInt, Float, Bool, String and more. The drawer name and keys can be up to 15 characters.
Use it
Upload, open the Serial Monitor at 115200 with line ending set to Newline, then:
- Type
speed 150and press Enter — the LED blinks fast. - Press the EN button (reset) or unplug the board. It comes back at 150 ms, and the boot number has gone up.
- Type
resetto clear the drawer.
Don’t wear out the flash
Flash cells survive a large but limited number of erase cycles (Espressif’s datasheets quote around 100,000). The library spreads writes around, but the rule still applies:
- Write when a value changes, not every time
loop()runs. - A boot counter (one write per boot) is fine. Saving a sensor reading every 100 ms for months is not.
The sketch only calls putUInt("blink", …) when you type a new speed.
Preferences vs EEPROM
On the Uno you’d use EEPROM.h, and the ESP32 core still has an EEPROM library (it’s emulated in flash and needs commit()). FlashReady’s own settings helper, fr_settings.h, uses it for Wi-Fi details. For your own values, Preferences is simpler: named keys instead of byte addresses, and no commit to forget.
Try it
- Save the last LED state from day 19’s web server, so the light comes back the way it was after a power cut.
- Store a min/max temperature (day 15) and keep it across restarts.
You’re done when…
- At start-up the Serial Monitor (115200, Newline) shows
Boot number … Blink speed 500 ms (from flash). -
speed 150printsSaved: 150 msand the LED blinks fast. - After pressing EN, and again after unplugging for 10 s, it comes back at 150 ms with a higher boot number.
-
resetprintsCleared. Back to 500 ms….
Today's code
// Day 21 — Saving settings in flash with Preferences (ESP32 DevKit V1)
// No wiring (blue LED on GPIO 2). In the Serial Monitor (115200 baud, "Newline") type:
// speed 200 → blink every 200 ms, and remember it after a reset or power cut
// reset → forget the saved speed and the boot count
// Press EN (reset) or unplug the board: the speed and boot count survive.
#include <Preferences.h>
const int LED_PIN = 2;
Preferences prefs;
uint32_t blinkMs = 500;
unsigned long lastBlink = 0;
bool ledOn = false;
void setup() {
Serial.begin(115200);
delay(500);
pinMode(LED_PIN, OUTPUT);
prefs.begin("lesson21", false); // a named "drawer" in flash; false = read/write
uint32_t boots = prefs.getUInt("boots", 0) + 1;
prefs.putUInt("boots", boots); // one write per boot: fine for flash wear
blinkMs = prefs.getUInt("blink", 500); // 500 if nothing was saved yet
Serial.printf("\nBoot number %lu. Blink speed %lu ms (from flash).\n", (unsigned long)boots, (unsigned long)blinkMs);
Serial.println("Type: speed <50..5000> or reset");
}
void handleCommand(String line) {
line.trim();
if (line.startsWith("speed ")) {
long ms = line.substring(6).toInt();
if (ms < 50 || ms > 5000) {
Serial.println("Pick 50..5000 ms");
return;
}
blinkMs = ms;
prefs.putUInt("blink", blinkMs); // saved only when it changes, never in a fast loop
Serial.printf("Saved: %lu ms\n", (unsigned long)blinkMs);
} else if (line == "reset") {
prefs.clear(); // empties this namespace only
blinkMs = 500;
Serial.println("Cleared. Back to 500 ms; boot count restarts next boot.");
} else if (line.length()) {
Serial.println("Unknown command");
}
}
void loop() {
if (Serial.available()) handleCommand(Serial.readStringUntil('\n'));
if (millis() - lastBlink >= blinkMs) {
lastBlink = millis();
ledOn = !ledOn;
digitalWrite(LED_PIN, ledOn ? HIGH : LOW);
}
}// Day 21 — Saving settings in flash with Preferences (ESP32 DevKit V1)
// No wiring (blue LED on GPIO 2). In the Serial Monitor (115200 baud, "Newline") type:
// speed 200 → blink every 200 ms, and remember it after a reset or power cut
// reset → forget the saved speed and the boot count
// Press EN (reset) or unplug the board: the speed and boot count survive.
#include <Preferences.h>
const int LED_PIN = 2;
Preferences prefs;
uint32_t blinkMs = 500;
unsigned long lastBlink = 0;
bool ledOn = false;
void setup() {
Serial.begin(115200);
delay(500);
pinMode(LED_PIN, OUTPUT);
prefs.begin("lesson21", false); // a named "drawer" in flash; false = read/write
uint32_t boots = prefs.getUInt("boots", 0) + 1;
prefs.putUInt("boots", boots); // one write per boot: fine for flash wear
blinkMs = prefs.getUInt("blink", 500); // 500 if nothing was saved yet
Serial.printf("\nBoot number %lu. Blink speed %lu ms (from flash).\n", (unsigned long)boots, (unsigned long)blinkMs);
Serial.println("Type: speed <50..5000> or reset");
}
void handleCommand(String line) {
line.trim();
if (line.startsWith("speed ")) {
long ms = line.substring(6).toInt();
if (ms < 50 || ms > 5000) {
Serial.println("Pick 50..5000 ms");
return;
}
blinkMs = ms;
prefs.putUInt("blink", blinkMs); // saved only when it changes, never in a fast loop
Serial.printf("Saved: %lu ms\n", (unsigned long)blinkMs);
} else if (line == "reset") {
prefs.clear(); // empties this namespace only
blinkMs = 500;
Serial.println("Cleared. Back to 500 ms; boot count restarts next boot.");
} else if (line.length()) {
Serial.println("Unknown command");
}
}
void loop() {
if (Serial.available()) handleCommand(Serial.readStringUntil('\n'));
if (millis() - lastBlink >= blinkMs) {
lastBlink = millis();
ledOn = !ledOn;
digitalWrite(LED_PIN, ledOn ? HIGH : LOW);
}
}