[SOLVED] Check if JSON key exists in rule

I have a rule where I read items from a JSON string into several values.

This JSON string has a state ON/OFF and brightness 0-255.

This is all working as I want but sometimes the JSON message only contains the state and not the brightness.

This causes my rule to throw an error because it cant find the JSON key it is looking for,

Is there a way I can check to see if the brightness key exists before I try to parse it to a value?

Thanks.

What binding are you using to get these values?

Please post your Rule (use code fences).

I’m using the JSON Transformation Binding.

rule "Incoming Transformation"
when
    Member of gZigbeeLightString received update
then
    val trigIn = triggeringItem
    val String zigbeestate = transform("JSONPATH", "$.state", trigIn.state.toString)
    val Number zigbeebright = Float::parseFloat(transform("JSONPATH", "$.brightness", trigIn.state.toString))
    val dimcontrol= gZigbeeLightControl.members.findFirst[ t | t.name == trigIn.name.toString.split('_').get(0) ] as DimmerItem
    logInfo("User.Testing","Incoming transformation. State =  " + zigbeestate + " Brightness = " + zigbeebright + "Dimmer control = " + dimcontrol.name)
    
     if (zigbeestate == "OFF") {
        dimcontrol.postUpdate(0)
    } else {
        var Number brightIn = Math::round(zigbeebright.floatValue() / 255 * 100 )
        dimcontrol.postUpdate(brightIn)
        logInfo("User.Testing","Incoming brightness = " + brightIn)
    } 
end

I know i can do the following in Javascript but I don’t know how to do it in a rule.

if(json.hasOwnProperty('click')){
    result = json.click;
} else {
    result = "none";
}

Thanks.

So am I to guess you are using the MQTT binding to receive these JSON strings from zibgee2mqtt?

I ask because the MQTT 2 binding supports chaining transformations so you can put a REGEX transformation to look for the ‘click’ property and it will only get passed to the JSONPATH transform if it’s there.

It is also useful to avoid the XY Problem.

You can’t do what you are after in the call to the transform. It either needs to be there or it will generate an error.

You need to check if it’s there first. But that can be relatively easily be done using a simple

if(triggeringItem.state.toString.contains("click"))
2 Likes

If the key doesn’t exist in the JSON string, transform returns the original string that was passed to it. It’s counter-intuitive, but that’s the way it works. :confused: So…

val String s = transform("JSONPATH", "$.brightness", trigIn.state.toString)
if (s.equals(trigIn.state.toString)) {
    // JSON string doesn't contain brightness key
} else {
    // JSON string contains brightness key
}
1 Like

But doesn’t it also generate an error in the logs?

Also, OP indicated that there is an error in the Rule. Maybe it works slightly differently in rules?

I don’t have a lot of experience with JSONPATH called from rules.

I didn’t think so, but I honestly don’t remember. I’ll check.

Float::parseFloat will throw an exception (NumberFormatException, I think) if the argument is non-numeric. So, when transform returns the full JSON string (because $.brightness doesn’t exist), it will throw the exception.

@rlkoshak With this rule.

    logInfo("test", "TEST: Test rule is executing")
    val String sJson = '{"state":"ON"}'
    try {
        val Number nBright = Float.parseFloat(transform("JSONPATH","$.brightness",sJson))
        val Number converted = (nBright * 100)
        logInfo("test","Converted = " + converted)
    } catch (NumberFormatException e) {
        logInfo("test","Caught NumberFormatException: {}", e.getMessage)
    }

You get this in the log.

2019-03-20 07:01:25.560 [INFO ] [.eclipse.smarthome.model.script.test] - TEST: Test rule is executing
2019-03-20 07:01:25.560 [INFO ] [.eclipse.smarthome.model.script.test] - Caught NumberFormatException: For input string: "{"state":"ON"}"
2 Likes