0

I'm making a small IOT project using the ESP8266 in which I make 2 API calls:

  1. api.openweathermap.org for weather data
  2. api.timezonedb.com

The request logic is the same for both calls, the only difference being how I parse the response string. The first response is parsed fine, while the other isn't.

  1. I print the String responses to Serial, they look fine.
  2. Tried both Dynamic and Static buffers to no avail.
  3. Making the request only to the second API, still not being parsed.
  4. If I make a test and just make the response a String, char[] or char*, it parses fine.

Parsing logic [works]:

StaticJsonBuffer<1000> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(response);
float raw = root[String("main")][String("temp")].as<float>();

Parsing logic: [does not work]

StaticJsonBuffer<500> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(response);

String data = root[String("formatted")].as<String>();

The response object looks like this:

{
  "status": "OK",
  "message": "",
  "formatted": "2017-06-30 11:34:13"
}

Request logic:

String RequestAPI::performRequest(String url, char* host){
WiFiClient client;
if (!client.connect(host, port)) {
    lcd -> clearScreen();
    lcd -> drawText("Failed to connect to API", 0, 0, this -> randomUint16());
    delay(5000);
    return "";
}

char endOfHeaders[] = "\r\n\r\n";
client.print(
String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" + 
"Connection: close\r\n\r\n"
);
// Skiping HTTP headers from the response
client.find(endOfHeaders);

unsigned long startTime = millis();
while(client.available() == 0){
    if(millis() - startTime > this -> timeout){
        lcd -> clearScreen();
        lcd -> drawText("API request failed", 0, 0, this -> randomUint16());
        delay(5000);
        return "";
    }
}

String response = "";
while(client.available()){
    response += client.readStringUntil('\r');
}
Serial.println(response);

return response;
}

Now I'm thinking, could the empty message be causing a bug? Or am I doing something wrong?

  • You say that the 2 responses are parsed differently, but only show one method. Also the line String data = root[String("formatted")].as<String>(); doesn't look right. From the examples I think it should be String data = String(root["formatted"]); – Code Gorilla Jun 30 '17 at 10:07
  • @CodeGorilla Updated answer with the working parser. – MustSeeMelons Jun 30 '17 at 11:14
  • @CodeGorilla Your suggestion ends up with: 'String(ArduinoJson::JsonObjectSubscript<const char*>)' is ambiguous – MustSeeMelons Jun 30 '17 at 11:26
  • Strange - I was just looking at the examples, github.com/bblanchon/ArduinoJson/blob/master/examples/…, sorry I couldn't help. – Code Gorilla Jun 30 '17 at 11:30
  • very helpful, I'm working a similar problem. Any chance you could share your entire code? Especially more details on the section on handling the Get request timeout. unsigned long startTime = millis(); while(client.available() == 0){ if(millis() - startTime > this -> timeout){ lcd -> clearScreen(); lcd -> drawText("API request failed", 0, 0, this -> randomUint16()); delay(5000); return ""; } } – micromet Sep 18 '17 at 0:33
1

The issue was caused because of: https://en.wikipedia.org/wiki/Chunked_transfer_encoding

Was not obvious as the data printed to the serial looked completely fine. Fixed with the below code:

client.print(
  String("GET ") + url + " HTTP/1.0\r\n" +
  "Host: " + host + "\r\n" + 
  "Connection: close\r\n\r\n"
);

Dunno why it worked for one API but not the other though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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