ESP32 - Preferences, not storing some data

Hi, I'm buiding a project where I need to log some data in NVR for laters uses. As is suggested I'm using Preferences instead of EEPROM library but I'm stuck with how to make it right with the preferences library.

This is my project:

Once a day, the device will make a measure of alkalinity. And it will record two pair of values for each measure: Timestamp in unix format and the Alkalinity value.

But, it will keep just the last 255 records, in order to keep the memory usage under control.

There is need to store an index number too, Because I will use a circular array in NVR in order to minimize the read/write cycles. The index number will be cycling between 0 and 254. This index is important to let the device know what log record have to be writed or updated.

In order to make a prototype, I made a sketch to test how the NVR storage work. But It doesn't work properly. I can see just the record for the measure is stored properly, but the record index isn't. Then each new record is stored in the same position on the array.

According to how I understand preferences work, I need to use two namespaces, one for the array of data records and another to keep the index number.

For some unknown reason (for me), the index record in not being stored. ¿What I'm doing wrong?

This is my test sketch:

#include <Preferences.h>
#include <SimpleTimer.h>
#include "TimeLib.h"

tmElements_t te;  //Time elements structure
time_t unixTime; // a time stamp

unsigned int indice;

Preferences registro;

SimpleTimer timer;

typedef struct { // data structure for each record
  unsigned long unix = 0;
  float kH = 0;
} Log_kh;

Log_kh Log_kh_[255]; //Size of the record array in memory

void bitacora(){
  registro.begin("Settings", false); //opens the namespace "Settings" to store a new record in the next position according the indice
  Serial.println("Inicia Bitacora " + String(indice)); //prints the actual indice *** it shows allways 0!!
  //Now it will create a new record with some variable data just to test it is actually stored in NVR
  te.Second = indice*60/255;
  te.Hour = 18; //11 pm
  te.Minute = random(60);
  te.Day = 7 ;
  te.Month = 2;
  te.Year = 2023 - 1970; //Y2K, in seconds = 946684800UL
  unixTime =  makeTime(te);
  Log_kh_[indice].unix = unixTime;
  Log_kh_[indice].kH = 7 + random(2); 
  registro.putBytes("Log_kh", &Log_kh_, sizeof(Log_kh_)); //Stores the data in NVR
  registro.getBytes("Log_kh", &Log_kh_, sizeof(Log_kh_)); // get the data to check
  //It will print the data it got from memory.
  Serial.print(Log_kh_[indice].unix);
  printf(" Fecha: %4d-%02d-%02d %02d:%02d:%02d\n ", year(Log_kh_[indice].unix), month(Log_kh_[indice].unix), day(Log_kh_[indice].unix), hour(Log_kh_[indice].unix), minute(Log_kh_[indice].unix), second(Log_kh_[indice].unix));
  Serial.println(Log_kh_[indice].kH);
  registro.end(); //close the namespace "Settings"
  //now the indice used is printed, incremented (with condition to cycle between 0 and 254), and printed again
  Serial.println("registra indice " + String(indice));
  indice = indice + 1;
  Serial.println("Siguiente indice "+ String(indice));
  if (indice = 255) indice = 0;   
  registro.begin("puntero", false); //open the name space "puntero" to store the new indice
  registro.putUInt("index", indice);// stores the new indice in memory
  Serial.println("registro guardado: " +String(registro.getUInt("index", 0))); //prints the value actually stored*** it allways shows 0!!
  registro.end(); // close the namespace "puntero"
  
}

void setup() {
  Serial.begin(115200);
  registro.begin("puntero", false); //open namespace "puntero" to recover the last index number stored
  indice = registro.getUInt("index", 0);// put the index on indice, if there no first entry, will assume 0
  registro.end(); //close the name space "puntero"
  Serial.println("Indice after reset: "+String(indice)); //Prints the indice got from memory
  registro.begin("Settings", false);  //open namespace "Settings" to recover the full array of measure records stored
  Serial.print("sizeof(Log_kh_) = "); Serial.println(String(sizeof(Log_kh_)));//prints the size of the record array
  registro.end();  //close the namespace "Settings"
  
  // next lines prints the data records from 0 to indice
  for (int i = 0 ; i < indice ; i++) {    
    Serial.print(Log_kh_[i].unix);
    printf(" Fecha: %4d-%02d-%02d %02d:%02d:%02d\n ", year(Log_kh_[i].unix), month(Log_kh_[i].unix), day(Log_kh_[i].unix), hour(Log_kh_[i].unix), minute(Log_kh_[i].unix), second(Log_kh_[i].unix));
    Serial.println(Log_kh_[i].kH);    
  }  
  timer.setInterval(10000, bitacora); //bitacora will run every 10 seconds. This function will have to create a new data record in memory.
}

void loop() {
  timer.run();
}

You mean:
if (indice == 255) indice = 0;

Did you forget to put this line in setup()?

registro.getBytes("Log_kh", &Log_kh_, sizeof(Log_kh_)); // get the data

1 Like

If indice was declared as a byte unstead of an unsigned int then it would automatically roll over from 255 back to zero

1 Like

Oh, Thank you. The "=" instead the "==" was the problem. It's not the firs time I make that mistake.

When I cleaned the sketch for this post I deleted the registro.getBytes by mistake.

Thanks for the valuable help @johnwasser

that's a great idea.

I will try that.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.