The following correctly requests and parses a json string from a local server, but only twice before we get a “parse fail”. If I manually increase the size of the StaticJsonBuffer (I tried up to 10000) it works for more iterations and then fails. Any suggestions? I tried to use DynamicJsonBuffer jsonBuffer(bufferSize); but this would not compile.
#include <SparkJson.h>
#include <ArduinoJson.h>
#include "application.h"
#include "HttpClient.h"
//Sample of string
///const char[] = {"data": [{"time": 0, "headsign": "Middlesex Ave & Second St", "id": "38428705"}, {"time": 25, "headsign": "Wellington", "id": "38428527"}, {"time": 61, "headsign": "Wellington via Veterans Senior Center", "id": "38428504"}]}
const size_t bufferSize = JSON_ARRAY_SIZE(6) + JSON_OBJECT_SIZE(1) + 6*JSON_OBJECT_SIZE(3) + 390;
StaticJsonBuffer<bufferSize> jsonBuffer;
HttpClient http;
http_request_t request;
http_response_t response;
// Headers currently need to be set at init, useful for API keys etc.
http_header_t headers[] = {
// { "Content-Type", "application/json" },
// { "Accept" , "application/json" },
{ "Accept" , "*/*"},
{ NULL, NULL } // NOTE: Always terminate headers will NULL
};
void tickTock() {
//Create path for http address
request.hostname = "10.1.41.87";
request.port = 5000;
request.path = "/";
//Get http response and print status, length and response
http.get(request, response, headers);
Serial.println(response.status, DEC);
Serial.println(response.body.length(), DEC);
Serial.println(response.body);
//Convert json String to char*
int j_length = response.body.length()+1;
char json[j_length];
response.body.toCharArray(json, j_length);
//Create json object
JsonObject& root = jsonBuffer.parseObject(json);
if (!root.success())
Serial.println("Parse fail");
else
Serial.println("Parse success");
const char* direction = root["data"][0]["headsign"];
int arrival = root["data"][0]["time"];
Serial.println(direction);
Serial.println(arrival, DEC);
}
Timer timer(5000, tickTock);
void setup() {
timer.start();
Serial.begin(9600);
}
void loop() {
}
I found ArduinoJson to be unreliable for large JSON data. It keeps too many copies of the data and uses too many heap-based options for use in a limited memory environment, in my opinion.
I wrote JsonParserGeneratorRK to solve this issue. The API is quite different from ArduinoJson/SparkJson, but it’s really memory-efficient.
Does it need to have the JSON in a specific format? The JSON (shown below) that parsed with ArduinoJson will not parse with RK. Below is the code that worked with ArduinoJson now modified for RK. It did work with the test2 string.
Great. That works perfectly. Would you mind also provided an example of how to retrieve the number of objects in a Json array? i.e. the data array shown above.
I did something similar a while back. This loads a JSON string and then loops through the JSON elements. I was sending JSON messages to a Photon via UDP multicast. It’s probably not the most efficient method of looping through elements but it’s a working example.
//char msg_cp[255] = "";
JsonParserStatic<2000, 250> jparser; //2000 is oversized to accomodate a minium Network MTU of 1500 with a token every ~8 bytes.
void ParseNew(char *NewCmd)
{
//bool error = false;
jparser.clear();
jparser.addString(NewCmd);
if (!jparser.parse()) {
Log.error("JSON parse failed. Check your format.");
Log.error("Cmd Txt: %s", NewCmd);
return;
}
for (int i=0; i<32; i++) {
const JsonParserGeneratorRK::jsmntok_t *targetKeyTok;
const JsonParserGeneratorRK::jsmntok_t *targetValueTok;
String targetKeyName;
size_t targetKeyLen;
if (jparser.getKeyValueTokenByIndex(jparser.getOuterObject(), targetKeyTok, targetValueTok, i)) {
if (jparser.getTokenValue(targetKeyTok, targetKeyName)) {
Log.info("(%i) New cmd targets device/group: %s", i, targetKeyName.c_str());
} else {
//Log.error("Cannot parse target object %i or end of objects.", i);
//error = true;
break;
}
}
}
} //ParseNew