ESP32, LittleFS e recupero dati array

Nel mio progetto uso LittleFS per salvare i dati di configurazione ma ho uno strano comportamento quando recupero i dati.

Queste sono le variabili

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

Nel setup avvio la funzione per recuperare i dati

loadSettings(LittleFS, "/config.json");

La funzione è fatta così

void loadSettings(fs::FS &fs, const char *path) {
  File fileConfig = fs.open(path, "r");
  if (!fileConfig) {
    Serial.print("Impossibile aprire il file per la lettura: ");
    return;
  }
  StaticJsonDocument<1024> configLoad;
  DeserializationError error = deserializeJson(configLoad, fileConfig);
  fileConfig.close();
  if (error) {
    Serial.print("deserializeJson() fallito: ");
    Serial.println(error.c_str());
    return;
  }
  ssid = configLoad["ssid"] | "N/A";
  password = configLoad["password"] | "N/A";
  myChannelNumber = configLoad["myChannelNumber"] | -1;
  myWriteAPIKey = configLoad["myWriteAPIKey"] | "N/A";
  thingspeak = configLoad["thingspeak"] | -1;
  sonda1 = configLoad["sonda1"] | "N/A";
  sonda2 = configLoad["sonda2"] | "N/A";
  sonda3 = configLoad["sonda3"] | "N/A";
  mitt = configLoad["mitt"] | "N/A";
  dest = configLoad["dest"] | "N/A";
  impianto = configLoad["impianto"] | "N/A";
  Serial.print("ssid: " + ssid);
  Serial.print("Password: " + password);
  delay(1000);
  }

Qui sul monitor serial visualizzo correttamente il ssid e la password !
Poi però il listato continua con

lcd.setCursor(3, 0);
  lcd.print("Connecting to ");
  lcd.setCursor(0, 1);
  lcd.print(ssid);
  delay(1000);
  WiFi.mode(WIFI_STA);
  Serial.print("X" + ssid + "X");
  Serial.print("X" + password + "X");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    lcd.clear();
    lcd.setCursor(1, 0);
    lcd.write(byte(10));
    lcd.setCursor(3, 0);
    lcd.print("Not connected");
    lcd.setCursor(3, 1);
    lcd.print("..searching..");
  }
  delay(500);
  lcd.clear();
  lcd.setCursor(2, 1);
  lcd.print("WiFi connected");
  lcd.setCursor(2, 2);
  lcd.print("IP: ");
  lcd.setCursor(6, 2);
  lcd.print(WiFi.localIP());
  delay(2000);
  lcd.clear();

e qui ssid e password non sono più corretti , nel monitor seriale mi scrive:
19:49:05.565 -> X4��X
19:49:05.565 -> X�X

Perchè i due dati vengono persi?

Grazie a chi mi aiuta!

Se qualifichi una variabile come const, non puoi cambiarne il valore in un secondo momento!

Però perchè nel monitor seriale mi mostra il valore corretto?

Come posso cambiare

ssid = configLoad["ssid"] | "N/A";

Non trovo informazioni su quel "N/A" e come funziona

Probabilmente la classe Serial accede alla variabile in modo corretto mentre la classe per il display non lo fa.

Ad ogni modo è concettualmente sbagliato dichiarare una costante e poi cercare di modificarla e più in generale non è una buona idea memorizzare ssid e password su un file in chiaro, quando l'ESP32 dispone di un'area di memoria dedicata per memorizzare tutte le impostazioni relative a "station mode" e "access point mode".

Se la chiave impianto non è presente nel JSON, il risultato di configLoad["impianto"] sarà un null pointer che messo in OR con la literal string "N/A" restituisce "N/A"
Questa cosa è possibile solo perché la libreria ArduinoJson implementa l'overload dell'operatore | per le stringhe

1 Like

Ho cambiato un pò di cose ma ho ancora qualche problema :smiling_face_with_tear:

Per prima cosa verifico se il file "config.json" esiste ed in caso negativo lo creo

void checkFile() {
  bool fileexists = LittleFS.exists("/config.json");
  Serial.println(fileexists);
  if(!fileexists) {
    Serial.println("File doesn’t exist");  
    Serial.println("Creating file...");
    String configCheck;
    JsonDocument docCheck;
    docCheck["ssid"] = "nome_wifi";
    docCheck["password"] = "la_mia_password";
    docCheck["myChannelNumber"] = "id_thingspeak";
    docCheck["myWriteAPIKey"] = "api_thingspeak";
    docCheck["thingspeak"] = 0;
    docCheck["sonda1"] = "0x28, 0xE0, 0x7F, 0x2A, 0x06, 0x00, 0x00, 0x8F";
    docCheck["sonda2"] = "0x28, 0x3C, 0xEE, 0x2B, 0x06, 0x00, 0x00, 0xC3";
    docCheck["sonda3"] = "0x28, 0x05, 0xA9, 0x2B, 0x06, 0x00, 0x00, 0x00";
    docCheck["mitt"] = "mitt@mitt.it";
    docCheck["dest"] = "dest@dest.it";
    docCheck["impianto"] = "mio_impianto";

    serializeJson(docCheck, configCheck);
    char charCheckBuf[configCheck.length() + 1];
    configCheck.toCharArray(charCheckBuf, configCheck.length() + 1);
    Serial.println(charCheckBuf); //
    firstWriteFile(LittleFS, "/config.json", charCheckBuf);
    delay(1000);
  }

Il serial monitor mi restituisce l'array correttamente salvato

Creating file...
21:34:47.829 -> {"ssid":"nome_wifi","password":"la_mia_password","myChannelNumber":"id_thingspeak","myWriteAPIKey":"api_thingspeak","thingspeak":0,"sonda1":"0x28, 0xE0, 0x7F, 0x2A, 0x06, 0x00, 0x00, 0x8F","sonda2":"0x28, 0x3C, 0xEE, 0x2B, 0x06, 0x00, 0x00, 0xC3","sonda3":"0x28, 0x05, 0xA9, 0x2B, 0x06, 0x00, 0x00, 0x00","mitt":"mitt@mitt.it","dest":"dest@dest.it","impianto":"mio_impianto"}

A questo punto l'ESP32 prova a connettersi al wifi

lcd.setCursor(3, 0);
  lcd.print("Connecting to ");
  lcd.setCursor(0, 1);
  lcd.print(ssid);
  delay(1000);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.println(ssid);
    Serial.println(password);
    lcd.clear();
    lcd.setCursor(1, 0);
    lcd.write(byte(10));
    lcd.setCursor(3, 0);
    lcd.print("Not connected");
    lcd.setCursor(3, 1);
    lcd.print("..searching..");
  }

ma non ce la fa, nel serial monitor trovo il ssid corretto mentre la password la legge male

21:34:57.463 -> nome_wifi
21:34:57.463 -> xV��`

Da tenere conto che nome wifi e password sono alfanumerici

Questo LittleFS mi fa dannare :sweat_smile:

Scusa ma se fino ad un certo punto su seriale la password è corretta, mentre da un punto successivo stampa cose strane, mi pare ovvio che tra i due punto qualche parte del codice modifica la variabile password.
Inoltre secondo me con solo pezzi di codice difficile aiutarti. Ti sei impuntato che il problema è nei 2 pezzi che posti, ma se il problema è altrove ?

Non ho messo tutto il listato perchè sono 785 linee.
Comunque ho fatto ulteriori prove ... nel pezzo di listato in cui penso che succeda qualcosa ho posto un Serial.print(ssid) e Serial.print(password) dopo ogni comando e il problema succede subito dopo il comando WiFi.mode(WIFI_STA);

Qui ci sono alcune funzioni per creare o recuperare il config.json , tutte verificate che passano ssid e password corretti.

lcd.setCursor(3, 0);
  lcd.print("Connecting to ");
  lcd.setCursor(0, 1);
  lcd.print(ssid); // <- qui scrive il ssid corretto
  Serial.println("attendo dopo scritta a video");
  Serial.println(ssid); // <- qui scrive il ssid corretto
  Serial.println(password); // <- qui scrive la password corretta
  delay(1000);
  WiFi.mode(WIFI_STA);
  Serial.println("attendo dopo WIFI_STA");
  Serial.println(ssid);   // <- qui scrive il ssid corretto
  Serial.println(password); // <- qui scrive la password errata ( xV��` )
  delay(1000);
  WiFi.begin(ssid, password);
  Serial.println("attendo dopo wifi.begin");
  Serial.println(ssid); // <- qui scrive il ssid corretto
  Serial.println(password); // <- qui scrive la password errata ( xV��` )
  delay(1000);

Forse è un problema usare una variabile con il nome "password" ?

Ho "risolto" riassegnando nuovamente i valori con

loadSettings(LittleFS, "/config.json");

Comunque ho scoperto una libreria fatta apposta per quello di cui necessito che è
[GitHub - Juerd/ESP-WiFiSettings: WiFi Manager for the ESP32 Arduino environment](https://Libreria ESP-WiFiSettings)
c'è da lavorarci un pò per aggiungere gli altri campi che mi mancano ma sembra una via migliore di quella attuale

Di librerie simili ce ne sono molte nel repository Arduino.
Io ad esempio ne ho attive ben due anche se a conti fatti si tratta della stessa, solo che una usa il web server incluso nel core e l'altra invece fa uso della libreria ESPAsyncWebServer.

Ad ogni modo ribadisco che salvare SSID e password su un file è del tutto inutile (oltre che a rischio "furto" credenziali)

ho visto le funzioni per salvare ssid e password come dici tu però dovrei gestire "due destinazioni diverse". :thinking:
Vabbè che ssid e password, una volta impostate non le toccherei più (salvo modifiche alla wifi) però sto avendo difficoltà già a gestire un unico file :sweat_smile:
Il motivo per cui le salvo è perchè voglio arrivare ad un prodotto pronto all'uso per chiunque lo utilizzi.

Forse non mi sono spiegato bene.. Non c'è bisogno di salvarle in modo manuale.
Vengono salvate in automatico di default a meno che non venga impostato diversamente in modo esplicito.