0

i want to get my thingSpeak channel data into arduino by performing GET request every things works fine.Further i used Arduinojson lib to parse the JSON but i am getting failed every time when i try to parse it.I used arduinojson assistant to calculate the parsing program but still i am getting error. Below is my JSON and Failure message that i got every time in serial monitor.

{"channel":{"id":421932,"name":"remote_car","description":"Nothing up to this point !","latitude":"0.0","longitude":"0.0","field1":"MOTOR ONE","field2":"MOTOR TWO","field3":"MOTOR THREE","field4":"MOTOR FOUR","created_at":"2018-02-07T17:32:09Z","updated_at":"2018-03-17T07:08:49Z","last_entry_id":7},"feeds":[{"created_at":"2018-03-17T06:53:48Z","entry_id":4,"field1":"0"},{"created_at":"2018-03-17T06:59:22Z","entry_id":5,"field1":"0"},{"created_at":"2018-03-17T07:03:59Z","entry_id":6,"field1":"2"},{"created_at":"2018-03-17T07:08:49Z","entry_id":7,"field1":"1"}]}

Parse Failed...

this is my arduino code(i used arduino plus esp8266 to get my thinkSpeak channel data).

#include "WiFiEsp.h"
#include <ArduinoJson.h>
// Emulate Serial1 on pins 6/7 if not present
#ifndef HAVE_HWSERIAL1
#include "SoftwareSerial.h"
SoftwareSerial Serial1(2,3); // RX, TX
#endif
char ssid[] = "M T G";            // your network SSID (name)
char pass[] = "androidGUII";        // your network password
int status = WL_IDLE_STATUS;     // the Wifi radio's status
// Initialize the Ethernet client object
WiFiEspClient client;
static const char* host = "api.thingspeak.com";
static const char* apiKey = "H359MYV0P0KFG2VS";
const unsigned long HTTP_TIMEOUT = 10000; 

void setup()
{
  // initialize serial for debugging
  Serial.begin(115200);
  // initialize serial for ESP module
  Serial1.begin(9600);
  // initialize ESP module
  WiFi.init(&Serial1);

  // check for the presence of the shield
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue
    while (true);
  }

  // attempt to connect to WiFi network
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network
    status = WiFi.begin(ssid, pass);
  }
  // you're connected now, so print out the data
  Serial.println("You're connected to the network");
//  printWifiStatus();
  Serial.println();
}

void loop()
{
      const int httpPort = 80;
    if (!client.connect(host, httpPort)) {
        Serial.println("connection failed");
        return;
    }

 client.print("GET /channels/421932/fields/1.json?api_key=");
client.print(apiKey);
client.println("&results=4 HTTP/1.1");
client.print("Host:");
client.println(host);
client.println();
  while (client.available() == 0);
  while (!skipResponseHeaders());  // wait till something comes in; you may want to add a timeout here
while (client.available()) {                         // Now receive the data
    String line = client.readStringUntil('\n');
    if ( line.indexOf('{',0) >= 0 ) {                  // Ignore data that is not likely to be JSON formatted, so must contain a '{'
      Serial.println(line);                            // Show the text received
      parseData(line);
     }
  }
  client.stop();
  delay(10000);
}

void parseData(String data){
     const size_t bufferSize = JSON_ARRAY_SIZE(4) + JSON_OBJECT_SIZE(2) + 4*JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(12) + 520;
     DynamicJsonBuffer jsonBuffer(bufferSize);
     const char* json = data.c_str();
     JsonObject& root = jsonBuffer.parseObject(json);
      if(!root.success()){
        Serial.println("Parse Failed...");
      }
     JsonObject& channel = root["channel"];
long channel_id = channel["id"]; // 421932
const char* channel_name = channel["name"]; // "remote_car"
const char* channel_description = channel["description"]; // "Nothing up to this point !"
  Serial.println(channel_name);
  Serial.println(channel_description);
}

bool skipResponseHeaders() { 
  char endOfHeaders[] = "\r\n\r\n"; // HTTP headers end with an empty line 
  client.setTimeout(HTTP_TIMEOUT); 
  bool ok = client.find(endOfHeaders); 
  if (!ok) { Serial.println("No response or invalid response!"); } 
  return ok; 
} 

Any one have any idea how i am getting parsing failed message. Any help would be appreciated.

Wisal Muhammad
  • 15
  • 1
  • 3
  • 7

1 Answers1

0

It is a memory allocation failure. Your Arduino Uno has 2KB ob RAM and I found out, via a binary search on the size of the StaticJsonBuffer<size> object, that for this specific 566 byte long JSON string you need a JSON buffer of at least 785 bytes to parse it.

Use this minimal sketch to test the size:

#include <Arduino.h>
#include <avr/pgmspace.h>
#include <ArduinoJson.h>

#define stringToParse  \
        "{\"channel\":{\"id\":421932,\"name\":\"remote_car\",\"description\":\"Nothing up to this point !\",\"latitude\":\"0.0\",\"longitude\":\"0.0\",\"field1\":\"MOTOR ONE\",\"field2\":\"MOTOR TWO\",\"field3\":\"MOTOR THREE\",\"field4\":\"MOTOR FOUR\",\"created_at\":\"2018-02-07T17:32:09Z\",\"updated_at\":\"2018-03-17T07:08:49Z\",\"last_entry_id\":7},\"feeds\":[{\"created_at\":\"2018-03-17T06:53:48Z\",\"entry_id\":4,\"field1\":\"0\"},{\"created_at\":\"2018-03-17T06:59:22Z\",\"entry_id\":5,\"field1\":\"0\"},{\"created_at\":\"2018-03-17T07:03:59Z\",\"entry_id\":6,\"field1\":\"2\"},{\"created_at\":\"2018-03-17T07:08:49Z\",\"entry_id\":7,\"field1\":\"1\"}]}"

StaticJsonBuffer<785> jsonBuffer;
void parseData(const __FlashStringHelper* json){
    //const size_t bufferSize = JSON_ARRAY_SIZE(4) + JSON_OBJECT_SIZE(2) + 4*JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(12) + 520;
    //DynamicJsonBuffer jsonBuffer(bufferSize);
    //const char* json = data.c_str();
    JsonObject& root = jsonBuffer.parseObject(json);
    if(!root.success()){
        Serial.println("Parse Failed...");
        return;
    }
    JsonObject& channel = root["channel"];
    long channel_id = channel["id"]; // 421932
    const char* channel_name = channel["name"]; // "remote_car"
    const char* channel_description = channel["description"]; // "Nothing up to this point !"
    Serial.print("Channel name: "); Serial.println(channel_name);
    Serial.print("Channel description: "); Serial.println(channel_description);
    Serial.print("Channel id: ");
    Serial.println(channel_id);
}

void setup() {
    Serial.begin(9600);
    //We use the F() macro to create a flash string helper
    //this way, that huge JSON string is held in FLASH and not in precious RAM..
    parseData(F(stringToParse));
}

void loop() { }

If you decrease the buffer size by even 1 byte, parsing will fail.

Since you are using a DynamicJsonBuffer initially, your memory allocation will surely fail, since the heap can be really fragmented due to your other libraries (WiFiEspClient) and you are not able to find a continous 785 byte fragment on the heap. If the libraries tries to allocate memory object-wise (that is, not a continious segment), you might still get an out-of-memory error because

  1. the heap induces overhead per allocated object because of house-keeping information
  2. you fragment your heap over time, essentially leaving holes in it; this causes big allocations to fail because no continous segment could be found, although maybe in sum there is enough memory free
  3. other libraries / part of your program is also using the heap and you are actually out-of-memory no matter what your allocation strategy is

You have various options:

  • decrease the length of JSON string received by the Uno for it to be able to parse it.
    • For example, instead of huge JSON string have it receive a binary-formatted message with the information being as compactly packet in there as possible. You don't need to send "id\":421932, instead just make a field "id" in your packet format for a 32-bit integer. That decreases it from 11 bytes to 4 bytes.
  • use StaticJsonBuffer with fixed maximum size instead of DynamicJsonBuffer to make sure you can always parse the longest message (that is, if you have enough RAM free)
  • program the ESP8266 directly.

Really, your ESP8266 has about ~40KByte of user-usable RAM at startup and is at least an order of magnitude more powerful than your Uno. I wouldn't bother strapping a Arduino Uno to a mighty ESP8266 just for it to do JSON parsing.

Depending on what ESP8266 you have (ESP8266-01, ESP12F, NodeMCU board, ..) you should start looking for tutorials for programming it using the Arduino-ESP8266 framework.

Maximilian Gerhardt
  • 3,646
  • 16
  • 18