bblanchon / ArduinoJson

📟 JSON library for Arduino and embedded C++. Simple and efficient.
https://arduinojson.org
MIT License
6.7k stars 1.12k forks source link

CreateObject question #631

Closed beicnet closed 6 years ago

beicnet commented 6 years ago

Hi there,

I wish to create sub categories in the root, I did not find any docu for that.

I would like to do it like this, sensors is a root:

sensors
- dht11
-- temperature
-- humidity
- sht30
-- temperature
-- humidity

Thank you for your answer! ;)

Kind regards, Viktor

bblanchon commented 6 years ago

Hi,

I pasted the following in the ArduinoJson Assistant:

{
  "sensors": {
    "dht11": {
      "temperature": 21,
      "humidity": 50
    },
    "sht30": {
      "temperature": 21,
      "humidity": 50
    }
  }
}

Here is the serialization code:

const size_t bufferSize = JSON_OBJECT_SIZE(1) + 3*JSON_OBJECT_SIZE(2);
DynamicJsonBuffer jsonBuffer(bufferSize);

JsonObject& root = jsonBuffer.createObject();

JsonObject& sensors = root.createNestedObject("sensors");

JsonObject& sensors_dht11 = sensors.createNestedObject("dht11");
sensors_dht11["temperature"] = 21;
sensors_dht11["humidity"] = 50;

JsonObject& sensors_sht30 = sensors.createNestedObject("sht30");
sensors_sht30["temperature"] = 21;
sensors_sht30["humidity"] = 50;

root.printTo(Serial);

Please apologize for the delay, I focused on finishing the book.

Regards, Benoit

beicnet commented 6 years ago

Thank you for your fast response @bblanchon and congratz for your Book too! ;)

I tried your sniplet/proposition and it's working almost 100%, but have a little issue here:

The current output (the issue is that it's cutting of the leading zero's and also adding some other decimal numbers too):

{
  "ESP8266": {
    "NTC": {
      "temperature": 18.68202
    },
    "DHT11": {
      "temperature": 21,
      "humidity": 56
    },
    "SHT30": {
      "temperature": 21.56596,
      "humidity": 61.18258
    },
    "BMP180": {
      "temperature": 21.9,
      "pressure": 1002.36
    },
    "WU": {
      "temperature": 6.9,
      "humidity": 90,
      "pressure": 1012
    }
  }
}

it need to look like this (I'm sending exactly these values to Json object):

{
  "ESP8266": {
    "NTC": {
      "temperature": 18.68
    },
    "DHT11": {
      "temperature": 21.00,
      "humidity": 56.00
    },
    "SHT30": {
      "temperature": 21.56,
      "humidity": 61.18
    },
    "BMP180": {
      "temperature": 21.90,
      "pressure": 1002.36
    },
    "WU": {
      "temperature": 6.90,
      "humidity": 90.00,
      "pressure": 1012.00
    }
  }
}

Please advise!

Kind regards, Viktor

bblanchon commented 6 years ago

Hi Viktor,

Since version 5.10, ArduinoJson doesn't support a fixed number of digits anymore. I don't think this feature will be restored because I don't see the point.

To reduce the number of digits, you can round the value in your program. Use this function for instance:

// Rounds a number to 2 decimal places
// Example: round(3.14159) -> 3.14
double round2(double value) {
   return (int)(value * 100 + 0.5) / 100.0;
}

If you need trailing zeros, you need to use RawJson, but it will be a pain in the butt. See #566.

Why do you need this feature after all?

Regards, Benoit

beicnet commented 6 years ago

Hey @bblanchon,

I tried your round2 fucntion, but it's not what I wish, see the output:

{
  "ESP8266": {
    "NTC": {
      "temperature": 18
    },
    "DHT11": {
      "temperature": 19,
      "humidity": 50
    },
    "SHT30": {
      "temperature": 19.28,
      "humidity": 57.87
    },
    "BMP180": {
      "temperature": 19.6,
      "pressure": 999.72
    },
    "WU": {
      "temperature": 6.1,
      "humidity": 79,
      "pressure": 1009
    }
  }
}

Also I don't know from where your library pulling these values too 18.68202

If you see my own XML parser output you will se the difference what I'm sending to parsers:

<?xml version='1.0'?>
 <ESP8266>
   <NTC>
     <temperature>18.00</temperature>
   </NTC>
   <DHT11>
     <temperature>19.00</temperature>
     <humidity>49.00</humidity>
   </DHT11>
   <SHT30>
     <temperature>19.31</temperature>
     <humidity>57.71</humidity>
   </SHT30>
   <BMP180>
     <temperature>19.60</temperature>
     <pressure>999.70</pressure>
   </BMP180>
   <WU>
     <temperature>6.10</temperature>
     <humidity>79.00</humidity>
     <pressure>1009.00</pressure>
   </WU>
 </ESP8266>

And here is my Terminal output too, I sending these exact values to both parsers: arduino_json_output

Why do you need this feature after all?

Duh, cuz I want correct values to be shown and sent too! :stuck_out_tongue_winking_eye:

Kind regards, Viktor

bblanchon commented 6 years ago

Hi Viktor,

Also I don't know from where your library pulling these values too 18.68202

I cannot reproduce this bug. See a demo here: https://wandbox.org/permlink/b0xMSVBYqgpzENyn

Can you please provide an MCVE?

Regards, Benoit

beicnet commented 6 years ago

Hello Benoit,

Here is what I'm using exactly:

//  NTC Sensor
float ntc_t = 00.0;

//  DHTxxx Sensor
float dht_t = 00.0;
float dht_h = 00.0;
float dht_f = 00.0;
float dht_hx = 00.0;
float dht_dw = 00.0;

//  BMP085/180 Sensor
float bmp_t = 00.0;
float bmp_p = 00.0;

//  SHT3x Sensor
float sht_t = 00.0;
float sht_h = 00.0;
float sht_f = 00.0;
float sht_hx = 00.0;
float sht_dw = 00.0;

//  Wunderground Sensor
float wu_t = 00.0;
float wu_h = 00.0;
float wu_p = 00.0;
void handleJsonOutput()
  {
  String wPage = "";

  DynamicJsonBuffer jsonBuffer;

  JsonObject& root = jsonBuffer.createObject();

  JsonObject& sensors = root.createNestedObject("ESP8266");

  JsonObject& sensors_ntc = sensors.createNestedObject("NTC");
  sensors_ntc["temperature"] = ntc_t;

  JsonObject& sensors_dht11 = sensors.createNestedObject("DHT11");
  sensors_dht11["temperature"] = dht_t;
  sensors_dht11["humidity"] = dht_h;

  JsonObject& sensors_sht30 = sensors.createNestedObject("SHT30");
  sensors_sht30["temperature"] = sht_t;
  sensors_sht30["humidity"] = sht_h;

  JsonObject& sensors_bmp180 = sensors.createNestedObject("BMP180");
  sensors_bmp180["temperature"] = bmp_t;
  sensors_bmp180["pressure"] = bmp_p;

  JsonObject& sensors_wu = sensors.createNestedObject("WU");
  sensors_wu["temperature"] = wu_t;
  sensors_wu["humidity"] = wu_h;
  sensors_wu["pressure"] = wu_p;

  root.prettyPrintTo(wPage);

  server.send(200, "text/txt", wPage);
  }

Kind regards, Viktor

bblanchon commented 6 years ago

Hi Viktor,

Please see a demo here: https://wandbox.org/permlink/vebUf9dITRpAKMnV I don't see anything wrong.

Are you sure the problem comes from ArduinoJson?

Regards, Benoit

beicnet commented 6 years ago

Hey @bblanchon,

I saw you demo, and the numbers are not show 1:1 how you/I'm pasting them.

And I think, I know what is the reason for it! :wink:

Just to quickly elaborate the first value in your demo:

The defined, input value: float ntc_t = 18.0;

and the output is: "temperature": 18

Do you see the difference? The input is 4 chars, but the output is only 2 chars.

And the winner is the "json serializer". :fireworks:

So, if I send any value as String I got all chars correct, but if I send float I got truncated values like mentioned above.

Kind regards, Viktor

bblanchon commented 6 years ago

Hi Viktor,

The float to string conversion implemented in Arduino (in String, Serial...) is inferior to the one in ArduinoJson because it only supports a fixed number of digits and doesn't support exponentiation.

ArduinoJson behaves like JavaScript engines. On your browser, if you execute:

JSON.stringify({"temperature":18.0})

you'll get the following JSON document:

{"temperature":18}

Viktor, I'm not sure I can do anything, can I?

Regards, Benoit

beicnet commented 6 years ago

Hi @bblanchon,

Nah, you can't do nothing, that is the downfall of the Json architecture/standard.

For example, some IoT devices expect 5 char as input and the Json will pass only 2 chars: 18.00 ==> 18

I know it's a same value, but the char count is not.

What I was trying to say is, if you send like this, you will get all 5 chars: sensors_dht11["temperature"] = (String)dht_t;

as is: 18.00 ==> 18.00

odd thing, but nevertheless...

Kind regards, Viktor

bblanchon commented 6 years ago

Hi Viktor,

sensors_dht11["temperature"] = (String)dht_t;

The line above produces "18.00", not 18.00; so, it's a string, not a number. Indeed, it calls the constructor of String and is equivalent to the following:

sensors_dht11["temperature"] = String(dht_t);

Can we close this issue?

Regards, Benoit

beicnet commented 6 years ago

Hi Benoit,

Yes, as I said, but String will be fine too, had a luck that I figured out that!

Kind regards, Viktor

bblanchon commented 6 years ago

OK, Viktor, I'm closing the issue them. I'm just mentioning #566, so we can find this conversation easily.

beicnet commented 6 years ago

Okay! :wink: