Closed effelle closed 4 years ago
Hi @effelle,
If you want to know the type of a value, use JsonVariant::is
JsonVariant power = root["Power"];
if (power.is<double>()) {
// just one value
}
if (power.is<JsonArray>()) {
// several values
for (JsonVariant v : power.as<JsonArray>()) {
// ...
}
}
Best Regards, Benoit
Benoît,
thanks for your reply.
I've added the JsonVariant
and I think I got it.
The only issue I have is when a value is null
for some reasons (happens from time to time with DHT11). In that specific case the bool dpower
will be set as True
. Is a rare case, but could happens.
Anyway, for the sake of knowledge here the complete void:
void HAssAnnounceSensors(void)
{
uint8_t hass_xsns_index = 0;
do {
mqtt_data[0] = '\0';
int tele_period_save = tele_period;
tele_period = 2;
XsnsNextCall(FUNC_JSON_APPEND, hass_xsns_index);
tele_period = tele_period_save;
char sensordata[512];
strlcpy(sensordata, mqtt_data, sizeof(sensordata));
if (strlen(sensordata)) {
sensordata[0] = '{';
snprintf_P(sensordata, sizeof(sensordata), PSTR("%s}"), sensordata);
AddLog_P2(LOG_LEVEL_INFO, PSTR("JSON: Input list '%s'"), sensordata);
StaticJsonBuffer<500> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(sensordata);
if (!root.success()) {
AddLog_P2(LOG_LEVEL_ERROR, PSTR("HASS: jsonBuffer failed to parse '%s'"), sensordata);
continue;
}
for (auto sensor : root) {
const char* sensorname = sensor.key;
JsonObject& sensors = sensor.value.as<JsonObject>();
if (!sensors.success()) {
AddLog_P2(LOG_LEVEL_ERROR, PSTR("HASS: JsonObject failed to parse '%s'"), sensordata);
continue;
}
for (auto subsensor : sensors) {
bool dpower= false;
const char* subsensorname = subsensor.key;
AddLog_P2(LOG_LEVEL_INFO, PSTR("NAME: sensorname '%s'"), subsensorname);
JsonVariant multival = sensors[subsensorname];
if (!multival.is<double>()) {
dpower = true;
}
AddLog_P2(LOG_LEVEL_INFO, PSTR("CHKP: dpower value %d"), dpower);
HAssAnnounceSensor(sensorname, subsensor.key);
}
}
}
yield();
} while (hass_xsns_index != 0);
}
I tested it with some json and I got fairly good results:
19:09:27 JSON: Input list '{"ANALOG":{"A0":609}}'
19:09:27 NAME: sensorname 'A0'
19:09:27 CHKP: dpower value 0
19:09:27 JSON: Input list '{"BME280":{"Temperature":28.1,"Humidity":40.5,
"Pressure":1003.4}}'19:09:27
19:09:27 NAME: sensorname 'Temperature'
19:09:27 CHKP: dpower value 0
19:09:28 NAME: sensorname 'Humidity'
19:09:28 CHKP: dpower value 0
19:09:28 NAME: sensorname 'Pressure'
19:09:28 CHKP: dpower value 0
20:32:34 JSON: Input list '{"ENERGY":{"Total":2.684,"Power":[23.63,67.17],
"ApparentPower":[23.63,67.17],"Voltage":229.3,"Current":[0.103,0.293]}}'
20:32:34 NAME: sensorname 'Total'
20:32:34 CHKP: dpower value 0
20:32:35 NAME: sensorname 'Power'
20:32:35 CHKP: dpower value 1
20:32:35 NAME: sensorname 'ApparentPower'
20:32:35 CHKP: dpower value 1
20:32:35 NAME: sensorname 'Voltage'
20:32:35 CHKP: dpower value 0
20:32:35 NAME: sensorname 'Current'
20:32:35 CHKP: dpower value 1
Thanks for your time!
Federico
You're welcome Federico. Thank you for using ArduinoJson.
Sorry to bother you again but do I have a way to count the number of values in the array? Seems I need to manage also values like
{"ENERGY":{"Total":2.684,"Power":[23.63,67.17,44.18]}}
Should return Total =1 Power = 3
Seems I need to use JsonArray::size()
or better JsonObject::size()
.
JsonArray::size() is the right answer: it returns the number of elements in the array.
HI Benoît,
I've used JsonArray::size()
to count the number of items:
if (subsensor.value.is<JsonArray&>()) {
JsonArray& subsensors = subsensor.value.as<JsonArray&>();
subqty = subsensors.size();
But I realized it takes almost 90 bytes. Is there a way to archive the same result using less flash space? Thanks,
Federico
Hi @effelle,
JsonArray::size()
does a linear scan to count the elements.
In most cases, you can avoid this function by calling begin()/end()
.
Best regards, Benoit
I think I'm misunderstanding the use of begin()/end()
because that function use the same space of size()
in flash.
Just to be sure we are on the same page, let's say subsensor.value
is "[22,34,1023.4]".
My new code should be:
if (subsensor.value.is<JsonArray&>()) {
JsonArray& subsensors = subsensor.value.as<JsonArray&>();
for (auto value : subsensors) {
subqty++;
}
Am I right to say is virtually the same but with more lines of code?
Edit: I think my problem is more about the jsonbuffer
I have on the beginning of the void:
StaticJsonBuffer<500> jsonBuffer;
I'm starting to think subsensor is crating a second 500 buffer because if I remove the second jsonarray I'm trying to fix it takes 0.2k less on flash space.
@bblanchon thank you so much for your library! I'm trying to update part of the code to support nested values on a firmware for ESP8266. Normally I need to decode normal JSON pairs, like
The problem begin with two values per key:
I use the json to create single entities for Home Assistant, and is giving issue because the firmware doesn't create entities listening to
[0]
and[1]
. What I didn't understand is how to check if there are two values (I don't need to parse the result, just look at it) and consequently pass to another void the correct flag to generate the entities where just sensor (example: ENERGY) and subsensor (example: Power) are needed. Here's the relevant part of my code:I think I need add some sort of "checkpoint" before
for (auto sensor : root)
. What approach would you suggest to solve my issue? Thanks, Federico