Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

root is destroy in the void loop #715

Closed
Ostrochibi opened this issue Mar 30, 2018 · 6 comments
Closed

root is destroy in the void loop #715

Ostrochibi opened this issue Mar 30, 2018 · 6 comments
Labels
question v5 ArduinoJson 5

Comments

@Ostrochibi
Copy link

Ostrochibi commented Mar 30, 2018

Hi Benoit,

First, thank you about the work you offer to us with this library.

I'm facing to an issue i can't resolve by myself. I wanna get back data to the spiff. I get it, i can see it with root.prettyPrintTo(Serial) in the void setup but when i wanna do the same in the void loop there is nothing in except an empty Json than i create in the beginning of the sketch.
Due to that, when i lost my data after each reboot because when i use my add function in the void loop root was empty.
I try to do a second object "root2" and surprise, when i do a root2.prettyPrintTo(Serial) in the void setup it's worked well but when i do the same in the void loop, i have an error root2 was not declared in this scope.

Can you help with that pls?

Version of your library 5.13.1
The scketch:

#include <ESP8266WiFi.h>
 #include <ESP8266WebServer.h>
 #include <TimeLib.h>
 #include <NtpClientLib.h>
 #include <ArduinoJson.h>
 #include <FS.h>
 
 #define ssid1      "Livebox"      // WiFi SSID
 #define password1  ""  // WiFi password
 #define ssid     "ESP"      // WiFi SSID
 #define password ""  // WiFi password
 #define HISTORY_FILE "/history.json"
 char json[10000];  
 String connectionMethod = "default";  // WiFi password
 String selectedPlastic = "none";
 
 
 const uint8_t GPIOPIN[9] = {13,5,14,12,16};  // Led
  
 ESP8266WebServer server ( 80 );
 String rootStrAfterLoad ;
 StaticJsonBuffer<10000> jsonBuffer;     
 JsonObject& root = jsonBuffer.createObject();
 JsonArray& plasticKind = root.createNestedArray("plasticKind");
 

 void savePlastic(){          
  File historyFile = SPIFFS.open(HISTORY_FILE, "r+");
  root.prettyPrintTo(Serial);
  root.printTo(historyFile);
  historyFile.close();  
 }


 

 void loadPlastic(){
  File file = SPIFFS.open(HISTORY_FILE, "r");
  if (!file){
    Serial.println("Aucun historique existe - No History Exist");
  } else {
    size_t size = file.size();
    if ( size == 0 ) {
      Serial.println("Fichier historique vide - History file empty !");
    } else {
        std::unique_ptr<char[]> buf (new char[size]);
        file.readBytes(buf.get(), size);
        JsonObject& root = jsonBuffer.parseObject(buf.get());
        if (!root.success()) {
          Serial.println("Impossible de lire le JSON - Impossible to read JSON file");
        } else {
          Serial.println("Historique charge - History loaded");
          root.prettyPrintTo(Serial);
          root.printTo(rootStrAfterLoad);
          
          }
      }
    file.close();
  }
}

 void addPlastic() {
  String tps = NTP.getTimeDateString();
  JsonObject& item = plasticKind.createNestedObject();
  item["plName"]= "Global";
  item["weltTemp"]= "210";
  item["timeRecycling"]= 0;
  item["timestamp"]= tps;
  loadPlastic();
}



  void sendPlasticList(){  
  root.printTo(json, sizeof(json));         
  server.send(200, "application/json", json);  
  Serial.println("Historique envoye");   
  }



  void setup() {

  
   for ( int x = 0 ; x < 8 ; x++ ) {
     pinMode(GPIOPIN[x], OUTPUT);
   }

  Serial.begin ( 115200 );
  Serial.println("scan start");

  // WiFi.scanNetworks will return the number of networks found
  int n = WiFi.scanNetworks();
  Serial.println("scan done");
  if (n == 0) {
    Serial.println("no networks found");
  } else {
    Serial.print(n);
    Serial.println(" networks found");
    for (int i = 0; i < n; ++i) {
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));
      Serial.print(" (");
      Serial.print(WiFi.RSSI(i));
      Serial.print(")");
      Serial.println((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? " " : "*");
      if (WiFi.SSID(i) == ssid1) {
        connectionMethod = "home";
        Serial.println ( connectionMethod );
      }else {      
        };
      delay(10);
    }
  }

  
   

   if (connectionMethod == "home"){
    Serial.print ( "Connecting to " ); 
    Serial.println ( ssid1 );
    WiFi.begin ( ssid1, password1 );
  // Attente de la connexion au réseau WiFi / Wait for connection
    while ( WiFi.status() != WL_CONNECTED ) {
      delay ( 500 ); Serial.print ( "." );
    }
  // Connexion WiFi établie / WiFi connexion is OK
    Serial.println ( "" );
    Serial.print ( "Connected to " ); Serial.println ( ssid1 );
    Serial.print ( "IP address: " ); Serial.println ( WiFi.localIP() );
   }else{
    WiFi.mode(WIFI_AP_STA);
    WiFi.softAP( ssid, password );
    Serial.print ( "Connected to " ); 
    Serial.println ( ssid );
    Serial.print ( "IP address: " ); 
    Serial.println ( WiFi.softAPIP());
    
   }
   delay(10);

   NTP.begin("pool.ntp.org", 1, true);
   NTP.setInterval(60);
   Serial.println(NTP.getTime());
   NTP.onNTPSyncEvent([](NTPSyncEvent_t error) {
    if (error) {
     Serial.print("Time Sync error: ");
      if (error == noResponse)
        Serial.println("NTP server not reachable");
      else if (error == invalidAddress)
        Serial.println("Invalid NTP server address");
    }
    else {
      Serial.print("Got NTP time: ");
      Serial.println(NTP.getTimeDateString(NTP.getLastNTPSync()));
    }
  });

   if (!SPIFFS.begin()){
     Serial.println("SPIFFS Mount failed");
    } else {
     Serial.println("SPIFFS Mount succesfull");
    }

loadPlastic();
JsonObject& root = jsonBuffer.parseObject(rootStrAfterLoad);
root.prettyPrintTo(Serial);

JsonObject& root2 = jsonBuffer.parseObject(rootStrAfterLoad);
root2.prettyPrintTo(Serial);
  

   server.on("/plasticList.json", sendPlasticList);

   server.serveStatic("/js", SPIFFS, "/js");
   server.serveStatic("/css", SPIFFS, "/css");
   server.serveStatic("/img", SPIFFS, "/img");
   server.serveStatic("/", SPIFFS, "/index.html");
 
   server.begin();
   Serial.println();
   Serial.println ( "HTTP server started" );
   
 }
 
 void loop() {
   server.handleClient();
  delay(100);
  delay(10000);
  Serial.println(rootStrAfterLoad);
  Serial.println();
  Serial.println();
  root.prettyPrintTo(Serial);
  Serial.println();
//  root2.prettyPrintTo(Serial);
  Serial.println();
//  
//  addPlastic();
//  savePlastic();
//  loadPlastic();
//  delay(10000);
 }

Have a good day!

@bblanchon
Copy link
Owner

Hi @Ostrochibi,

What immediately stands out is that this program abuses of global variables.
You should start by moving everything as local variables.
When you'll do that, you'll need to use a DynamicJsonBuffer and a String because the ESP only allows 4KB on the stack.

Regards,
Benoit

PS: If none of this makes sense, please read "The Missing C++ Chapter" in Mastering ArduinoJson.

@Ostrochibi
Copy link
Author

Ostrochibi commented Apr 12, 2018

Hi @bblanchon ,

thank you and sorry about my time response. I understand what you say. I modify the code to avoid the global variable. But when i return my root the json exported what not the same than in the function where live the return and the function where i call it.

the esp's code:

#include <ESP8266WiFi.h>
 #include <ESP8266WebServer.h>
 #include <TimeLib.h>
 #include <NtpClientLib.h>
 #include <ArduinoJson.h>
 #include <FS.h>
 
 #define ssid1      "Livebox-"      // WiFi SSID
 #define password1  ""  // WiFi password
 #define ssid     "ESP_recycleBot"      // WiFi SSID
 #define password ""  // WiFi password
 #define HISTORY_FILE "/history.json"
 char json[10000];  
 String connectionMethod = "default";  // WiFi password
 String selectedPlastic = "none";
 char* john = "{\"plasticKind\":[{\"plName\":\"Global\",\"weltTemp\":\"210\",\"timeRecycling\":0,\"timestamp\":\"18:12:42 09/04/2018\"},{\"plName\":\"Global\",\"weltTemp\":\"210\",\"timeRecycling\":0,\"timestamp\":\"18:13:02 09/04/2018\"}]}";
 
 const uint8_t GPIOPIN[9] = {13,5,14,12,16};  // Led
  
 ESP8266WebServer server ( 80 );
String rootStrAfterLoad ;
 StaticJsonBuffer<10000> jsonBuffer;     




 void savePlastic(JsonObject& root){          
  File historyFile = SPIFFS.open(HISTORY_FILE, "w");
  root.prettyPrintTo(Serial);
  root.printTo(historyFile); // Exporte et enregsitre le JSON dans la zone SPIFFS - Export and save JSON object to SPIFFS area
  historyFile.close();
  Serial.println("coucou");  
 }


 

 JsonObject&  loadPlastic(){
  File file = SPIFFS.open(HISTORY_FILE, "r");
  if (!file){
    Serial.println("Aucun historique existe - No History Exist");
  } else {
    size_t size = file.size();
    if ( size == 0 ) {
      Serial.println("Fichier historique vide - History file empty !");
    } else {
        std::unique_ptr<char[]> buf (new char[size]);
        file.readBytes(buf.get(), size);
        JsonObject& root = jsonBuffer.parseObject(buf.get());
        
        if (!root.success()) {
          Serial.println("Impossible de lire le JSON - Impossible to read JSON file");
        } else {
          Serial.println("Historique charge - History loaded");
          Serial.println("root in spiff function");
          root.printTo(Serial);
       
          return root;
          
          
          }
      }
    file.close();
  }
}

 void addPlastic() {
  JsonObject& root = loadPlastic();
  Serial.println("In addPlastic");
  root.printTo(Serial);
//  root["plasticKind"].prettyPrintTo(Serial);
//  String tps = NTP.getTimeDateString();
//  JsonObject& item = plasticKind.createNestedObject();
//  item["plName"]= "Global";
//  item["weltTemp"]= "210";
//  item["timeRecycling"]= 0;
//  item["timestamp"]= tps;
//  savePlastic();
}

  void sendPlasticList(){
  JsonObject& root = loadPlastic();
  root.printTo(json, sizeof(json));             // Export du JSON dans une chaine - Export JSON object as a string
  server.send(200, "application/json", json);   // Envoi l'historique au client Web - Send history data to the web client
  Serial.println("Historique envoye");   
  }

//                         VOID SETUP

  void setup() {

  
   for ( int x = 0 ; x < 8 ; x++ ) {
     pinMode(GPIOPIN[x], OUTPUT);
   }

  Serial.begin ( 115200 );
  Serial.println("scan start");

  // WiFi.scanNetworks will return the number of networks found
  int n = WiFi.scanNetworks();
  Serial.println("scan done");
  if (n == 0) {
    Serial.println("no networks found");
  } else {
    Serial.print(n);
    Serial.println(" networks found");
    for (int i = 0; i < n; ++i) {
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));
      Serial.print(" (");
      Serial.print(WiFi.RSSI(i));
      Serial.print(")");
      Serial.println((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? " " : "*");
      if (WiFi.SSID(i) == ssid1) {
        connectionMethod = "home";
        Serial.println ( connectionMethod );
      }else {      
        };
      delay(10);
    }
  }

  
   

   if (connectionMethod == "home"){
    Serial.print ( "Connecting to " ); 
    Serial.println ( ssid1 );
    WiFi.begin ( ssid1, password1 );
  // Attente de la connexion au réseau WiFi / Wait for connection
    while ( WiFi.status() != WL_CONNECTED ) {
      delay ( 500 ); Serial.print ( "." );
    }
  // Connexion WiFi établie / WiFi connexion is OK
    Serial.println ( "" );
    Serial.print ( "Connected to " ); Serial.println ( ssid1 );
    Serial.print ( "IP address: " ); Serial.println ( WiFi.localIP() );
   }else{
    WiFi.mode(WIFI_AP_STA);
    WiFi.softAP( ssid, password );
    Serial.print ( "Connected to " ); 
    Serial.println ( ssid );
    Serial.print ( "IP address: " ); 
    Serial.println ( WiFi.softAPIP());
    
   }
   delay(10);

   NTP.begin("pool.ntp.org", 1, true);
   NTP.setInterval(60);
   Serial.println(NTP.getTime());
   NTP.onNTPSyncEvent([](NTPSyncEvent_t error) {
    if (error) {
     Serial.print("Time Sync error: ");
      if (error == noResponse)
        Serial.println("NTP server not reachable");
      else if (error == invalidAddress)
        Serial.println("Invalid NTP server address");
    }
    else {
      Serial.print("Got NTP time: ");
      Serial.println(NTP.getTimeDateString(NTP.getLastNTPSync()));
    }
  });

   if (!SPIFFS.begin()){
     Serial.println("SPIFFS Mount failed");
    } else {
     Serial.println("SPIFFS Mount succesfull");
     loadPlastic();
    }

      
   server.on("/plasticList.json", sendPlasticList);
   /*HTTP_POST, []() {
     updateGpio();
   });
   */
   server.serveStatic("/js", SPIFFS, "/js");
   server.serveStatic("/css", SPIFFS, "/css");
   server.serveStatic("/img", SPIFFS, "/img");
   server.serveStatic("/", SPIFFS, "/index.html");
 
   server.begin();
   Serial.println();
   Serial.println ( "HTTP server started" );
   
 }
 
 void loop() {
   // put your main code here, to run repeatedly:
   server.handleClient();
  delay(100);
  delay(10000);

  addPlastic();
  
  delay(10000);

the serial output:

010f000, len 1384, room 16
tail 8
chksum 0x2d
csum 0x2d
v09f0c112
~ld
scan start
scan done
1 networks found
1: Livebox-C250 (-55)*
home
Connecting to Livebox-C250
.......
Connected to Livebox-C250
IP address: 192.168.1.23
1523553915
SPIFFS Mount succesfull
Historique charge - History loaded
root in spiff function
{"plasticKind":[{"plName":"Global","weltTemp":"210","timeRecycling":0,"timestamp":"07:58:32 12/04/2018"},{"plName":"Global","weltTemp":"210","timeRecycling":0,"timestamp":"07:58:53 12/04/2018"}]}
HTTP server started
Historique charge - History loaded
root in spiff function
{"plasticKind":[{"plName":"Global","weltTemp":"210","timeRecycling":0,"timestamp":"07:58:32 12/04/2018"},{"plName":"Global","weltTemp":"210","timeRecycling":0,"timestamp":"07:58:53 12/04/2018"}]}
In addPlastic
{"�":[{"plName":"Global","weltTemp":"210","timeRecycling":0,"timestamp":"07:58:32 12/04/2018"},{"plName":"Global","weltTemp":"210","timeRecycling":0,"timestamp":"07:58:53 12/04/2018"}]}

The plasticKind have disappear, can you tell me why and how i can solve this pls.

Thank you for the time you spend to answer me.

@bblanchon
Copy link
Owner

Hi @Ostrochibi,

I'm not sure that this is the solution to your problem, but I can spot something wrong:

char* john = "{\"plasticKind\":[{\"plName\":...

This variable must be a char[] or a const char* but it cannot be a char*.
There is probably a compiler warning about that, have a look at the compiler output.
(BTW, the "The Missing C++ Chapter" in Mastering ArduinoJson explains all of that).

Please try and tell me how it goes.

Thank you for the time you spend to answer me.

Thank you very much for saying that. I often beleive that people have no idea how much time I spend finding bugs in their program, but you proved me wrong ;-)

Regards,
Benoit

@bblanchon bblanchon reopened this Apr 13, 2018
@Ostrochibi
Copy link
Author

Hi @bblanchon ,

thank you for this quick answer.
This char is not use for my issue. Sorry, i should tell you where the issue live with more detail.

So, just look that

 JsonObject&  loadPlastic(){
  File file = SPIFFS.open(HISTORY_FILE, "r");
  if (!file){
    Serial.println("Aucun historique existe - No History Exist");
  } else {
    size_t size = file.size();
    if ( size == 0 ) {
      Serial.println("Fichier historique vide - History file empty !");
    } else {
        std::unique_ptr<char[]> buf (new char[size]);
        file.readBytes(buf.get(), size);
        JsonObject& root = jsonBuffer.parseObject(buf.get());
        
        if (!root.success()) {
          Serial.println("Impossible de lire le JSON - Impossible to read JSON file");
        } else {
          Serial.println("Historique charge - History loaded");
          Serial.println("root in spiff function");
          root.printTo(Serial);
       
          return root;
          
          
          }
      }
    file.close();
  }
}

and that

 void addPlastic() {
  JsonObject& root = loadPlastic();
  Serial.println("In addPlastic");
  root.printTo(Serial);

}

the root printed in the two function must be the same no? Instead of that, i have on one side :

root in spiff function
{"plasticKind":[{"plName":"Global","weltTemp":"210","timeRecycling":0,"timestamp":"07:58:32 12/04/2018"},{"plName":"Global","weltTemp":"210","timeRecycling":0,"timestamp":"07:58:53 12/04/2018"}]}

and on the otherside :

In addPlastic
{"�":[{"plName":"Global","weltTemp":"210","timeRecycling":0,"timestamp":"07:58:32 12/04/2018"},{"plName":"Global","weltTemp":"210","timeRecycling":0,"timestamp":"07:58:53 12/04/2018"}]}

the name of the array is replace by an unknow caracter, that is my issue. I suspect my declaration of the object returned, JsonObject& loadPlastic(){}, was not good but i dont know how do it in another way. Maybe i must use a JsonVariant instead because my JsonObject contain a JsonArray?

When i think about the time i spend to understand a new example of code, i understand how it can be long and difficult to you, specificly when the code is write by a newbie like me :).

@Ostrochibi
Copy link
Author

Hi @bblanchon ,

I tried to transform my JsonObject in JsonVariant but i have the same issue.

Have a good week end.

@bblanchon
Copy link
Owner

Hi @Ostrochibi,

I see the problem now:

std::unique_ptr<char[]> buf (new char[size]);
file.readBytes(buf.get(), size);
JsonObject& root = jsonBuffer.parseObject(buf.get());

Passing a char* (or char[]) makes ArduinoJson use the zero-copy mode.
In this mode, the JsonObject points to the bytes in the input.
The problem is that the input is local to the function; so it's destroyed as soon as the function returns.

To fix this issue, just pass the file object to parseObject() and let ArduinoJson do its job:

JsonObject& root = jsonBuffer.parseObject(file);

See also:

Regards,
Benoit

Repository owner locked and limited conversation to collaborators Sep 21, 2018
@bblanchon bblanchon added the v5 ArduinoJson 5 label Feb 6, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
question v5 ArduinoJson 5
Projects
None yet
Development

No branches or pull requests

2 participants