ESP32 Enregistrer les données de manière permanente à l’aide de la bibliothèque de préférences

ESP32 Enregistrer les données de manière permanente à l'aide de la bibliothèque de préférences

Ce guide montre comment enregistrer des données de manière permanente sur la mémoire flash de l’ESP32 à l’aide de la bibliothèque Preferences.h. Les données conservées dans la mémoire flash persistent après les réinitialisations ou les pannes de courant. L’utilisation de la bibliothèque Preferences.h est utile pour enregistrer des données telles que les informations d’identification réseau, les clés API, les valeurs de seuil ou même le dernier état d’un GPIO. Vous apprendrez à enregistrer et à lire les données de la mémoire flash.

ESP32 Enregistrer les données en permanence à l'aide de la bibliothèque de préférences

Dans ce didacticiel, nous aborderons les sujets suivants :

Bibliothèque Preferences.h

Dans un précédent tutoriel, nous vous avions conseillé d’utiliser la librairie EEPROM pour sauvegarder les données sur mémoire flash. Cependant, la bibliothèque EEPROM est obsolète au profit de la bibliothèque Preferences.h. Cette bibliothèque est « installée » automatiquement lorsque vous installez les cartes ESP32 dans votre IDE Arduino.

La bibliothèque Preferences.h est de préférence utilisée pour stocker des valeurs de variables via des paires clé:valeur. La sauvegarde permanente des données peut être importante pour :

  • mémoriser le dernier état d’une variable ;
  • enregistrer les paramètres;
  • enregistrer combien de fois un appareil a été activé ;
  • ou tout autre type de données que vous devez enregistrer en permanence.

Si, au lieu de variables, vous devez enregistrer des fichiers sur l’ESP32, nous vous recommandons d’utiliser le système de fichiers (SPIFFS) à la place. Pour apprendre à enregistrer des fichiers dans le système de fichiers ESP32, vous pouvez lire l’un des tutoriels suivants :

Enregistrer les données à l’aide de la bibliothèque Preferences.h

Les données enregistrées à l’aide des préférences sont structurées comme suit :

namespace {
  key:value
}

Vous pouvez enregistrer différentes clés sur le même espace de noms, par exemple :

namespace {
  key1: value1
  key2: value2
}

Dans un exemple pratique, cette configuration pourrait être utilisée pour enregistrer vos identifiants réseau :

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

Dans l’exemple précédent, les informations d’identification sont l’espace de noms, et ssid et pass sont les clés.

Vous pouvez également avoir plusieurs espaces de noms avec la même clé (mais chaque clé avec sa valeur) :

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

Lorsque vous utilisez la bibliothèque Preferences.h, vous devez définir le type de données que vous souhaitez enregistrer. Plus tard, si vous souhaitez lire ces données, vous devez connaître le type de données enregistrées. En d’autres termes, le type de données d’écriture et de lecture doit être le même.

Vous pouvez enregistrer les types de données suivants à l’aide de Preferences.h : char, Uchar, short, Ushort, int, Uint, long, Ulong, long64, Ulong64, float, double, bool, string et bytes.

Pour plus d’informations, vous pouvez accéder au Fichier Preferences.cpp ici.

Fonctions utiles de la bibliothèque Preferences.h

Pour utiliser la bibliothèque Preferences.h pour stocker des données, vous devez d’abord l’inclure dans votre croquis :

#include <Preferences.h>

Ensuite, vous devez lancer une instance de la bibliothèque Preferences. Vous pouvez l’appeler préférences, par exemple :

Preferences preferences;

Après cela, vous pouvez utiliser les méthodes suivantes pour gérer les données à l’aide de la bibliothèque Preferences.h.

Préférences de démarrage

La méthode begin() ouvre un « espace de stockage » avec un espace de noms défini. Le faux argument signifie que nous l’utiliserons en mode lecture/écriture. Utilisez true pour ouvrir ou créer l’espace de noms en mode lecture seule.

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

Dans ce cas, le nom de l’espace de noms est my-app. Le nom de l’espace de noms est limité à 15 caractères.

Effacer les préférences

Utilisez clear() pour effacer toutes les préférences sous l’espace de noms ouvert (cela ne supprime pas l’espace de noms) :

preferences.clear();

Supprimer la clé

Supprimez une clé de l’espace de noms ouvert :

preferences.remove(key);

Fermer les préférences

Utilisez la méthode end() pour fermer les préférences sous l’espace de noms ouvert :

preferences.end();

Mettre une valeur clé (Enregistrer une valeur)

Vous devez utiliser différentes méthodes en fonction du type de variable que vous souhaitez enregistrer.

Carboniser putChar (const char * clé, valeur int8_t)
Caractère non signé putUChar (const char * clé, valeur int8_t)
Court putShort (const char * clé, valeur int16_t)
Court non signé putUShort (const char * clé, valeur uint16_t)
Int putInt (const char * clé, valeur int32_t)
Entier non signé putUInt (const char * clé, valeur uint32_t)
Long putLong (const char * clé, valeur int32_t)
Long non signé putULong(const char* clé, valeur uint32_t)
Longue64 putLong64 (const char * clé, valeur int64_t)
Non signé Long64 putULong64 (const char * clé, valeur uint64_t)
Flotter putFloat (clé const char *, valeur const float_t)
Double putDouble (clé const char *, valeur const double_t)
Bool putBool(const char* key, const bool value)
Chaîne putString (const char * clé, valeur de chaîne const)
Octets putBytes(const char* key, const void* value, size_t len)

Obtenir une valeur clé (Lire la valeur)

De même, vous devez utiliser différentes méthodes en fonction du type de variable que vous souhaitez obtenir.

Carboniser getChar(const char* key, const int8_t defaultValue)
Caractère non signé getUChar(const char* key, const uint8_t defaultValue)
Court getShort(const char* key, const int16_t defaultValue
Court non signé getUShort(const char* key, const uint16_t defaultValue)
Int getInt (const char * clé, const int32_t defaultValue)
Entier non signé getUInt (const char * clé, const uint32_t defaultValue)
Long getLong(const char* key, const int32_t defaultValue)
Long non signé getULong(const char* key, const uint32_t defaultValue)
Longue64 getLong64 (const char * clé, const int64_t defaultValue)
Non signé Long64 gettULong64(const char* key, const uint64_t defaultValue)
Flotter getFloat (const char * clé, const float_t defaultValue)
Double getDouble(const char* key, const double_t defaultValue)
Bool getBool(const char* key, const bool defaultValue)
Chaîne getString(const char* key, const String defaultValue)
Chaîne getString(const char* clé, char* valeur, const size_t maxLen)
Octets getBytes(const char* key, void * buf, size_t maxLen)

Supprimer un espace de noms

Dans l’implémentation Arduino des Préférences, il n’existe aucune méthode pour supprimer complètement un espace de noms. Par conséquent, au cours de plusieurs projets, la partition des préférences de stockage non volatile (nvs) ESP32 peut devenir pleine. Pour effacer complètement et reformater la mémoire NVS utilisée par les Préférences, créez une esquisse contenant :

#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() {

}

Vous devez télécharger une nouvelle esquisse sur votre carte immédiatement après avoir exécuté ce qui précède, sinon elle reformatera la partition NVS à chaque mise sous tension.

Preferences.h – Enregistrer les paires clé:valeur

Pour un exemple simple sur la façon d’enregistrer et d’obtenir des données à l’aide de Preferences.h, dans votre IDE Arduino, accédez à Fichier > Exemples > Préférences > 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://Raspberryme.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() {

}

Afficher le code brut

Cet exemple augmente une variable appelée compteur entre les réinitialisations. Cela illustre que l’ESP32 « se souvient » de la valeur même après une réinitialisation.

Téléchargez le croquis précédent sur votre carte ESP32. Ouvrez le moniteur série à un débit en bauds de 115200 et appuyez sur le bouton RST intégré. Vous devriez voir la variable du compteur augmenter entre les réinitialisations.

Préférences ESP32 StartCounter Exemple Serial Monitor

Comment fonctionne le code

Cet exemple utilise les fonctions que nous avons vues dans les sections précédentes.

Tout d’abord, incluez la bibliothèque Preferences.h.

#include <Preferences.h>

Ensuite, créez une instance de la bibliothèque appelée preferences.

Preferences preferences;

Dans setup(), initialisez le Serial Monitor à un débit en bauds de 115200.

Serial.begin(115200);

Créez un « espace de stockage » dans la mémoire flash appelé my-app en mode lecture/écriture. Vous pouvez lui donner n’importe quel autre nom.

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

Obtenir la valeur de la clé de compteur enregistrée sur les préférences. S’il ne trouve aucune valeur, il renvoie 0 par défaut (ce qui se produit lorsque ce code s’exécute pour la première fois).

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

La variable de compteur est augmentée d’une unité à chaque exécution de l’ESP :

counter++;

Imprimez la valeur de la variable compteur :

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

Mémorisez la nouvelle valeur sur la touche « compteur » :

preferences.putUInt("counter", counter);

Fermez les Préférences.

preferences.end();

Enfin, redémarrez la carte ESP32 :

ESP.restart();

ESP32 – Enregistrer/lire les informations d’identification réseau à l’aide de la bibliothèque Preferences.h

La bibliothèque Preferences.h est souvent utilisée pour enregistrer vos informations d’identification réseau de manière permanente sur la mémoire flash. De cette façon, vous n’avez pas à coder en dur les informations d’identification dans chaque croquis qui implique de connecter l’ESP32 à Internet.

Dans cette section, nous allons vous montrer deux croquis simples qui pourraient être utiles dans vos projets :

Pour en savoir plus sur les fonctions liées au Wi-Fi de l’ESP32, lisez l’article suivant :

Enregistrer les informations d’identification réseau à l’aide de Preferences.h

L’esquisse suivante enregistre vos informations d’identification réseau de manière permanente sur la mémoire flash ESP32 à l’aide de Preferences.h.

/*
  Rui Santos
  Complete project details at https://Raspberryme.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() {

}

Afficher le code brut

N’oubliez pas d’insérer vos identifiants réseau dans les variables suivantes :

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

Comment fonctionne le code

Examinons rapidement les parties pertinentes du code pour cet exemple.

Dans le setup (), créez un nouvel espace de stockage sur la mémoire flash avec l’espace de noms des informations d’identification.

preferences.begin("credentials", false);

Ensuite, créez une clé appelée ssid qui enregistre votre valeur SSID (variable ssid) – utilisez la méthode putString().

preferences.putString("ssid", ssid); 

Ajoutez une autre clé appelée mot de passe pour enregistrer la valeur du mot de passe (variable de mot de passe) :

preferences.putString("password", password);

Ainsi, vos données sont structurées de cette manière :

credentials{
  ssid: your_ssid
  password: your_password
}

Téléchargez le code sur votre carte et voici ce que vous devriez obtenir sur le Serial Monitor :

ESP32 Enregistrer les informations d'identification réseau à l'aide de la bibliothèque de préférences

Dans l’exemple suivant, nous allons vous montrer comment lire les informations d’identification réseau à partir des préférences et les utiliser pour connecter l’ESP32 à votre réseau.

Connectez-vous au Wi-Fi avec les informations d’identification réseau enregistrées dans les préférences

L’esquisse suivante obtient les valeurs des informations d’identification du réseau et se connecte à votre réseau à l’aide de ces informations d’identification.

/*
  Rui Santos
  Complete project details at https://Raspberryme.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:
}

Afficher le code brut

Comment fonctionne le code

Examinons rapidement les parties pertinentes du code pour cet exemple.

Ouvrez l’espace de noms des identifiants :

preferences.begin("credentials", false);

Obtenez les valeurs SSID et mot de passe à l’aide de la méthode getString(). Vous devez utiliser le nom de clé que vous avez utilisé pour enregistrer les variables, dans ce cas, les clés ssid et password :

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

Comme deuxième argument de la fonction getString(), nous avons passé une chaîne vide. Il s’agit de la valeur renvoyée au cas où il n’y aurait pas de clés ssid ou de mot de passe enregistrées dans les préférences.

Si tel est le cas, nous imprimons un message indiquant qu’il n’y a pas de valeurs enregistrées :

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

Sinon, nous nous connectons au Wi-Fi en utilisant le SSID et le mot de passe enregistrés dans les préférences.

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());
}

Téléchargez ce code sur votre tableau après le précédent (pour vous assurer que les informations d’identification sont enregistrées). Si tout se passe comme prévu, voici ce que vous devriez obtenir sur votre Serial Monitor.

ESP32 se connecte au réseau avec les informations d'identification enregistrées dans les préférences

Se souvenir du dernier état GPIO après la réinitialisation

Une autre application de la bibliothèque Preferences.h consiste à enregistrer le dernier état d’une sortie. Par exemple, imaginez le scénario suivant :

  1. Vous contrôlez une sortie avec l’ESP32 ;
  2. Vous configurez votre sortie pour qu’elle s’allume ;
  3. L’ESP32 perd soudainement de la puissance ;
  4. Lorsque le courant revient, la sortie reste désactivée, car elle n’a pas conservé son dernier état.
Bibliothèque de préférences ESP32 Mémoriser le dernier état GPIO (sans préférences)

Vous ne voulez pas que cela se produise. Vous voulez que l’ESP32 se souvienne de ce qui se passait avant de perdre de l’alimentation et revienne au dernier état.

Pour résoudre ce problème, vous pouvez enregistrer l’état de la lampe dans la mémoire flash. Ensuite, vous devez ajouter une condition au début de votre croquis pour vérifier le dernier état de la lampe et allumer ou éteindre la lampe en conséquence.

La figure suivante montre ce que nous allons faire :

Bibliothèque de préférences ESP32 Mémoriser le dernier état GPIO

Nous allons vous montrer un exemple utilisant une LED et un bouton poussoir. Le bouton-poussoir contrôle l’état de la LED. La LED conserve son état entre les réinitialisations. Cela signifie que si la LED est allumée lorsque vous coupez l’alimentation, elle s’allumera lorsqu’elle sera à nouveau alimentée.

Diagramme schématique

Câblez un bouton-poussoir et une LED à l’ESP32 comme indiqué dans le schéma de principe suivant.

ESP32 Schéma schématique circuit LED sortie bouton poussoir entrée

Lecture recommandée : Référence de brochage ESP32 : Quelles broches GPIO devez-vous utiliser ?

Code

Il s’agit d’un code anti-rebond qui change l’état de la LED chaque fois que vous appuyez sur le bouton-poussoir. Mais il y a quelque chose de spécial à propos de ce code – il se souvient du dernier état de la LED, même après avoir réinitialisé ou coupé l’alimentation de l’ESP32. Ceci est possible car nous enregistrons l’état de la led dans les Préférences chaque fois qu’il change.

/*
  Rui Santos
  Complete project details at https://Raspberryme.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);
  }
}

Afficher le code brut

Comment fonctionne le code

Examinons rapidement les parties de code pertinentes pour cet exemple.

Dans le setup(), commencez par créer une section dans la mémoire flash pour sauvegarder l’état du GPIO. Dans cet exemple, nous l’avons appelé gpio.

preferences.begin("gpio", false);

Obtenez l’état GPIO enregistré dans les Préférences sur la clé d’état. C’est une variable booléenne, utilisez donc la fonction getBool(). S’il n’y a pas encore de clé d’état (ce qui se produit lors de la première exécution de l’ESP32), renvoyez false (la LED sera éteinte).

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

Imprimez l’état et réglez la LED sur le bon état :

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

Enfin, dans la boucle (), mettez à jour la clé d’état sur les préférences chaque fois qu’il y a un changement.

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

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

Manifestation

Téléchargez le code sur votre carte et câblez le circuit. Ouvrez le moniteur série à un débit en bauds de 115200 et appuyez sur le bouton RST intégré.

Appuyez sur le bouton-poussoir pour modifier l’état de la LED, puis coupez l’alimentation ou appuyez sur le bouton RST.

ESP32 Schematics diagram circuit LED output bouton-poussoir test de démonstration d'entrée

Lorsque l’ESP32 redémarre, il lit le dernier état enregistré dans les Préférences et règle la LED sur cet état. Il imprime également un message sur le moniteur série chaque fois qu’il y a un changement dans l’état GPIO.

ESP32 Mémoriser les dernières préférences d'état des LED

Conclusion

Dans ce didacticiel, vous avez appris à enregistrer des données de manière permanente sur la mémoire flash de l’ESP32 à l’aide de la bibliothèque Preferences.h. Cette bibliothèque est pratique pour enregistrer des paires clé:valeur. Les données conservées sur la mémoire flash y restent même après la réinitialisation de l’ESP32 ou la mise hors tension.

Si vous avez besoin de stocker de plus grandes quantités de données ou de fichiers, vous devez plutôt utiliser le système de fichiers ESP32 (SPIFFS) ou une carte microSD :

Nous espérons que vous avez trouvé ce tutoriel utile.

En savoir plus sur l’ESP32 avec nos ressources :

Cette vidéo vous emmène dans l’histoire de Raspberry Pi :

YouTube video