Closed scottchiefbaker closed 6 months ago
Hi @scottchiefbaker,
JsonObject
is a reference to an object in a JsonDocument
.
In other words, JsonObject
doesn't hold any data but points to the data in the JsonDocument
.
To establish this link from the JsonObject
to the JsonDocument
, you must assign the reference to something that exists in the document; otherwise, the reference will be unbound.
In your case, last_obj
is unbound because it is never assigned.
Sure, the program calls JsonObject::set()
, but it's a no-op because the reference is unbound.
One solution could be to assign last_obj
, like so:
- last_obj.set(obj);
+ last_obj = obj;
But I suspect that caching the reference is not what you are after.
Instead, you probably expect to save the content of the object pointed by obj
.
In that case, the solution is to use a JsonDocument
instead:
- static JsonObject last_obj;
+ static JsonDocument last_obj;
Best regards, Benoit
You are correct, I want the content of the object. When I change my static variable to a Document like you mention I now get an error:
no matching function for call to 'ArduinoJson::V703L1::JsonObject::set(ArduinoJson::V703L1::JsonDocument&)'
I also tried using equals assignment and I get:
no match for 'operator=' (operand types are 'ArduinoJson::V703L1::JsonObject' and 'ArduinoJson::V703L1::JsonDocument')
I think we're on the right track, but I don't know how to get the data back into the original JsonObject
Indeed, JsonObject::set()
only accepts JsonObjectConst
, and there is no implicit conversion between JsonDocument
and JsonObjectConst
. I should probably improve that, but I never noticed it because very few people use JsonObject::set()
.
You can workaround this error by explicitly converting the JsonDocument
to a JsonObject
:
- obj.set(last_obj);
+ obj.set(last_obj.as<JsonObject>());
Alternatively, you could refactor your program so that foobar()
returns a JsonDocument
:
JsonDocument foobar() {
static JsonDocument doc;
static uint32_t last_hit = 0;
bool too_soon = (millis() - last_hit) < 5000;
if (!too_soon) {
doc["name"] = "Jason Doolis";
doc["color"] = "Red";
last_hit = millis();
}
return last_obj;
}
void loop() {
JsonDocument json;
json["test"] = foobar();
serializeJson(json, Serial);
Serial.println();
delay(2000);
}
Sure, it produces one or two additional copies, but it's a thousand times more readable.
Another alternative would be to return a String
from foobar
and then use serialized()
to insert it in the main document.
Aha! This is exactly what I needed. I didn't realize you could put a JsonDocument
into another JsonDocument
. That really simplifies things. With this method I was able to include "cached": true
as well.
There is a minor typo in your code above with last_obj
so here is my full working code for posterity in case someone else has a similar problem:
#include "ArduinoJson.h"
void setup() {
Serial.begin(115200);
}
JsonDocument foobar() {
static JsonDocument doc;
static uint32_t last_hit = 0;
int32_t diff = millis() - last_hit;
bool too_soon = abs(diff) < 5000;
if (last_hit && too_soon) {
doc["cached"] = true;
} else {
doc.clear();
doc["name"] = "Jason Doolis";
doc["time"] = millis();
last_hit = millis();
}
return doc;
}
void loop() {
JsonDocument json;
json["test"] = foobar();
serializeJson(json, Serial);
Serial.println();
delay(2000);
}
Thank you for your assistance on this. And thank you for an AMAZING library. ArduinoJson is a masterpiece.
You're welcome, @scottchiefbaker! Thank you for using ArduinoJson.
I have Googled, looked in closed issues, and I even hit up ChatGPT and I cannot find an answer to what I assume is a simple request.
Describe the issue
I need a way to cache a JsonObject between function calls to reuse if a request is made too quickly
Environment
Here is the environment that I'm using':
arduino-cli
v0.35.3Reproduction
Here is a small snippet that demonstrate the problem.
Expected output: The JSON uses the previous iteration as a cache
Actual output: When I call this function every two seconds I see this:
Clearly it's getting the correct data the first time, but when it comes back and triggers the
too_soon
it's not seeing the data from the previous iteration inlast_obj
. Bonus points if I could append"cached": true
to the object after realize we're in thetoo_soon
if statement.