Function Node with RBE functionality, issue with JSON Objects

Hey, I know I could do this with the RBE/filter node, but it's in some code, and I'd like to keep it in the function node.

Is there a way for this code to check for JSON objects. It does check for numbers/strings etc. But JSON objects seems to get through the code even if it's identical.
This is the code in the function node.

// block unless value changes

var new_input = msg.payload;
var last_output = context.get("last_output");
var master = global.get("master_office_lights");

if (master == "off"){
    if (typeof last_output == 'undefined') {
        context.set("last_output", new_input);
        return msg; // forward initial value
        // * return null to ignore the initial value * //
    }
    
    // otherwise last_output is defined, so did it change?
    if (new_input == last_output) {
        return null;
    }
    else {
        context.set("last_output", new_input);
        return msg;
    }
}

if (master =="on"){
    context.set("last_output", 'cleared')
    }

Here is a flow that shows an object it gets through the function node, but is stopped by the RBE node.

[{"id":"e221f25fc838887b","type":"function","z":"8c249630.076968","name":"RBE & Gate","func":"// block unless value changes\n\nvar new_input = msg.payload;\nvar last_output = context.get(\"last_output\");\nvar master = global.get(\"master_office_lights\");\n\nif (master == \"off\"){\n    if (typeof last_output == 'undefined') {\n        context.set(\"last_output\", new_input);\n        return msg; // forward initial value\n        // * return null to ignore the initial value * //\n    }\n    \n    // otherwise last_output is defined, so did it change?\n    if (new_input == last_output) {\n        return null;\n    }\n    else {\n        context.set(\"last_output\", new_input);\n        return msg;\n    }\n}\n\nif (master ==\"on\"){\n    context.set(\"last_output\", 'cleared')\n    }","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":670,"y":1600,"wires":[["6c25fc06b3647bd6"]]},{"id":"6c25fc06b3647bd6","type":"debug","z":"8c249630.076968","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":850,"y":1600,"wires":[]},{"id":"cf463ab38a1e0c24","type":"inject","z":"8c249630.076968","name":"","props":[{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":310,"y":1560,"wires":[["1f77d8bf169d02dd"]]},{"id":"538f59be7e060990","type":"inject","z":"8c249630.076968","name":"","props":[{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":310,"y":1600,"wires":[["e25aa489742d569d"]]},{"id":"91e9fdaa2d1b1d30","type":"inject","z":"8c249630.076968","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"-13","payloadType":"num","x":310,"y":1660,"wires":[["e221f25fc838887b","b67a2e571f2eff2c"]]},{"id":"1f77d8bf169d02dd","type":"function","z":"8c249630.076968","name":"","func":"return {payload:{data:{'brightness_pct':60,'color_temp':275}}}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":1560,"wires":[["e221f25fc838887b","b67a2e571f2eff2c"]]},{"id":"e25aa489742d569d","type":"function","z":"8c249630.076968","name":"","func":"return {payload:{\"service\": \"turn_off\" }}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":1600,"wires":[["e221f25fc838887b","b67a2e571f2eff2c"]]},{"id":"b67a2e571f2eff2c","type":"rbe","z":"8c249630.076968","name":"","func":"rbe","gap":"","start":"","inout":"out","septopics":false,"property":"payload","topi":"topic","x":675,"y":1660,"wires":[["3850a39194311ea6"]],"l":false},{"id":"3850a39194311ea6","type":"debug","z":"8c249630.076968","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":850,"y":1660,"wires":[]}]

You can't compare the contents of objects in javascript using ==.

Try googling 'javascript how to check for an object'

Yeah, I tried, but beyond my paygrade. Any particular page to look at?

What site did you look at and what didn’t you understand?

I know that this is short circuiting the teaching/learning process but this is one way (look for Stackoverflow as a source of answers;

This is one way

/**

    * Description   Determines whether or not supplied argument is of type 'object'.
    * 
    * @param  {*}         objValue     - The argument to check.
    * 
    * @return {boolean}                - True if the argument is of type 'object', otherwise false.
    */

    function isObject(objValue) {

        return objValue != null && objValue.constructor.name === 'Object';

    } // End Function isObject()
1 Like

My issue is, I dont know why it's not working. I'm no coder, obviously. Just a tinkerer. I'm not sure if it's because it's undefined, or because it was missing the === I learn by seeing what someone else has done, and working from that. Thanks @Buckskin, I'll take a look at that page.

So, I think I understand where I was going wrong. Please correct me if I'm wrong.

Since json does something weird, it results in "undefined" from typeof. Thus, in my code above, it always is passed through given the return msg. Is that correct?

In your function 'RBE & Gate' the first time it is run neither the global or the contect variables will exist. This is explained in the Node-RED documentation: Writing Functions : Node-RED.

Since global.get("master_office_lights") will not return anything, both

if (master == "off")

and

if (master == "on")

will be false and nothing is done. And if you initialize the global prior to this function node, the context variable is not initialized.

In addition, you are injecting an object in msg.payload but if 'master' is 'on' you set the context variable to a string. A string will never equal an object so new_input will never equal last_output.

A great way to debug function nodes (see: Writing Functions : Node-RED) is to use node.warn(put something here). You could add node.warn('debug 1')
node.warn('debug 2')
etc... in different parts of the code to see what the path in your code is. You can also use variables in node.warn by using
node.warn("x =" + x)
however if x is an object you will get x =[object Object]. You can add two debug nodes
node.warn("x =")
node.warn(x)
which will return two debug messages and you will be able to expand the object to see what it contains.

Hopefully this will help you move forward with your function by discovering the problems you have in your code. Feel free to ask for more help with your debugging.

p.s. here is a small flow to set the global variable on or off to help you test your code:

[{"id":"44cfe5b3000dc1a1","type":"inject","z":"bfb19c4d8b07d765","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"on","payloadType":"str","x":190,"y":340,"wires":[["f4be8b8ce82d935b"]]},{"id":"f4be8b8ce82d935b","type":"change","z":"bfb19c4d8b07d765","name":"","rules":[{"t":"set","p":"master_office_lights","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":360,"wires":[[]]},{"id":"e672fefca2065ed8","type":"inject","z":"bfb19c4d8b07d765","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"off","payloadType":"str","x":190,"y":400,"wires":[["f4be8b8ce82d935b"]]}]