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.

1 Answer 1

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.

16
  • Hi sir thank you for your precious time...i modified the code according to your instruction but but now i am getting this..strange info...
    – Wisal
    Commented Mar 18, 2018 at 12:21
  • Con¬B Parse Failed.
    – Wisal
    Commented Mar 18, 2018 at 12:22
  • Does the above sketch work on its own? Edit your question to include the full code and runtime error. Commented Mar 18, 2018 at 12:24
  • the above code works fine when use stand alone but when i modified it for my own purpose then it throws the above error...my main goal is to received the json from thingspeak and then parse it...
    – Wisal
    Commented Mar 18, 2018 at 12:39
  • you can look up into my main arduino code sir.
    – Wisal
    Commented Mar 18, 2018 at 12:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.