Sauvgarder JSON dans le SPIFFS d'un nodemcu

Bonjour a tous,
J'essaye de sauvegarder un Json dans le SPIFFS d'un nodemcu, pour les recharger après une panne d'électricité ou un reset du module.
j'ai remarque qu'après un reset cela ne récupère pas les données.
Toutes les variable sont des int.
Les librairies que j'utilise

#include <ArduinoJson.h>
#include <FS.h>
#include <LittleFS.h>
Je suis partie au debout avec l'exemple du JsonConfigFile de la librairie Arduinojson6.
rajouter quelques lignes selon des exemples trouver sur le net.

J'aimerais votre aide.

bool loadConfiguration() {
 File file = LittleFS.open("/config.json", "r");
 // File file = SPIFFS.open("/config.json", "r");
 if (!file) {
  Serial.println("Failed to open config file");
  return false;
 }

  size_t size = file.size();
  if (size > 1024) {
    Serial.println("Config file size is too large");
    return false;
  }

  // Allocate a buffer to store contents of the file.
  std::unique_ptr<char[]> buf(new char[size]);

  // We don't use String here because ArduinoJson library requires the input
  // buffer to be mutable. If you don't use ArduinoJson, you may as well
  // use file.readString instead.
  file.readBytes(buf.get(), size);
  
  // StaticJsonDocument<200> doc;
  DynamicJsonDocument jsonBuffer(2048);
  auto error = deserializeJson(jsonBuffer, buf.get());
  if (error) {
    Serial.println("Failed to parse config file");
  Serial.println(error.f_str());
    return false;
  }

  // Copy values from the JsonObject to the Config
 Usermax0 = jsonBuffer["Usermax0"];
 Usermin0 = jsonBuffer["Usermin0"];
 Usermax1 = jsonBuffer["Usermax1"];
 Usermin1 = jsonBuffer["Usermin1"];
 Usermax2 = jsonBuffer["Usermax2"];
 Usermin2 = jsonBuffer["Usermin2"];
 Usermax3 = jsonBuffer["Usermax3"];
 Usermin3 = jsonBuffer["Usermin3"];
 Usermax4 = jsonBuffer["Usermax4"];
 Usermin4 = jsonBuffer["Usermin4"];
 Usermax5 = jsonBuffer["Usermax5"];
 Usermin5 = jsonBuffer["Usermin5"];
 Usermax6 = jsonBuffer["Usermax6"];
 Usermin6 = jsonBuffer["Usermin6"];
 Usermax7 = jsonBuffer["Usermax7"];
 Usermin7 = jsonBuffer["Usermin7"];
 Usermax8 = jsonBuffer["Usermax8"];
 Usermin8 = jsonBuffer["Usermin8"];
 Usermax9 = jsonBuffer["Usermax9"];
 Usermin9 = jsonBuffer["Usermin9"];
 Usermax10 = jsonBuffer["Usermax10"];
 Usermin10 = jsonBuffer["Usermin10"];
 Usermax11 = jsonBuffer["Usermax11"];
 Usermin11 = jsonBuffer["Usermin11"];
 Usermax12 = jsonBuffer["Usermax12"];
 Usermin12 = jsonBuffer["Usermin12"];
 Usermax13 = jsonBuffer["Usermax13"];
 Usermin13 = jsonBuffer["Usermin13"];
 Usermax14 = jsonBuffer["Usermax14"];
 Usermin14 = jsonBuffer["Usermin14"];
 Usermax15 = jsonBuffer["Usermax15"];
 Usermin15 = jsonBuffer["Usermin15"];
 
  // Close the file (File's destructor doesn't close the file)
  file.close();
  return true;
}
bool saveConfiguration() {
// DynamicJsonDocument<1536> jsonBuffer;
 DynamicJsonDocument jsonBuffer(1536);

 File file = LittleFS.open("/config.json", "w");
 if (!file) {
  Serial.println("Failed to open config file for writing");
  return false;
  }

 // Set the values
 jsonBuffer["Usermax0"] = Usermax0;
 jsonBuffer["Usermin0"] = Usermin0;
 jsonBuffer["Usermax1"] = Usermax1;
 jsonBuffer["Usermin1"] = Usermin1;
 jsonBuffer["Usermax2"] = Usermax2;
 jsonBuffer["Usermin2"] = Usermin2;
 jsonBuffer["Usermax3"] = Usermax3;
 jsonBuffer["Usermin3"] = Usermin3;
 jsonBuffer["Usermax4"] = Usermax4;
 jsonBuffer["Usermin4"] = Usermin4;
 jsonBuffer["Usermax5"] = Usermax5;
 jsonBuffer["Usermin5"] = Usermin5;
 jsonBuffer["Usermax6"] = Usermax6;
 jsonBuffer["Usermin6"] = Usermin6;
 jsonBuffer["Usermax7"] = Usermax7;
 jsonBuffer["Usermin7"] = Usermin7;
 jsonBuffer["Usermax8"] = Usermax8;
 jsonBuffer["Usermin8"] = Usermin8;
 jsonBuffer["Usermax9"] = Usermax9;
 jsonBuffer["Usermin9"] = Usermin9;
 jsonBuffer["Usermax10"] = Usermax10;
 jsonBuffer["Usermin10"] = Usermin10;
 jsonBuffer["Usermax11"] = Usermax11;
 jsonBuffer["Usermin11"] = Usermin11;
 jsonBuffer["Usermax12"] = Usermax12;
 jsonBuffer["Usermin12"] = Usermin12;
 jsonBuffer["Usermax13"] = Usermax13;
 jsonBuffer["Usermin13"] = Usermin13;
 jsonBuffer["Usermax14"] = Usermax14;
 jsonBuffer["Usermin14"] = Usermin14;
 jsonBuffer["Usermax15"] = Usermax15;
 jsonBuffer["Usermin15"] = Usermin15;
 
 // Serialize JSON to file
 serializeJson(jsonBuffer, file);
 
 file.close();
 return true;
}

Est que cet exemple

Fonctionne sur votre montage ?

Ne postez pas juste un bout de code (Snippets R Us!). Avez vous configuré spiffs correctement ?

// Initialize SD library
  while (!SD.begin()) {
    Serial.println(F("Failed to initialize SD library"));
    delay(1000);
  }

L'exemple du JsonConfigFile est configurer pour une carte SD, je n'ai pas de carte SD a la place j'aimerais utiliser l'espace du SPIFFS.
Apres quelques changement j'ai commencer par ce code après avoir déplacer du code de place comme je n'étais pas sur si fonctionne bien.

Je suis repartie avec ce code:

#include <ArduinoJson.h>
#include <FS.h>

int MyValue1,MyValue2,MyValue3,MyValue4;
String MyString1,MyString2,MyString3;
int flag = 1;

bool loadConfiguration() {
 File file = SPIFFS.open("/config.json", "r");
 if (!file) {
  Serial.println("Failed to open config file");
  return false;
 }

  DynamicJsonDocument jsonBuffer(2048);
  DeserializationError error = deserializeJson(jsonBuffer, file);
  if (error) {
   Serial.print(F("deserializeJson() failed: "));
   Serial.println(error.f_str());
   return false;
  }

  // Copy values from the JsonObject to the Config
 MyValue1 = jsonBuffer["Value1"];
 MyValue2 = jsonBuffer["Value2"];
 MyValue3 = jsonBuffer["Value3"];
 MyValue4 = jsonBuffer["Value4"];
 MyString1 = jsonBuffer["StringValue1"].as<String>();
 MyString2 = jsonBuffer["StringValue2"].as<String>();
 MyString3 = jsonBuffer["MyString3"].as<String>();
  
  // Close the file (File's destructor doesn't close the file)
  file.close();
  return true;
}

bool saveConfiguration() {
  MyValue1 = random(1,99);
  MyValue2 = random(1,99);
  MyValue3 = random(1,99);
  MyValue4 = random(1,99);
  MyString1 = "MyString1";
  MyString2 = "MyString2";
  MyString3 = "MyString3";
  
  Serial.println("Before Saving:");
  Serial.print("MyValue1:"); Serial.println(MyValue1);
  Serial.print("MyValue2:"); Serial.println(MyValue2);
  Serial.print("MyValue3:"); Serial.println(MyValue3);
  Serial.print("MyValue4:"); Serial.println(MyValue4);
  Serial.print("MyString1:"); Serial.println(MyString1);
  Serial.print("MyString2:"); Serial.println(MyString1);
  Serial.print("MyString3:"); Serial.println(MyString1);
  
 File file = SPIFFS.open("/config.json", "w");
 if (!file) {
  Serial.println("Failed to open config file for writing");
  return false;
 }
 
 // DynamicJsonDocument<1536> jsonBuffer;
 DynamicJsonDocument jsonBuffer(1536);

 // Set the values
 jsonBuffer["Value1"] = MyValue1+1;
 jsonBuffer["Value2"] = MyValue2+1;
 jsonBuffer["Value3"] = MyValue3+1;
 jsonBuffer["Value4"] = MyValue4+1;
 jsonBuffer["StringValue1"] = MyString1;
 jsonBuffer["StringValue2"] = MyString2;
 jsonBuffer["StringValue3"] = MyString3;
 
 // Serialize JSON to file
 serializeJson(jsonBuffer, file);
 file.close();
 return true;
}

void setup() {
 Serial.begin(115200);
 MyValue1 = 0;
 MyValue2 = 0;
 MyValue3 = 0;
 MyValue4 = 0;
 
 Serial.println("Setup config:");
 Serial.print("MyValue1:"); Serial.println(MyValue1);
 Serial.print("MyValue2:"); Serial.println(MyValue2);
 Serial.print("MyValue3:"); Serial.println(MyValue3);
 Serial.print("MyValue4:"); Serial.println(MyValue4);

 Serial.println("\n\nMounting FS...\n");
 if (!SPIFFS.begin())
 {
  Serial.println("erreur SPIFFS");
  while (true); // on ne va pas plus loin
 }

 if(!saveConfiguration) {
  Serial.println(F("failed to Save...")); 
 }
 else {
  Serial.println(F("Saved OK..."));
 }

 if(!loadConfiguration) {
  Serial.println(F("Failed to load..."));
  }
 else {
  Serial.println(F("Load OK..."));
  Serial.println("After Loading:");
  Serial.print("MyValue1:"); Serial.println(MyValue1);
  Serial.print("MyValue2:"); Serial.println(MyValue2);
  Serial.print("MyValue3:"); Serial.println(MyValue3);
  Serial.print("MyValue4:"); Serial.println(MyValue4);
  Serial.print("MyString1:"); Serial.println(MyString1);
  Serial.print("MyString2:"); Serial.println(MyString1);
  Serial.print("MyString3:"); Serial.println(MyString1);
  }
}

void loop() {
 // put your main code here, to run repeatedly:
}

La j'ai remarqué que ca ne marche pas :frowning: je pense que cela vient de la mauvaise config du SPIFFS.

Ahh oui ce n'etais pas le final, par la suite je me suis retourne vers le code qui viens avec la librarire du esp8266 -> ConfigFile

je suis repartie pour ce code :

#include <ArduinoJson.h>
#include "FS.h"
#include <LittleFS.h>

int accessToken;

bool loadConfig() {
  File configFile = LittleFS.open("/config.json", "r");
  if (!configFile) {
    Serial.println("Failed to open config file");
    return false;
  }

  size_t size = configFile.size();
  if (size > 1024) {
    Serial.println("Config file size is too large");
    return false;
  }

  // Allocate a buffer to store contents of the file.
  std::unique_ptr<char[]> buf(new char[size]);

  // We don't use String here because ArduinoJson library requires the input
  // buffer to be mutable. If you don't use ArduinoJson, you may as well
  // use configFile.readString instead.
  configFile.readBytes(buf.get(), size);

  StaticJsonDocument<200> doc;
  auto error = deserializeJson(doc, buf.get());
  if (error) {
    Serial.println("Failed to parse config file");
    return false;
  }

  const char* serverName = doc["serverName"];
  accessToken = doc["accessToken"];

  // Real world application would store these values in some variables for
  // later use.

  Serial.print("Loaded serverName: ");
  Serial.println(serverName);
  Serial.print("Loaded accessToken: ");
  Serial.println(accessToken);
  return true;
}

bool saveConfig() {
  StaticJsonDocument<200> doc;
  doc["serverName"] = "api.example.com";
  doc["accessToken"] = 125;

  File configFile = LittleFS.open("/config.json", "w");
  if (!configFile) {
    Serial.println("Failed to open config file for writing");
    return false;
  }

  serializeJson(doc, configFile);
  return true;
}

void setup() {
  Serial.begin(115200);
  Serial.println("");
  delay(1000);
  Serial.println("Mounting FS...");

  if (!LittleFS.begin()) {
    Serial.println("Failed to mount file system");
    return;
  }


  if (!saveConfig()) {
    Serial.println("Failed to save config");
  } else {
    Serial.println("Config saved");
  }

  if (!loadConfig()) {
    Serial.println("Failed to load config");
  } else {
    Serial.println("Config loaded");
  }
}

void loop() {
}

Je l'ai modifier pour mes variable.
Avec cette exemple ca a l'air de fonctionner.

Apres avoir envoyer les données du Form, je lance la sauvegarde (saving), dans le setup je lance le chargement (loading) des données, ça ne marche pas toutes les données reste a zéro :frowning: , même en rajoutant un petit delay d'1s. dans le setup avant et après le chargement.

est-ce que 200 c'est assez ?

Un moyen de la savoir est d'utiliser l'assistant :

et les StaticJsonDocument sont sur la pile, donc attention à ne pas en mettre trop - sinon passer à un DynamicJsonDocument

ile me faut StaticJsonDocument<512> doc d'après l'assistant.

J'ai essayer de refaire mon code, j'ai un code en arduinojson 5 qui marchait, j'ai essayer de faire la migration en arduinojson6, j'espère que je le fais correctement, je ne l'ai pas encore testé.

Je n'ai pas reussi de faire ce que j'ai envie.

  1. de sauvgarder les donnees dans un fichier json dans le SPIFFS du NodeMcu
  2. de les charger dans le setup

J'ai mis mon code complet pour que vous puissiez l'examiner et me proposer les changement possible.
configjson.h c'est le fichier que j'ai fais selon les exemples de la version 6
configjson1.h c'est le fichier que j'ai essayer de faire la migration.

attachez le code ici, je ne vais pas sur les autres sites...

ESP_Multiplexer_XML.ino (18.8 KB)
html.h (24.3 KB)
jsonconfig.h (5.0 KB)
jsonconfig1.h (1.4 KB)
readSensor.h (2.8 KB)

avez vous noté ce warning?

ESP_Multiplexer_XML.ino:143:6: warning: the address of 'void saveConfiguration()' will never be NULL [-Waddress]
  143 |  if(!saveConfiguration) {
      |      ^~~~~~~~~~~~~~~~~

si vous voulez appeler la fonction il faut écrire

if(!saveConfiguration()) { // NE PAS OUBLIER LES PARENTHESES

le compilateur vous prévient aussi de ceci

/readSensor.h:65:12: warning: array subscript 15 is above array bounds of 'int [15]' [-Warray-bounds]
   65 |   sensor[15] = analogRead(SIG);

➜ tout débordement de tableau rend le fonctionnement de l'ensemble du programme indéterminé

ne laissez pas de warning lors de la compilation (activez les warning détaillés dans les préférences)

Je n'ai pas reçu de warning

Le résultat de la compilation:

Executable segment sizes:
ICACHE : 32768           - flash instruction cache 
IROM   : 375860          - code in flash         (default or ICACHE_FLASH_ATTR) 
IRAM   : 28165   / 32768 - code in IRAM          (IRAM_ATTR, ISRs...) 
DATA   : 1508  )         - initialized variables (global, static) in RAM/HEAP 
RODATA : 5600  ) / 81920 - constants             (global, static) in RAM/HEAP 
BSS    : 26928 )         - zeroed variables      (global, static) in RAM/HEAP 
Le croquis utilise 411133 octets (39%) de l'espace de stockage de programmes. Le maximum est de 1044464 octets.
Les variables globales utilisent 34036 octets (41%) de mémoire dynamique, ce qui laisse 47884 octets pour les variables locales. Le maximum est de 81920 octets.
esptool.py v3.0
Serial port COM4
Connecting....
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: 3c:71:bf:32:b0:25
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 415280 bytes to 278848...
Writing at 0x00000000... (5 %)
Writing at 0x00004000... (11 %)
Writing at 0x00008000... (16 %)
Writing at 0x0000c000... (22 %)
Writing at 0x00010000... (27 %)
Writing at 0x00014000... (33 %)
Writing at 0x00018000... (38 %)
Writing at 0x0001c000... (44 %)
Writing at 0x00020000... (50 %)
Writing at 0x00024000... (55 %)
Writing at 0x00028000... (61 %)
Writing at 0x0002c000... (66 %)
Writing at 0x00030000... (72 %)
Writing at 0x00034000... (77 %)
Writing at 0x00038000... (83 %)
Writing at 0x0003c000... (88 %)
Writing at 0x00040000... (94 %)
Writing at 0x00044000... (100 %)
Wrote 415280 bytes (278848 compressed) at 0x00000000 in 24.9 seconds (effective 133.6 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

faut ticker les cases à cocher pour les détails

Ok je ne l'avais pas remarquer, je l'ai coché

je n'ai pas de warning avec la compilation detaille.

bizarre... vous êtes sûr, ça défile très vite - moi j'ai ça qui défile parmi tous les messages

~/Desktop/ESP_Multiplexer_XML/ESP_Multiplexer_XML.ino: In function 'void handleReadUserPlantSelected()':
~/Desktop/ESP_Multiplexer_XML/ESP_Multiplexer_XML.ino:143:6: warning: the address of 'void saveConfiguration()' will never be NULL [-Waddress]
  143 |  if(!saveConfiguration) {
      |      ^~~~~~~~~~~~~~~~~
~/Desktop/ESP_Multiplexer_XML/ESP_Multiplexer_XML.ino: In function 'void setup()':
~/Desktop/ESP_Multiplexer_XML/ESP_Multiplexer_XML.ino:345:7: warning: the address of 'void loadConfiguration()' will never be NULL [-Waddress]
  345 |   if(!loadConfiguration) { Serial.println(F("Failed to load...")); }
      |       ^~~~~~~~~~~~~~~~~
In file included from ~/Desktop/ESP_Multiplexer_XML/ESP_Multiplexer_XML.ino:83:
~/Desktop/ESP_Multiplexer_XML/readSensor.h: In function 'void getSoilHumidity()':
~/Desktop/ESP_Multiplexer_XML/readSensor.h:65:12: warning: array subscript 15 is above array bounds of 'int [15]' [-Warray-bounds]
   65 |   sensor[15] = analogRead(SIG);
      |   ~~~~~~~~~^
~/Desktop/ESP_Multiplexer_XML/ESP_Multiplexer_XML.ino:39:5: note: while referencing 'sensor'
   39 | int sensor[15];
      |     ^~~~~~
~/Desktop/ESP_Multiplexer_XML/ESP_Multiplexer_XML.ino: In function 'void driveSolenoid()':
~/Desktop/ESP_Multiplexer_XML/ESP_Multiplexer_XML.ino:201:35: warning: array subscript 15 is above array bounds of 'int [15]' [-Warray-bounds]
  201 |   solenoidState15 = solenoidStatus(sensor[15], solenoid15, Usermax15, Usermin15);
      |                     ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~/Desktop/ESP_Multiplexer_XML/ESP_Multiplexer_XML.ino:39:5: note: while referencing 'sensor'
   39 | int sensor[15];
      | 

donc vous avez oublié les parenthèses et vous débordez dans votre tableau

compilation.pdf (305.1 KB)

J'ai ajouter le resultat de la compilation

vous avez quitté et redémarré l'IDE ?

Bonsoir j'ai redémarré ce soir l'IDE et relance la compile, je ne reçoit pas de warning.
si le int sensor[15] pose problème je peux mettre plusieurs variables.

Ce qui m'intrigue le plus, c'est la partie de la sauvegarde du JSON, de reussir a les sauvegarder pour pouvoir les charger dans le setup après un reset ca pourrait être aussi une panne d'électricité.