How to pass JsonObject between functions of 2 separate classes?
Created by: vyruz1986
Hi everyone! I've been using ArduinoJson for a couple of years now (Thanks @bblanchon & contributors!) but find myself stuck with something seemingly simple. I was struggling with how to pass a JsonObject between 2 functions of 2 separate classes, but after reading through the documentation, I think I should take a step back and think about what I'm doing is correct or not. So here goes:
I have a WebHandlerClass
and a SlaveHandlerClass
, the SlaveHandlerClass
sets up a websocket client connection which receives regular json messages from the remote host, depending on what the message is, the SlaveHandlerClass
should discard the message, or pass it on to the WebHandlerClass
. Since I need to check the type of message, I need/want to create a JsonObject
in the SlaveHandlerClass
in order to use ArduinoJson functionality to validate the json message format and content. So after validating a json message I have a JsonObject&
which contains the message I need to pass to WebHandlerClass
. What would be the appropriate way to pass this data to the other class?
- use
PrintTo()
to print it to aString
and send that string object toWebHandlerClass
? - Pass pointer/reference (these still confuse after years of C++/Arduino coding...) to
JsonObject*
toWebHandlerClass
? - Something else...?
I put this on gitter and @bblanchon mentioned to create this issue to further discuss, he already mentioned that passing the JsonObject
from one class to the other will likely be the best solution, but the challenge will be to keep the DynamicJsonBuffer
alive for this to work correctly.
I attempted to do this, but it's not working, the relevant code is below (just snippets of my bigger project, so likely won't compile. The full source code can found here), I'll try to briefly describe the sequence of relevant events:
-
SlaveHandlerClass::init()
initializes the__jsonRaceDataBuffer
with thebsRaceData
global variable as size which is big enough to hold a RaceData json object. (calculated with helper tool on ArduinoJson.org) -
SlaveHandlerClass
establishes websocket connection to remote host, via the callback functionSlaveHandlerClass::_wsEvent()
it's informed when there's new data.- In case of
WStype_TEXT
, the function will create a temporaryDynamicJsonBuffer
andJsonObject&
to validate json format, and check the type of message. If the message is a RaceData (request.containsKey("RaceData")
then I use the protected class member_jsonRaceDataBuffer
and_jsonRaceData
objects to parse the payload from the websocket again, but now it should be kept alive since these objects are protected members, global to the `SlaveHandlerClass
- In case of
-
WebHandlerClass::_SendRaceData()
function will perform the following tasks:- Create a
DynamicJsonBuffer
object with the size ofbsRaceDataArray
(which should be big enough to hold an array of 2 RaceData objects), and initialize aJsonObject
with a nestedJsonArray
- Create another
DynamicJsonBuffer
/JsonObject
combination to store its own RaceData (jsonMasterRaceData
) - If a slave is connected, create another
DynamicJsonBuffer
/JsonObject
combination to store the slave data (jsonSlaveRaceData
) - Fill the
jsonMasterRaceData
object with data, and add it to thejsonRaceData
array object - If a slave is present, query the
SlaveHandlerClass
for the latest slave RaceData, and add it to thejsonRaceData
object as well - Send the RaceData array (
jsonRaceData
) object (either with or without slave racedata) out to all connected websocket clients
- Create a
The problem is I can't figure out how to correctly pass the data to the WebHandlerClass function. The JsonObject
I get back from calling SlaveHandlerClass::getSlaveRaceData()
is either empty, or contains rubbish, or the system crashes alltogether.
SlaveHandler.h
class SlaveHandlerClass
{
protected:
DynamicJsonBuffer _jsonRaceDataBuffer(bsRaceData); //bsRaceData is a global variable that contains the size for a RaceData json object
JsonObject& _jsonRaceData;
WebSocketsClient _wsClient;
void _WsEvent(WStype_t type, uint8_t * payload, size_t length);
public:
void init();
void loop();
JsonObject* getSlaveRaceData();
}
extern SlaveHandlerClass SlaveHandler;
SlaveHandler.cpp
#include "SlaveHandler.h"
#include <WebSocketsClient.h>
#include <ArduinoJson.h>
void SlaveHandlerClass::init()
{
this->_wsClient.begin(this->_RemoteIP.toString(), 80, "/ws");
this->_wsClient.onEvent(std::bind(&SlaveHandlerClass::_WsEvent, this
, std::placeholders::_1
, std::placeholders::_2
, std::placeholders::_3));
DynamicJsonBuffer _jsonRaceDataBuffer(bsRaceData);
}
void SlaveHandlerClass::loop()
{
this->_wsClient.loop();
}
void SlaveHandlerClass::_WsEvent(WStype_t type, uint8_t * payload, size_t length)
{
switch (type) {
case WStype_DISCONNECTED:
this->_SetDisconnected();
break;
case WStype_CONNECTED:
this->_bConnected = true;
this->_bWSConnectionStarted = false;
this->_AnnounceSlaveIfApplicable();
Serial.printf("[WSc] Connected to url: %s\n", payload);
// send message to server when Connected
//this->_wsClient.sendTXT("Connected");
break;
case WStype_TEXT:
{
Serial.printf("[WSc] got text: %s\n", payload);
DynamicJsonBuffer jsonBufferRequest;
JsonObject& request = jsonBufferRequest.parseObject(payload);
if (!request.success()) {
syslog.logf_P(LOG_ERR, "Error parsing JSON!");
}
if (request.containsKey("RaceData")) {
JsonObject& _jsonRaceData = _jsonRaceDataBuffer.parseObject(payload);
}
else if (request.containsKey("SystemData")) {
}
break;
}
case WStype_BIN:
Serial.printf("[WSc] get binary length: %u\n", length);
// send data to server
// webSocket.sendBIN(payload, length);
break;
}
}
JsonObject* SlaveHandlerClass::getSlaveRaceData()
{
return _jsonRaceData;
}
WebHandler.cpp
void WebHandlerClass::_SendRaceData(uint iRaceId)
{
DynamicJsonBuffer JsonBuffer(bsRaceDataArray);
JsonObject& JsonRoot = JsonBuffer.createObject();
JsonArray& jsonRaceData = JsonRoot.createNestedArray("RaceData");
DynamicJsonBuffer jsonMasterRaceDataBuffer(bsRaceData);
JsonObject& jsonMasterRaceData = jsonMasterRaceDataBuffer.createObject();
DynamicJsonBuffer jsonSlaveRaceDataBuffer(bsRaceData);
JsonObject& jsonSlaveRaceData = jsonSlaveRaceDataBuffer.createObject();
/* fill jsonMasterRaceData object with valid data from various other functions */
jsonRaceData.add(jsonMasterRaceData);
if (_bSlavePresent) {
jsonRaceData.add(SlaveHandler.getSlaveRaceData());
}
size_t len = JsonRoot.measureLength();
AsyncWebSocketMessageBuffer * wsBuffer = _ws->makeBuffer(len);
if (wsBuffer)
{
JsonRoot.printTo((char *)wsBuffer->get(), len + 1);
_ws->textAll(wsBuffer);
}