Need help with my subflow - deepcopy msg problem

I am trying to write my own filter (RBE) node but its mode can be changed with commands.

It works for simple things, but when I get a complex message it doesn't seem to work.

Here is a flow with the subflow in it.

There are options to configure the subflow.
The default (startup) mode and you need to set the topic for the control messages.
And - lastly - if it also uses the message topic for comparing messages. (Not perfect, but....)

The commands are:

Anyway, here's the code:

[{"id":"5a6ca5972b0f9e7b","type":"subflow","name":"Advanced blocker","info":"You need to set the `env` variable `TOPIC` to set the control topic.\nInput values:\n - STOP - basically don't pass ANY message.\n - ALL - pass all messages.\n - BLOCK - block repeats of same message.\n - ONE - pass ONLY the next message to arrive.  (ONE)","category":"","in":[{"x":170,"y":130,"wires":[{"id":"685360a3.c08db8"}]}],"out":[{"x":550,"y":130,"wires":[{"id":"685360a3.c08db8","port":0}]}],"env":[{"name":"TOPIC","type":"str","value":""},{"name":"DEFAULT_MODE","type":"str","value":""},{"name":"topic_mode","type":"bool","value":"false","ui":{"type":"input","opts":{"types":["bool"]}}}],"meta":{},"color":"#3FADB5","icon":"node-red/function.svg","status":{"x":550,"y":190,"wires":[{"id":"197b01d950cf86b4","port":0}]}},{"id":"685360a3.c08db8","type":"function","z":"5a6ca5972b0f9e7b","name":"My blocker node.  V6.1b","func":"////////////////////////////////////////////////////////////////////////////////\n//  Version 6.1\n//  2022 04 25\n//  Added topic specific blocking or generic\n//  This is mentiond below on earlier update but not applied.\n\n//      The shape property can be: ring or dot.\n//      The fill property can be: red, green, yellow, blue or grey\n\n//      These are the three commands accepted.\nconst all = \"ALL\";          //  Allow all message to pass\nconst block = \"BLOCK\";      //  Block repeat message (of same topic)\nconst one = \"ONE\";          //  Allow ONE message to pass.  (may not be perfect)\nconst stop = \"STOP\";        //  Block ALL message...  ALL!\n//  Get topic\nvar topic = msg.topic;\nif (topic == \"\")\n    topic = \"BLANK\";\nif (msg.topic == undefined)\n    topic = \"BLANK\";\n//  Get new value from message\n\n\ntopic_mode = env.get(\"topic_mode\") || \"\";\nif (topic_mode.length < 1)\n{\n    //  *****\n    topic_mode = false;\n}\nif (topic_mode == false)\n    topic = \"BLANK\";\n\n//  Used to determine if a message was received to change the mode.\nvar updated_mode = context.get(\"updated_mode\") || 0;\n\n////////////////////////////////////////////////////////////////////////////////\n//\n//  2022 03 06\n//\n//  Needs work here as the *default* topic is being reset\n//  every time a new message comes through.\n//  Set `updated_mode` to `1` so it won't be called again.\n\n//  See if there is a DEFAULT MODE set.\nif (updated_mode == 0)\n{\n    let default_mode = env.get(\"DEFAULT_MODE\");\n    if (default_mode.length > 0)\n    {\n        //\n        context.set(\"MODE\",default_mode);\n        context.set(\"updated_mode\",1)\n    }\n}\n\ncontext.set(\"MODE\",\"BLOCK\");\ncontext.set(\"updated_mode\",1)\n\n//node.warn(\"Topic is set to \" + topic);\n\nvar lastval = context.get(topic);\n//node.warn(\"Stored value is \" + lastval);\n\n\nvar newval = msg.payload;\ncontext.set(topic,newval);\n\n\n//  Get the topic used to determine which messages are to control the mode.\nlet CTLTopic = env.get(\"TOPIC\");\nif (CTLTopic.length < 1)\n    throw\"You must define a TOPIC for controlling the node\";\nCTLTopic = \"MODE\";\n\nif (msg.topic == CTLTopic)\n{\n    //\n    //  Set how node works.\n    //\n\n    if (msg.payload == stop)\n    {\n        node.status({ text: \"Set to stop\" });\n        context.set(\"MODE\",msg.payload);\n        node.warn(\"Set to STOP\");\n        context.set(\"BLANK\",\"\");        //  2022 04 26\n    } else if (msg.payload == block)\n    {\n        node.status({ text: \"Set to block\" });\n        context.set(\"MODE\",msg.payload);\n        node.warn(\"Set to BLOCK\");\n    } else if (msg.payload == all) \n    {\n        node.status({ text: \"Set to allow\" });\n        context.set(\"MODE\",msg.payload);\n        node.warn(\"Set to ALL\");\n        context.set(\"BLANK\",\"\");        //  2022 04 26\n    } else if (msg.payload == one) \n    {\n        context.set(\"previousMode\",context.get(\"MODE\"));\n        node.warn(context.get(\"previousMode\"));\n        node.status({ text: \"Set to once\" });\n        context.set(\"MODE\",msg.payload);\n    } else      //      Show valid commands.\n    {\n        node.warn(\"For control of the node's mode msg.payload must be `\" + all + \"` `\" + block + \"` or `\" + stop + \"` or `\" + one +\"`\");\n    };\n//    context.set(\"updated_mode\",1);  2022 03 06 no longer needed\n    return;\n}\n\n\n\n//        --  Main code starts here.\n\n//  Get status from context.\nvar mode = context.get(\"MODE\");\n\n//  =============== STOP\n//else if (mode == \"STOP\")\nif (mode == stop)\n{\n    return;\n}\n//  =============== ALL\n//else if (mode == \"ALL\")\nelse if (mode == all)\n{\n    node.status({fill:\"blue\",shape:\"dot\",text:\"All\"});\n    context.set(topic, newval);\n    return msg;\n}\n//  =============== BLOCK\n//if (mode == \"BLOCK\")\nelse if (mode == block)\n{\n    //\n    //  See if the new value is different to the old value.\n    //\n    //node.warn(\"Old value \" + lastval);\n    //node.warn(\"New value \" + newval);\n    if (newval != lastval)\n    {\n       context.set(topic, newval);\n       node.status({fill:\"green\",shape:\"dot\",text:\"Passed\"});\n       return msg;\n    }\n    node.status({fill:\"red\",shape:\"dot\",text:\"Blocked\"});\n    return;\n}\n//  =============== ONE\n//else if (mode == \"ONE\")\nelse if (mode == one)\n{\n    //\n    //  Allow only 1 message to pass\n    //\n//    mode = context.get(\"MODE\");\n    node.warn(\"Allowing ONE message\");\n    context.set(topic, newval);\n    context.set(\"MODE\",context.get(\"previousMode\"));\n//    context.set(\"MODE\",\"BLOCK\");\n    node.status({ text: \"Set to \" + context.get(\"previousMode\") });\n    return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":130,"wires":[[]]},{"id":"197b01d950cf86b4","type":"status","z":"5a6ca5972b0f9e7b","name":"","scope":["685360a3.c08db8"],"x":310,"y":190,"wires":[[]]},{"id":"7d9e2fcda831d99d","type":"subflow:5a6ca5972b0f9e7b","z":"e2bd5a4e.5597e8","name":"","env":[{"name":"TOPIC","value":"MODE","type":"str"},{"name":"DEFAULT_MODE","value":"BLOCK","type":"str"}],"x":3530,"y":3700,"wires":[["c5ef9215d84dccbe"]]},{"id":"32a409f5fd84f06c","type":"inject","z":"e2bd5a4e.5597e8","name":"ALL","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"MODE","payload":"ALL","payloadType":"str","x":3490,"y":3750,"wires":[["7d9e2fcda831d99d"]]},{"id":"ac49686314b4f056","type":"inject","z":"e2bd5a4e.5597e8","name":"STOP","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"MODE","payload":"STOP","payloadType":"str","x":3490,"y":3780,"wires":[["7d9e2fcda831d99d"]]},{"id":"9bf5730521cb69fc","type":"inject","z":"e2bd5a4e.5597e8","name":"BLOCK","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"MODE","payload":"BLOCK","payloadType":"str","x":3490,"y":3810,"wires":[["7d9e2fcda831d99d"]]},{"id":"6338a36f02faeb52","type":"inject","z":"e2bd5a4e.5597e8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"A","payloadType":"str","x":3310,"y":3660,"wires":[["7d9e2fcda831d99d"]]},{"id":"e76dd88b6b55e6fe","type":"inject","z":"e2bd5a4e.5597e8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"B","payloadType":"str","x":3310,"y":3700,"wires":[["7d9e2fcda831d99d"]]},{"id":"c5ef9215d84dccbe","type":"debug","z":"e2bd5a4e.5597e8","name":"THIS ONE","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":3770,"y":3700,"wires":[]},{"id":"c87a643f85876c29","type":"inject","z":"e2bd5a4e.5597e8","name":"A","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"A","payloadType":"str","x":3310,"y":3820,"wires":[["7d9e2fcda831d99d"]]},{"id":"09015bb9ca6ebb1b","type":"inject","z":"e2bd5a4e.5597e8","name":"B","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"something","payload":"B","payloadType":"str","x":3310,"y":3870,"wires":[["7d9e2fcda831d99d"]]},{"id":"4702523e25f6b9a9","type":"inject","z":"e2bd5a4e.5597e8","name":"C","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"something","payload":"C","payloadType":"str","x":3310,"y":3920,"wires":[["7d9e2fcda831d99d"]]},{"id":"6480d3903931e9d5","type":"inject","z":"e2bd5a4e.5597e8","name":"B","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"B","payloadType":"str","x":3310,"y":3780,"wires":[["7d9e2fcda831d99d"]]},{"id":"e4e3bbeea1dbf510","type":"inject","z":"e2bd5a4e.5597e8","name":"B","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"B","payloadType":"str","x":3310,"y":3740,"wires":[["7d9e2fcda831d99d"]]},{"id":"30f467b5b4a4a15a","type":"inject","z":"e2bd5a4e.5597e8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":3190,"y":3570,"wires":[["92391f004a2e5fe2"]]},{"id":"92391f004a2e5fe2","type":"function","z":"e2bd5a4e.5597e8","name":"","func":"msg.payload = {\"Who\":\"TimePi\",\"device\":\"UpLink\",\"UpLink\":\"Online\"};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":3350,"y":3570,"wires":[["7d9e2fcda831d99d","e4527527d935cf62"]]},{"id":"e4527527d935cf62","type":"debug","z":"e2bd5a4e.5597e8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":3510,"y":3570,"wires":[]},{"id":"9264231b45e9c232","type":"comment","z":"e2bd5a4e.5597e8","name":"This part works.","info":"","x":3140,"y":3780,"wires":[]},{"id":"b7033b3b5a07e475","type":"comment","z":"e2bd5a4e.5597e8","name":"Doesn't work.","info":"","x":3360,"y":3530,"wires":[]}]

If I am injecting the Working nodes, it seems to do as it is told/set.

But the top bit/part is where it all falls apart.
I'm guessing that the message (payload) isn't stored correctly so when it comes through again it isn't being blocked.

So what's the trick to get the message remembered?

Without looking at your code in any depth, my suspicion is you need to clone before storing / restoring from context.



PS ↑ these are the benefits of switching to the monaco editor

also, you would see other issues...



Yeah, I am going to have to get the finger out and install that editor some day.

That first bit
const copy = RED.util.closeMessage(msg)
That looks like the main problem, but where would I have found out about it?

And why const? This changes with every new incoming message.
And again with the newval.... why const?

Thanks though.

edit settings.js & restart & refresh - done!.

In the docs

  • RED.util.cloneMessage(..) : safely clones a message object so it can be reused

Every time a function is executed, the consts, lets, vars are all created - EVERY TIME.
Use const to avoid redefinition within the function (helps you avoid issues).

1 Like

Yeah, sorry about not knowing... I never got that deep into coding alas. When I did it, it was a very different thing and even then, I was at/in the shallow end of the pool.

Onto the editor:
So.... lib: "ace".... is that a normal program on the RasPi (for that machine) and what if I am using Ubuntu on some?
(I feel I have to ask, or I am going to get into a mess very quickly)

If I am understanding that about the editor I ssh to one of the RasPi and typed in ace....
Command not found. :frowning:

pi@TimePi:~ $ ace
-bash: ace: command not found
pi@TimePi:~ $

Oh that machine is running buster.

You literally just open the settings.js file in the .node-red folder & set the value as I showed.

ace & monaco are not executables, they are web based editors built in to node-red v2.x

Oops. Ok. Shall try now.

T'would be nicer if you showed the closing of the { but I'm guessing all there is are comments in yours.
My settings.js file doesn't have any of that in it, so I am hoping that all I need is to add the line (with correct indenting) like this:

codeEditor: {
    lib: "ace",

But I have a sneaky suspicions there may be more to it because of the , inside the { and }
(oh NR 2.2.2)

tarting as a systemd service.
Error loading settings file: /home/pi/.node-red/settings.js
SyntaxError: Unexpected identifier
    at wrapSafe (internal/modules/cjs/loader.js:1001:16)
    at Module._compile (internal/modules/cjs/loader.js:1049:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module._load (internal/modules/cjs/loader.js:790:12)
    at Module.require (internal/modules/cjs/loader.js:974:19)
    at require (internal/modules/cjs/helpers.js:101:18)
    at Object.<anonymous> (/usr/lib/node_modules/node-red/red.js:136:20)
    at Module._compile (internal/modules/cjs/loader.js:1085:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
nodered.service: Succeeded.

As I suspected.

I need to learn to read.

find this..... not found. Sorry.

If you have upgraded from node-red V1 to V2 at some point, your settings file will be old & missing many new settings & features.

This is the default settings file for reference: node-red/settings.js at 4acb66fb7a4c50ba237248ac61b20f0472526d08 · node-red/node-red · GitHub


But I'm confused - as usual.

Ok, Yes, I updated to NR 2.x and the settings.js file didn't update.
Well, maybe it did, but when restored my stuff, it probably overwrote that. (Opps?)

But if I add the valid entry for the codeEditor why would it spit the dummy?
(Semi rhetorical)

I'll look at that link and see what I can work out.

No it won't, you have to do that manually and keep your settings.js file up to date.
The node-RED release notes always tells you about what changes are needed.

Ok, I stand corrected. But if they/it were/was updated, as I said: I would have overwritten it when I threw my stuff in there.

I'm looking at the file now (the settings.js) one.

Yeah, this is going to be fun.

The editor is working, but only just.
The theme isn't quite working, but that isn't End of the world for me.

I'll get back to that once I get the actual problem resolved.

So @Steve-Mcl this..... RED.util.cloneMessage(msg).....
I've looked at the link you posted (down the bottom) and read:


    RED.util.cloneMessage(..) : safely clones a message object so it can be reused

That means both everything and nothing to me.

I see a command, and what it does, but not how to use it. (Well, it could be argued I am shown how to use it, but not fully.)

Once I've done that, then what?
There is no continuation on with explaining anything about it.

Ok, my problem....

Sorry... I'll see what I can find.

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