Arduinojson: Complex Nested Json Objects

Created on 21 Apr 2016  Â·  10Comments  Â·  Source: bblanchon/ArduinoJson

Sorry to ask a question you've already answered... but I've been unable to figure out exactly how to implement the solution you mentioned in issue #252 with my json requirements.

I would like to output my json in the following format:

{"networks":{
  0 : {
    "ssid":"asdf",
    "rssi":"test",
    etc etc etc
  },
  1 : {
    "ssid":jkl",
    "rssi":"fubar",
    etc etc etc
  }
}}

I've tried your example in about as many ways as I can think of, but obviously I'm missing something?

My code, which currently just outputs the information at the root level...

String scan_network() {
  DEBUG_PRINT(F("Scanning available networks..."));

  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  byte n = WiFi.scanNetworks();

  DEBUG_PRINT(F("found "));
  DEBUG_PRINT(n);
  DEBUG_PRINT(F("..."));

  StaticJsonBuffer<200> jsonBuffer;
  JsonObject& root = jsonBuffer.createObject();
  String retJson;

  for(int i=0;i<n;i++) {
    root["ssid"] = WiFi.SSID(i);
    root["encryption"] = WiFi.encryptionType(i);
    root["rssi"] = WiFi.RSSI(i);
    root["bssid"] = WiFi.BSSIDstr(i);
    root["channel"] = WiFi.channel(i);
    root["isHidden"] = WiFi.isHidden(i);
  }
  root.printTo(retJson);
  DEBUG_PRINTLN(F("ok!"));

  return retJson;
}
question

Most helpful comment

Hi @bepursuant,

There are three problems in your program:

  1. You try to generate invalid JSON
  2. The JsonBuffer is too small
  3. The loop overrides the root values

To address problem 1, I'll simply assume that the JSON is the following:

{
  "networks": [
    {
      "ssid": "foo",
      "rssi": -70
    },
    {
      "ssid": "bar",
      "rssi": -80
    }
  ]
}

To address problem 2, without further information, I suggest to switch to a DynamicJsonBuffer.

To address problem 3, you just need to call createNestedObject() in the loop.

Here is the final program:

String scan_network() {
   // ...

  DynamicJsonBuffer jsonBuffer;
  JsonObject& root = jsonBuffer.createObject();

  JsonArray& networks = root.createNestedArray("networks");

  for(int i=0;i<n;i++) {
    JsonObject& network = networks.createNestedObject();
    network["ssid"] = WiFi.SSID(i);
    network["encryption"] = WiFi.encryptionType(i);
    network["rssi"] = WiFi.RSSI(i);
    network["bssid"] = WiFi.BSSIDstr(i);
    network["channel"] = WiFi.channel(i);
    network["isHidden"] = WiFi.isHidden(i);
  }

  String retJson;
  root.printTo(retJson);
  return retJson;
}

All 10 comments

Hi @bepursuant,

There are three problems in your program:

  1. You try to generate invalid JSON
  2. The JsonBuffer is too small
  3. The loop overrides the root values

To address problem 1, I'll simply assume that the JSON is the following:

{
  "networks": [
    {
      "ssid": "foo",
      "rssi": -70
    },
    {
      "ssid": "bar",
      "rssi": -80
    }
  ]
}

To address problem 2, without further information, I suggest to switch to a DynamicJsonBuffer.

To address problem 3, you just need to call createNestedObject() in the loop.

Here is the final program:

String scan_network() {
   // ...

  DynamicJsonBuffer jsonBuffer;
  JsonObject& root = jsonBuffer.createObject();

  JsonArray& networks = root.createNestedArray("networks");

  for(int i=0;i<n;i++) {
    JsonObject& network = networks.createNestedObject();
    network["ssid"] = WiFi.SSID(i);
    network["encryption"] = WiFi.encryptionType(i);
    network["rssi"] = WiFi.RSSI(i);
    network["bssid"] = WiFi.BSSIDstr(i);
    network["channel"] = WiFi.channel(i);
    network["isHidden"] = WiFi.isHidden(i);
  }

  String retJson;
  root.printTo(retJson);
  return retJson;
}

This is beautiful! I think a lot of my trouble came from my incorrect JSON requirements. Using the method you outlined above, I was able to convert my entire API to return JSON using this library.

Thank you so much for the thorough answer and detailed response. Is there a reason (I didn't see) DynamicJsonBuffer in the example?

Thanks again! I'm sure this answer will be used by more than just me :)

I chose DynamicJsonBuffer because I assumed you were running on an ESP8266.
The stack on the ESP8266 is limited to 4KB, so it's not possible to have a big StaticJsonBuffer.

You can optimize the performance of the program by specifying an initial size to the constructor of the DynamicJsonBuffer.

I added a link to this question in the FAQ: How to create complex nested objects?

I'm having difficulty trying to figure out how to decode double nested objects. For example I'm using WeatherUnder.com API json calls and sometimes I'll get an error Json:

{ "response": { "version":"0.1", "termsofService":"http://www.wunderground.com/weather/api/d/terms.html", "features": { "conditions": 1 }, "error": { "type": "querynotfound" ,"description": "No cities match your search query" } } }

I'm trying to get at the error description to display message to the user.

Here is my (simplified code):
` DynamicJsonBuffer jsonBuffer(4000);

//Load data into Json object and parse
JsonObject& json = jsonBuffer.parseObject(payload);

if (json.success()) {//success
if (!json.containsKey(F("current_observation"))) {
WU.hasError = true;
return;
}
WU.temp_f = json[F("current_observation")][temp_f];
}
`

But what I really want is something like this (this of course does not work at all):
if (!json.containsKey("response","error")) { errortext = json[F("response")]["error"]["description"]; return; }

So how can I a. check if a deeply nested key exists, and b. get a really deeply nested value?
EDIT: Not sure why the code isn't formatted properly....

Hi Terry,

I would do this:

const char* error = json["response"]["error"]["description"];

if (error)
{
    Serial.println(error);
    return;
}

Regards,
Benoit

PS: see GitHub Syntax Highlighting

Benoit -
Thanks that worked perfectly. I guess .containsKey is not able to resolve
[...][...][...][etc]. Would you recommend using that method to determine
if a key worked instead of using .containsKey?
I think I'd recommend updating the wiki with that example to show people
how to extract data from a deeply tested Json, as well as checking to see
if it exists

On 17 April 2017 at 14:36, Benoît Blanchon notifications@github.com wrote:

Hi Terry,

I would do this:

const char* error = json["response"]["error"]["description"];
if (error)
{
Serial.println(error);
return;
}

Regards,
Benoit

PS: see GitHub Syntax Highlighting
https://guides.github.com/features/mastering-markdown/

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/bblanchon/ArduinoJson/issues/264#issuecomment-294554222,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AXv_jWJiIX74Gn88SH5MCun6MaXRCUBQks5rw7EegaJpZM4IMUFA
.

--
Terry Myers (T.J.)

Here you go: JsonObject::containsKey(); with an example that should be familiar 😉

That's fantastic. I'm glad I can help make your library documentation that
much better. Its already pretty comprehensive :)

On 20 April 2017 at 03:46, Benoît Blanchon notifications@github.com wrote:

Here you go: JsonObject::containsKey()
https://arduinojson.org/api/jsonobject/containskey/;
with an example that should be familiar 😉

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/bblanchon/ArduinoJson/issues/264#issuecomment-295614559,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AXv_jVCugpQ_QNzLSZGs8n60H5vD1XKyks5rxw1LgaJpZM4IMUFA
.

--
Terry Myers (T.J.)

{"data":{"id":82,"brand_name":"6s","item_name":"iPhone","fault":"screen","technician_id":1,"dateOfBooking":"2018-07-26","timeOfBooking":"08:06:15","created_at":"2018-07-21 17:04:28","updated_at":"2018-07-21 17:04:28"}}
how to convert into gson??

@umerfarooq786, try the ArduinoJson Assistant.

How to use ArduinoJson

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kylegordon picture kylegordon  Â·  6Comments

ghost picture ghost  Â·  7Comments

timpur picture timpur  Â·  5Comments

nardev picture nardev  Â·  5Comments

egadgetjnr picture egadgetjnr  Â·  3Comments