Over time, my devices end up having a number of Particle.functions() and Particle.variables(). This is especially true as I am working on the LoRA Gateway which not only has to service variable and function requests for itself but would need to do so for its nodes as well. I was thinking that perhaps I could use the JSONParserGeneratorRK library to create a single uber function that would accept JSON which it would parse to take appropriate action. It would accept a JSON payload and as a start would have this structure:
functions - things I want my device to do such as “reset counts”
variable request - would ask for the values of various variables such as “current hourly count”
Yes, aggregating multiple operations in a single Particle function makes sense. Using JSON also makes sense. And it also reduces data operations. There is some effort to parse it, but it’s not that much more complicated than multiple functions and worth the effort.
@rickkas7 thank you for the encouragement. This code works though it is not very elegant. I will keep refining (perhaps use enum /switch case for the functions) and work this into a Particle.function.
#include "Particle.h"
#include "JsonParserGeneratorRK.h"
SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED); // Means my code will not be held up by Particle processes.
SerialLogHandler logHandler(LOG_LEVEL_INFO); // Easier to see the program flow
void jsonFunctionParser();
const char * const commandString = "{\"cmd\":[{\"node\":1,\"var\":\"hourly\",\"fn\":\"reset\"},{\"node\":0,\"var\":1,\"fn\":\"lowpowermode\"},{\"node\":2,\"var\":\"daily\",\"fn\":\"report\"}]}";
JsonParserStatic<1024, 80> jp; // Global parser that supports up to 256 bytes of data and 20 tokens
void setup() {
delay(2000);
jp.clear();
jp.addString(commandString);
if (!jp.parse()) {
Log.info("parsing failed");
}
jsonFunctionParser();
}
void loop() {
}
void jsonFunctionParser() {
int nodeNumber;
String variable;
String function;
const JsonParserGeneratorRK::jsmntok_t *cmdArrayContainer; // Token for the outer array
jp.getValueTokenByKey(jp.getOuterObject(), "cmd", cmdArrayContainer);
const JsonParserGeneratorRK::jsmntok_t *cmdObjectContainer; // Token for the objects in the array (I beleive)
for (int i=0; i<10; i++) { // Iterate through the array looking for a match
cmdObjectContainer = jp.getTokenByIndex(cmdArrayContainer, i);
if(cmdObjectContainer == NULL) {
break; // Ran out of entries
}
jp.getValueByKey(cmdObjectContainer, "node", nodeNumber);
jp.getValueByKey(cmdObjectContainer, "var", variable);
jp.getValueByKey(cmdObjectContainer, "fn", function);
if (function == "reset") Log.info("Reset variable %s on node %d", variable.c_str(),nodeNumber);
else if (function == "lowpowermode") Log.info("Set low power mode to %s on node %d", (variable =="1") ? "true":"false",nodeNumber);
else if (function == "report") Log.info("report value of %s on node %d", variable.c_str(),nodeNumber);
else Log.info("Not a valid command");
}
}
Hey Chip, yes, I think this has been done in the Tracker One, its cmd function receives different JSON commands.
Maybe you can look in the code to get inspiration?