bblanchon / ArduinoJson

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

Question - Access JSON data variables in nested arrays #2107

Closed justinpanta closed 10 hours ago

justinpanta commented 4 days ago

Firstly, I am a beginner not only to ArduinoJSON, but also to C++. ArduinoJSON is an amazing library, however, due to my lack of knowledge in this area, I have a question that I'm hoping will be easily answered.

I'm using ArduinoJSON on an ESP32 with Arduino IDE 1.8.19 to deserialize weather data from a JSON API. Using the ArduinoJSON assistant, it has generated the program code to use in my project, which works well. I can successfully access and use any deserialized data that is assigned to variables or pointers (int, float, const char*), however, as some of the JSON source data includes items that are in arrays, I am having trouble working out how to access this data. As shown below, the data in particular that I am having trouble with is the 'forecasts', as it has forecast data for multiple days. I need to know how to select a particular day (1-3) and access the associated data for that day as variables.

Here is a sample of the JSON data I receive from the weather source:

{ "location": { "id": 13973, "name": "Arthurs Creek", "region": "Yarra Valley and Dandenong Ranges", "state": "VIC", "postcode": "3099", "timeZone": "Australia/Melbourne", "lat": -37.579, "lng": 145.2014, "typeId": 21 }, "forecasts": { "weather": { "days": [ { "dateTime": "2024-06-30 00:00:00", "entries": [ { "dateTime": "2024-06-30 00:00:00", "precisCode": "chance-shower-cloud", "precis": "Shower or two", "precisOverlayCode": "", "night": false, "min": 5, "max": 10 } ] }, { "dateTime": "2024-07-01 00:00:00", "entries": [ { "dateTime": "2024-07-01 00:00:00", "precisCode": "partly-cloudy", "precis": "Partly cloudy", "precisOverlayCode": "", "night": false, "min": 3, "max": 11 } ] }, { "dateTime": "2024-07-02 00:00:00", "entries": [ { "dateTime": "2024-07-02 00:00:00", "precisCode": "mostly-fine", "precis": "Morning frost. Mostly sunny", "precisOverlayCode": "frost", "night": false, "min": 1, "max": 11 } ] } ], "units": { "temperature": "c" }, "issueDateTime": "2024-06-30 18:09:38" } }, "observational": { "observations": { "temperature": { "temperature": 8.3, "apparentTemperature": 6.7, "trend": -1 }, "delta-t": { "temperature": 0, "trend": 0 }, "cloud": { "oktas": 1, "trend": 0 }, "humidity": { "percentage": 99, "trend": 0 }, "dewPoint": { "temperature": 8.2, "trend": -1 }, "pressure": { "pressure": 1023.6, "trend": 0 }, "wind": { "speed": 5.5, "gustSpeed": 7.4, "trend": 0, "direction": 238, "directionText": "WSW" }, "rainfall": { "lastHourAmount": 0, "todayAmount": 2.4, "since9AMAmount": 1.6 } }, "stations": { "temperature": { "id": 438, "name": "Viewbank", "lat": -37.741, "lng": 145.097, "distance": 20.2 }, "delta-t": { "id": 438, "name": "Viewbank", "lat": -37.741, "lng": 145.097, "distance": 20.2 }, "cloud": { "id": 437, "name": "Essendon Airport", "lat": -37.728, "lng": 144.907, "distance": 30.8 }, "humidity": { "id": 438, "name": "Viewbank", "lat": -37.741, "lng": 145.097, "distance": 20.2 }, "dewPoint": { "id": 438, "name": "Viewbank", "lat": -37.741, "lng": 145.097, "distance": 20.2 }, "pressure": { "id": 438, "name": "Viewbank", "lat": -37.741, "lng": 145.097, "distance": 20.2 }, "wind": { "id": 438, "name": "Viewbank", "lat": -37.741, "lng": 145.097, "distance": 20.2 }, "rainfall": { "id": 438, "name": "Viewbank", "lat": -37.741, "lng": 145.097, "distance": 20.2 } }, "issueDateTime": "2024-06-30 19:00:00", "units": { "temperature": "c", "amount": "mm", "speed": "km/h", "distance": "km", "pressure": "hPa" } } }

Here is the program code generated by the assistant, which I am currently using:

// Stream& input;

JsonDocument doc;

DeserializationError error = deserializeJson(doc, input);

if (error) { Serial.print("deserializeJson() failed: "); Serial.println(error.c_str()); return; }

JsonObject location = doc["location"]; int location_id = location["id"]; // 13973 const char location_name = location["name"]; // "Arthurs Creek" const char location_region = location["region"]; // "Yarra Valley and Dandenong Ranges" const char location_state = location["state"]; // "VIC" const char location_postcode = location["postcode"]; // "3099" const char* location_timeZone = location["timeZone"]; // "Australia/Melbourne" float location_lat = location["lat"]; // -37.579 float location_lng = location["lng"]; // 145.2014 int location_typeId = location["typeId"]; // 21

JsonObject forecasts_weather = doc["forecasts"]["weather"];

for (JsonObject forecasts_weather_day : forecasts_weather["days"].as()) {

const char* forecasts_weather_day_dateTime = forecasts_weather_day["dateTime"]; // "2024-06-30 ...

JsonObject forecasts_weather_day_entries_0 = forecasts_weather_day["entries"][0]; const char forecasts_weather_day_entries_0_dateTime = forecasts_weather_day_entries_0["dateTime"]; const char forecasts_weather_day_entries_0_precisCode = forecasts_weather_day_entries_0["precisCode"]; const char forecasts_weather_day_entries_0_precis = forecasts_weather_day_entries_0["precis"]; const char forecasts_weather_day_entries_0_precisOverlayCode = forecasts_weather_day_entries_0["precisOverlayCode"]; bool forecasts_weather_day_entries_0_night = forecasts_weather_day_entries_0["night"]; // false, false, ... int forecasts_weather_day_entries_0_min = forecasts_weather_day_entries_0["min"]; // 5, 3, 1 int forecasts_weather_day_entries_0_max = forecasts_weather_day_entries_0["max"]; // 10, 11, 11

}

const char* forecasts_weather_units_temperature = forecasts_weather["units"]["temperature"]; // "c"

const char* forecasts_weather_issueDateTime = forecasts_weather["issueDateTime"]; // "2024-06-30 ...

JsonObject observational = doc["observational"];

JsonObject observational_observations = observational["observations"];

JsonObject observational_observations_temperature = observational_observations["temperature"]; float observational_observations_temperature_temperature = observational_observations_temperature["temperature"]; float observational_observations_temperature_apparentTemperature = observational_observations_temperature["apparentTemperature"]; int observational_observations_temperature_trend = observational_observations_temperature["trend"];

int observational_observations_delta_t_temperature = observational_observations["delta-t"]["temperature"]; int observational_observations_delta_t_trend = observational_observations["delta-t"]["trend"]; // 0

int observational_observations_cloud_oktas = observational_observations["cloud"]["oktas"]; // 1 int observational_observations_cloud_trend = observational_observations["cloud"]["trend"]; // 0

int observational_observations_humidity_percentage = observational_observations["humidity"]["percentage"]; int observational_observations_humidity_trend = observational_observations["humidity"]["trend"]; // 0

float observational_observations_dewPoint_temperature = observational_observations["dewPoint"]["temperature"]; int observational_observations_dewPoint_trend = observational_observations["dewPoint"]["trend"]; // -1

float observational_observations_pressure_pressure = observational_observations["pressure"]["pressure"]; int observational_observations_pressure_trend = observational_observations["pressure"]["trend"]; // 0

JsonObject observational_observations_wind = observational_observations["wind"]; float observational_observations_wind_speed = observational_observations_wind["speed"]; // 5.5 float observational_observations_wind_gustSpeed = observational_observations_wind["gustSpeed"]; // 7.4 int observational_observations_wind_trend = observational_observations_wind["trend"]; // 0 int observational_observations_wind_direction = observational_observations_wind["direction"]; // 238 const char* observational_observations_wind_directionText = observational_observations_wind["directionText"];

JsonObject observational_observations_rainfall = observational_observations["rainfall"]; int observational_observations_rainfall_lastHourAmount = observational_observations_rainfall["lastHourAmount"]; float observational_observations_rainfall_todayAmount = observational_observations_rainfall["todayAmount"]; float observational_observations_rainfall_since9AMAmount = observational_observations_rainfall["since9AMAmount"];

for (JsonPair observational_station : observational["stations"].as()) { const char* observational_station_key = observational_station.key().c_str(); // "temperature", ...

int observational_station_value_id = observational_station.value()["id"]; // 438, 438, 437, 438, 438, ... const char* observational_station_value_name = observational_station.value()["name"]; // "Viewbank", ... float observational_station_value_lat = observational_station.value()["lat"]; // -37.741, -37.741, ... float observational_station_value_lng = observational_station.value()["lng"]; // 145.097, 145.097, ... float observational_station_value_distance = observational_station.value()["distance"]; // 20.2, 20.2, ...

}

const char* observational_issueDateTime = observational["issueDateTime"]; // "2024-06-30 19:00:00"

JsonObject observational_units = observational["units"]; const char observational_units_temperature = observational_units["temperature"]; // "c" const char observational_units_amount = observational_units["amount"]; // "mm" const char observational_units_speed = observational_units["speed"]; // "km/h" const char observational_units_distance = observational_units["distance"]; // "km" const char* observational_units_pressure = observational_units["pressure"]; // "hPa"

If anyone can assist with my question, it would be greatly appreciated.

Thanks.

bblanchon commented 3 days ago

Hi @justinpanta,

Here is how to get the weather forecast data for the first day:

JsonObject forecasts_weather_day_1 = doc["forecasts"]["weather"]["days"][0];

Best regards, Benoit

justinpanta commented 2 days ago

Thanks @bblanchon.

I can confirm that I can access the forecast data with the info you provided, however only within the for loop. Is there a way I can access these variables outside of the for loop?

bblanchon commented 15 hours ago

doc["forecasts"]["weather"]["days"][0] is independent of the loop and can be used outside of it.

justinpanta commented 10 hours ago

Yes, confirming I made an error in the code.

Thanks so much!