Arduinojson: Data dropping off JSON String in Loop

Created on 14 Mar 2016  路  3Comments  路  Source: bblanchon/ArduinoJson

Hi There,
Firstly, thank you for such an amazing Library. I've been using it a while and it makes things so much more simple for my code.

I'm unfortunately having an issue though that I haven't come across before and was hoping that maybe you could point out to me where I'm going wrong.

The Issue I'm having is the JSON data that I pass to a string seems to drop the end off each time until there is nothing left (for example, {"Probe0":"10.00","Probe1":"10.00","Probe2":"10.00","Probe3":"10.00"}{"Probe0":"15.00","Probe1":null}{}{}{}{}{}{}{}{}{}{}...

#include <ArduinoJson.h>

StaticJsonBuffer<200> jsonBuffer;

void setup() {
  Serial.begin(9600);
  while (!Serial) {
    // wait serial port initialization
  }
}

float fProbeSample[4] = {100,200,300,400};
int iReadingCount[4] = {10,20,30,40};
String sDataString;

void loop() {
  // not used in this example
  JsonObject& jobject = jsonBuffer.createObject();
  for (int i = 0; i <= 3; i++)
      {
        String sProbeNumber = "Probe" + String(i);
        float fReading = fProbeSample[i] / iReadingCount[i];
        jobject[sProbeNumber] = String(fReading);
        fProbeSample[i] = fProbeSample[i] * 1.5;
      }

      jobject.printTo(sDataString);

      Serial.print(sDataString);
      sDataString = "";
      delay(2000);
}

Can you see where I may possibly be going wrong?

question

Most helpful comment

Easy... you're defining jsonbuffer as a global object. Bad idea...
See

https://arduinojson.org/faq/the-first-parsing-succeeds-why-do-the-next-ones-fail

and

https://arduinojson.org/doc/pitfalls/#4-dont-reuse-the-same-jsonbuffer

and

https://github.com/bblanchon/ArduinoJson/issues/242

you should have

void loop() {
  // not used in this example

StaticJsonBuffer<200> jsonBuffer;


  JsonObject& jobject = jsonBuffer.createObject();
  for (int i = 0; i <= 3; i++)
      {
        String sProbeNumber = "Probe" + String(i);
        float fReading = fProbeSample[i] / iReadingCount[i];
        jobject[sProbeNumber] = String(fReading);
        fProbeSample[i] = fProbeSample[i] * 1.5;
      }

      jobject.printTo(sDataString);

      Serial.print(sDataString);
      sDataString = "";
      delay(2000);
}

(not checked your code fully. but the buffer needs to be scoped... It might also no be big enough. What platform are you using?

All 3 comments

Easy... you're defining jsonbuffer as a global object. Bad idea...
See

https://arduinojson.org/faq/the-first-parsing-succeeds-why-do-the-next-ones-fail

and

https://arduinojson.org/doc/pitfalls/#4-dont-reuse-the-same-jsonbuffer

and

https://github.com/bblanchon/ArduinoJson/issues/242

you should have

void loop() {
  // not used in this example

StaticJsonBuffer<200> jsonBuffer;


  JsonObject& jobject = jsonBuffer.createObject();
  for (int i = 0; i <= 3; i++)
      {
        String sProbeNumber = "Probe" + String(i);
        float fReading = fProbeSample[i] / iReadingCount[i];
        jobject[sProbeNumber] = String(fReading);
        fProbeSample[i] = fProbeSample[i] * 1.5;
      }

      jobject.printTo(sDataString);

      Serial.print(sDataString);
      sDataString = "";
      delay(2000);
}

(not checked your code fully. but the buffer needs to be scoped... It might also no be big enough. What platform are you using?

Ofcourse!!! I knew I was doing something wrong.

Thanks so much. I'm at work now so I can't try it just yet, but I will be sure to as soon as I can (possibly in 2 hours or so).

What is the best way to decide on the Buffer size? I'm running it on an ESP8266 (flashed with Arduino).

I've also used it on a Mega2560 and didn't have any issues (and believe I made the stupid mistake of declaring it globally there too.)

On the ESP8266, the stack is limited to 4KB and but the heap is big; so you can safely use a DynamicJsonBuffer, which will grow as needed.
However, if you want to keep StaticJsonBuffer or want to set the right initial size of the DynamicJsonBuffer, keep reading...

Computing the size of the buffer is usually done with the macros JSON_OBJECT_SIZE() and JSON_ARRAY_SIZE(), but in you case it's more complicated.
Indeed, you're using temporary Strings that get duplicated inside the JsonBuffer.
So the required size it the size of the JSON object tree (that can be computed with the macros), plus the sum of the length of all strings.

For example for:

{"Probe0":"10.00","Probe1":"10.00","Probe2":"10.00","Probe3":"10.00"}

It would be:

  1. JSON_OBJECT_SIZE(4) because you store an object of 4 elements
  2. 7 bytes to store "Probe0"
  3. 6 bytes to store "10.00"
  4. 7 bytes to store "Probe1"
  5. 6 bytes to store "10.00"
  6. 7 bytes to store "Probe2"
  7. 6 bytes to store "10.00"
  8. 7 bytes to store "Probe3"
  9. 6 bytes to store "10.00"

As you can see, it become quite complicated because it heavily depends on runtime value.
My advice it to try with a big JsonBuffer and call JsonBuffer::size() to check the current size.

See:

For the records, you program would be much more efficient if the JSON was looking like this:

{"Probes":[10,10,10,10]}

because you could have zero duplication and a very tiny JsonBuffer.

Was this page helpful?
0 / 5 - 0 ratings