Does this make sense? Uber Function to simply interaction with devices

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”

The JSON structure I was thinking about would be:

{
    "cmd":[
         {
             "node":1,
             "var":"hourly",
             "fn":"reset"
         },
         {
             "node":0,
             "var":1,
             "fn":"lowPowerMode"
         },
         {
            "node":2,
            "var":"daily",
            "fn":"report"
    ] 
  }

In this example, I would have reset node 1’s hourly count, put node 0 into low power mode and received the value of the daily count.

If this works there could be a few advantages:

  1. It would reduce the clutter in setup() and in the console as there would only be one function.
  2. I could build a configuration string that could have multiple commands to automate the configuration of my gateways and nodes.
  3. The JSON string could be a single command or it could do many things at one go.

Just not sure how gnarly the code will get to parse these JSON payloads.

I am not sure of the following so I thought I would post here first before spending too many cycles on this:

  • Has this already been done?
  • Does this make sense?
  • Any ideas suggestions?

Thanks,

Chip

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.

4 Likes

@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");
	}
}

Thanks,

Chip

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?

Cheers,
Gustavo.

@gusgonnet ,

Yes! I figured I had seen this somewhere before. It was too good an idea for me to have come up with it. :wink:

I will take a look, thank you for the reminder.

Chip

2 Likes

I disagree.
You had a great idea, and then someone had it first :muscle:

3 Likes