Inline node for debugging that can be enabled or disabled without deploying every time

After making a feature request and bumbling about with setting the node status from inside a function, I have my solution.

Here is a subflow that is an inline debug output node. That can be enabled, or disabled and can be set to output the msg.payload only, or the entire msg object. Just like a regular debug node. But it can consolidate many connections in. as seen in this example:

Instead of connecting a debug node to ALL of the outputs of the inject nodes AND where ever else the connections go. I simply have to put this inline debug node before the mqtt output node to see what's making it to the mqtt node input.

Using the shift click and drag to move the connections from the input of the mqtt node to the input of the inline debug node. (I just learned about this the other day. It's very handy)

The options for the subflow are to enable or disable the debug output of the node. or the select the msg object or only the payload to be output to the debug tab via the properties window of the subflow node. To change these options, double click on the subflow node after it has been placed.

image

As you can see in the first image, there is also an inject node labelled "toggle"

Connecting an inject node with the topic set to "toggle" and connecting to the input of the Inline Debug node will turn its output on or off without having to redeploy every time. \

Like this. The topic of the inject node must be set to "toggle"
image

This will alternately enable or disable the node when you click it. Which will be indicated by the status of the inline debug node. Like so.
image
image

As always, this has been a learning experience. Any suggestions or improvements are welcome. I've probably overlooked something. I have tested it to see what happens when multiples are deployed on the same flow and it seems to be okay. They seem to keep to themselves. edit: fixed this. It now sets on deployment. On initial deployment the status doesn't get set so there's no display until something passes through it for the first time. And just to clarify, the msg object will always be passed through to the output.

Oh. Almost forgot to post the code. Here ya go.

[
    {
        "id": "c2bcad1.0c3e4d",
        "type": "subflow",
        "name": "Inline Debug",
        "info": "This is a debug node that can be placed inline\nso you can see what's going into another node,\nor passing through a node",
        "category": "",
        "in": [
            {
                "x": 160,
                "y": 180,
                "wires": [
                    {
                        "id": "bd6896fe.f4e21"
                    }
                ]
            }
        ],
        "out": [
            {
                "x": 560,
                "y": 170,
                "wires": [
                    {
                        "id": "bd6896fe.f4e21",
                        "port": 0
                    }
                ]
            }
        ],
        "env": [
            {
                "name": "payloadOnly",
                "type": "bool",
                "value": "true"
            },
            {
                "name": "enabled",
                "type": "bool",
                "value": "true"
            }
        ],
        "icon": "node-red/debug.png",
        "status": {
            "x": 560,
            "y": 220,
            "wires": [
                {
                    "id": "bd6896fe.f4e21",
                    "port": 1
                }
            ]
        }
    },
    {
        "id": "bd6896fe.f4e21",
        "type": "function",
        "z": "c2bcad1.0c3e4d",
        "name": "debugOutputFunction.V1",
        "func": "var x,y,status,active;\n\nx = env.get('enabled');\ny = env.get('payloadOnly');\n\n//check here to make sure the proper variables are set\nif (typeof (flow.get(\"active\")) === \"undefined\"||isNaN(flow.get(\"active\"))) {\n   flow.set(\"active\",\"1\");\n}\nelse{\n    active = flow.get(\"active\");\n}\n//when toggle is clicked, do this, or this, or this.\nif (msg.topic==\"toggle\"){\n    active = Math.abs(active-1);\n    flow.set(\"active\",active);\n}\n\n\n\n//Set the status here\nif (active===0){ \n    status = ({fill:\"red\",shape:\"dot\",text:\"output:disabled\"});\n}\n\nif (active===1){\n    //if active is on and output is payload only, set status to\n    if (y===true ){\n    status = ({fill:\"green\",shape:\"dot\",text:\"output:msg.payload\"});\n    }  \n    //if active is on and output is msg.object, set status to\n    if (y===false ){\n    status = ({fill:\"green\",shape:\"ring\",text:\"output:msg object\"});\n    }\n}\n\n//if msg.topic is toggle, return from here. No need to go any further. \n//if msg.topic is \"initstatusofinlinedebugnode\" return also\n//that topic is unlikely to collide with user's topics\nif(msg.topic ==\"toggle\"||msg.topic===\"initstatusofinlinedebugnode\"){\nreturn [null,{payload:status}];\n}\n\n\n//If active is on, then send the debug output here\nif (active===1){\n//payload only\n    if (x===true & y===true){\n        node.warn(msg.payload);\n    }\n\n//output entire msg object\n    if (x===true & y===false){\n        node.warn(msg);\n    }\n}\nreturn [msg,{payload:status}];",
        "outputs": 2,
        "noerr": 0,
        "x": 370,
        "y": 180,
        "wires": [
            [],
            []
        ]
    },
    {
        "id": "d985eda5.620dd8",
        "type": "config",
        "z": "c2bcad1.0c3e4d",
        "name": "",
        "properties": [
            {
                "p": "active",
                "pt": "flow",
                "to": "1",
                "tot": "num"
            }
        ],
        "active": true,
        "x": 110,
        "y": 60,
        "wires": []
    },
    {
        "id": "53b38a00.d5b3b4",
        "type": "inject",
        "z": "c2bcad1.0c3e4d",
        "name": "",
        "topic": "initstatusofinlinedebugnode",
        "payload": "",
        "payloadType": "date",
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "x": 130,
        "y": 110,
        "wires": [
            [
                "bd6896fe.f4e21"
            ]
        ]
    }
]
5 Likes

Side note: you can turn on/off a debug node without deploying.

1 Like

Just imported this and it said config error

it looks like this

image

I might be wrong but I think his flow with subflow properties was made in V1 node-red and I guess you're not using v1?

This would suggest in some cases, v1 flows are not backwards compatible?

If that is the case & it is known then perhaps the case for a built in "inline debug" (or an output pin on the current debug) is ok? I mean if there are breaking changes in flow compatibility then this is a good time to do the inline debug thing surely? :thinking:

*I could be completely wrong of course ;)*

As far as I know config is a contrib node node-red-contrib-config

Yep - ta :slight_smile:
Although since it doesn't actually seem to set anything I wonder if it was just accidentally left inside the sub-flow

1 Like

Subflow properties were introduced in 0.20

The V1 in there is the version of the function code as saved in the function library inside node-red. The version of node-red I'm using is fully updated as of the time of the posting. v0.20.7

The error is because the module "config" is missing. The config node can be found in node-red-contrib-config.

The config node just sets a flow variable that the function looks for which might not be there the first time it runs after a system restart.

It doesn't seem to set anything

If its meant to set flow.active then you seem to have that covered inside your function

//check here to make sure the proper variables are set
if (typeof (flow.get("active")) === "undefined"||isNaN(flow.get("active"))) {
   flow.set("active","1");
}
else{
    active = flow.get("active");
}

Much better not to require non-core nodes if possible I think

2 Likes

Did you import the node-red-contrib-config after you imported the subflow? It might have lost that bit. It does set the flow variable "active" to 1.I suppose it's not absolutely essential. You can probably delete it from the flow. I just had that in there for insurance. I'm still not 100% sure about what gets set where and what gets cleared after a deploy or node-red restart so I had that in there.

Yes I did - so that would explain why its empty :slight_smile: