JsonParserGeneratorRK - parsing a Child Key from a Firebase GET webhook

I have a JSON object from Firebase that I need to parse the Firebase Key. I’ve read through the JsonParserGeneratorRK library information but can’t seem to find which function or an example to use to parse my Key value “-M5sN1MfCHcXHkLBlwWW”

my GET webhook is working, here’s an abbreviated hook-response:

{"-M5sN1MfCHcXHkLBlwWW":{"aug":false,"fan":true,"ign":true}}

and here’s my parser1 code

void getDataHandler(const char *event, const char *data) {
    JsonParserStatic<768, 60> parser1;
    parser1.clear();
    parser1.addString(data);
    if (!parser1.parse()) {Log.warn("parsing failed to parse params\r\n"); return;}
    **// help here... how would I parse the key value into my variable? - char _Key[20]**
    if (!parser1.getOuterValueByKey("aug", newaug)) {Log.warn("failed to get newfan\r\n"); return;}
    if (!parser1.getOuterValueByKey("fan", newfan)) {Log.warn("failed to get newfan\r\n"); return;}
    if (!parser1.getOuterValueByKey("ign", newign)) {Log.warn("failed to get newign\r\n"); return; }

@rickkas7, could you help me here? thank you, Brian

Have you had a look at the README.md

Particularly the section about the fluent-style example

String s = parser.getReference().key("response").key("version").valueString();
1 Like

yes, thanks. i am sorry I realize I was not clear in my issue description. I did read through that @ScruffR, and I played with the cool parser tool to get the fluent-style command to use, but for my use, i will not know the Key value to insert into the .key("…") function, since it is assigned programatically by Firebase, I need to parse the object (-M5sN1MfCHcXHkLBlwWW) “blindly”, assign it to a string variable so I can use it in my program. Is there a way to grab this? I tried variations of getOuterObject() thinking that might be the right function, but I’m unable to get it to work. Thank you very much for your help.

Then you may want to look at getKeyValueByIndex() or getOuterKeyValueByIndex()

Hi @ScruffR, thank you for your help. I am working with getOuterKeyValueByIndex() and I have confirmed my library version is 0.1.1. I have a question on the passed variables.

the function calls for: bool getOuterKeyValueByIndex(size_t index, String &key, T &result)
for my example:
index = 0
&key = “” not sure what to use here with no key “name”…just the value -M5sN1MfCHcXHkLBlwWW
T &result = strVal

here’s my current code:

void handler(const char *topic, const char *data) {
    deviceName = String(data);
}
void getDataHandler(const char *event, const char *data) {
    JsonParserStatic<768, 60> parser1;
    parser1.clear();
    parser1.addString(data);

    if (!parser1.parse()) {Log.warn("parsing failed to parse params\r\n"); return;}
 
    String strVal;
    if (!parser1.getOuterKeyValueByIndex(0, "", strVal)) {Log.warn("failed to get Key from json params\r\n"); return;}
    strcpy(Key, strVal); // I strcpy the String into my char variable for my program to use.

I get this error**

no matching function for call to ‘JsonParserStatic<768u, 60u>::getOuterKeyValueByIndex(int, const char [1], String&)’

Can you help me with my sample code? I can’t figure out the syntax since my data (this value I’m trying to grab) is not in a typical Key:Value structure. thanks, Brian

The key is what you will get back from the function, so you need to provide a variable to put the key into. You cannot use a constant or string literal like "".

The function signature states that you need to provide a String& (a reference to a String variable) - even when you are not interested in the actualy key name, you need to provide a String to place the name into.

BTW, I don’t know whether this is supposed to work, but have you tried fluen style?
e.g.

  String s = parser.getReference().index(0).key("aug").valueBool();

I use this library with a firebase get: https://github.com/bblanchon/ArduinoJson

const size_t bufferSize = 3*JSON_ARRAY_SIZE(3) + JSON_OBJECT_SIZE(15) + 150;
    //DynamicJsonBuffer<bufferSize> jsonBuffer;
    StaticJsonBuffer<bufferSize> jsonBuffer;

    // Create a buffer for the json functions, it'll be cleared at function end
    //StaticJsonBuffer<1024> jsonBuffer;

    // Create a char to hold the argument, it'll be cleared at function end
    char charJSON[250];

    // Need to assign across the string
    strArg.toCharArray(charJSON, 250);

    JsonObject& root = jsonBuffer.parseObject(charJSON);

    // Lets make sure to clear this
    //free(charJSON);

    if (!root.success()) {
      Serial.println("parseObject() failed");
      Particle.publish("debug", "ERROR in setPit, parseObject() failed", 60, PRIVATE);


      //delete charJSON;
      // Return error
      return 0;
    } else {
        // do your assignments here. I use a struct for usersettings, so it's like this:
        strcpy(userSettings.fan, root["f"]);
       strcpy(userSettings.pWord, root["alg"][0]);
}

If:

  • The outer object contains a single key/value pair and you don’t know the key name in advance
  • You only want the first value

You can use getValueTokenByIndex with a parameter of 1, which is the value associated with the first key/value pair. Here’s the test code I used to verify:

	{
		// {"-M5sN1MfCHcXHkLBlwWW":{"aug":false,"fan":true,"ign":true}}
		JsonParserStatic<256, 14> jp;
		String s;

		char *data = readTestData("test2h.json");

		jp.addString(data);
		free(data);

		bool bResult = jp.parse();
		assert(bResult);

		const JsonParserGeneratorRK::jsmntok_t *firstObject;

		bResult = jp.getValueTokenByIndex(jp.getOuterObject(), 1, firstObject);
		assert(bResult);
		assert(firstObject != 0);

		bool bValue;

		bResult = jp.getValueByKey(firstObject, "aug", bValue);
		assert(bResult);
		assert(bValue == false);

		bResult = jp.getValueByKey(firstObject, "fan", bValue);
		assert(bResult);
		assert(bValue == true);

		bResult = jp.getValueByKey(firstObject, "ign", bValue);
		assert(bResult);
		assert(bValue == true);

	}
1 Like

First of all, without you guys @ScruffR @rickkas7 I would not be much of anywhere with my pellet grill smoker control program! Thank you for your help!

Here’s my solution based on your help!

in variables I declare:

const char *PUBLISH_PARAMETERS = "ParametersWrite";
const char *INITIAL_PARAMS_WRITE = "InitialParamsWrite";
const char *READ_PARAMETERS = "KEYParametersRead";

In Setup I declare subscribe and publish…

    Particle.subscribe("hook-response/InitialParamsWrite", getKeyHandler, MY_DEVICES);
    Particle.publish("spark/device/name", NULL, 60, PRIVATE);
    Particle.subscribe("hook-response/KEYParametersRead", getDataHandler, MY_DEVICES);

Since there is no web request: PATCH, I had to first do an IntialParamsWrite to firebase with POST and I grab the firebase key in a webhook response:

{"name":"-M99sRhDVc6yyjc0eNAf"}

then I parse the response in my getkeyHandler to populate my key and postKey variables:

void getKeyHandler(const char *event, const char *data) {
    JsonParserStatic<32, 60> keyParser;
    keyParser.clear();
    keyParser.addString(data);
    
    if (!keyParser.parse()) {Log.warn("parsing of the Key web-hook response failed - failed to parse the params key\r\n"); return;}
    String newKey;
    if (!keyParser.getOuterValueByKey("name", newKey)) {Log.warn("failed to get the key from the webhook params \r\n"); return;}
    strcpy(key, newKey);
}

Then when I WriteParameters, I use PUT and inject the controller{{n}} name and key{{k}} in the url string to basically overlay with my body parameters when they change so this single control record is updated from the photon and from my client Xamarin iOS/Android app.

{
"event": "ParametersWrite",
    "url": "https://someappname.firebaseio.com/ControllerData/{{n}}/Parameters/{{k}}.json",
    "requestType": "PUT",
    "noDefaults": true,
    "rejectUnauthorized": false,
    "query": {
        "auth": "someauthkeyblahblahblahWUbt3oVnfbB"
    },
    "body": "{\"ndex\":{{ndex}},\"Cyc\":{{Cyc}},\"PB\":{{PB}},\"PMode\":{{PMode}},\"PTog\":{{PTog}},\"Td\":{{Td}},\"Ti\":{{Ti}},\"fan\":{{fan}},\"ign\":{{ign}},\"aug\":{{aug}},\"pgm\":{{pgm}},\"mode\":\"{{mode}}\",\"target\":{{target}},\"u\":{{u}} }"
}

then when my ReadParameters web-hook fires I get the response with the nameless key.

{"-M99sRhDVc6yyjc0eNAf": "Cyc":60,"PB":60,"PMode":2,"PTog":0,"Td":45,"Ti":180,"aug":false,"fan":true,"ign":true,"key":"Pellet_Pirate_1","mode":"Start","ndex":1,"pgm":false,"target":200,"u":0.25}}

and I parse this with getDataHandler, using the key I got from my initial write:

void getDataHandler(const char *event, const char *data) {
    JsonParserStatic<768, 60> parser1;
    parser1.clear();
    parser1.addString(data);
 
    if (!parser1.parse()) {Log.warn("%s %.3f getDataHandler: Parameters read failed to parse\r\n", Time.timeStr().c_str(), getTimeWithMillis()); return;}
    newCycle = parser1.getReference().key(key).key("Cyc").valueInt();
    newPB = parser1.getReference().key(key).key("PB").valueInt();
    newPMode = parser1.getReference().key(key).key("PMode").valueInt();
    newPToggle = parser1.getReference().key(key).key("PTog").valueDouble();
    newTd = parser1.getReference().key(key).key("Td").valueInt();
    newTi = parser1.getReference().key(key).key("Ti").valueInt();
    newaug = parser1.getReference().key(key).key("aug").valueBool();
    newfan = parser1.getReference().key(key).key("fan").valueBool();
    newign = parser1.getReference().key(key).key("ign").valueBool();
    String strValue;
	strValue = parser1.getReference().key(key).key("mode").valueString();
	strcpy(newmode, strValue);
	newpgm = parser1.getReference().key(key).key("pgm").valueBool();
	newtarget = parser1.getReference().key(key).key("target").valueInt();
	newu = parser1.getReference().key(key).key("u").valueInt();
}

now just fine tuning the code… thanks again for the help! i hope this helps someone else with their integrations! Carpe Diem!

1 Like

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.