Can NodeRED preserve unique copies of a variable while a flow is exercised multiple times simultaneously?

I have a fairly intricate dimming flow setup for Lutron switches across about 20 different rooms. The dimmers will actually dim partially and then loop looking for motion for about 20 seconds to warn anyone present that they’re about to shut off. If motion is detected, they turn back on.

To accomplish this, I have setup a single shared ‘dimming’ flow that each room proceeds through after a timeout period is elapsed without motion. However, the problem I run into is that sometimes the dimming logic is triggered for two different rooms within that 20 second window, thereby over-writing its ‘flow’ variable to the second light, which has the effect of turning off the second light twice.

This problem is demonstrated in the simplified flow I posted below (trigger both buttons within 5 seconds to see what I mean.)

For ease of maintenance, I’d really like one shared dimming flow. Is there a way to resolve this that doesn’t involve copying and pasting the flow for each room independently?

[{"id":"d9b049cc.1afbc8","type":"debug","z":"95264241.85f59","name":"Turn off","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1670,"y":900,"wires":[]},{"id":"2d17756b.dd01da","type":"template","z":"95264241.85f59","name":"debug msg","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"Switch off in {{flow.counter}}.","output":"str","x":1500,"y":900,"wires":[["d9b049cc.1afbc8"]]},{"id":"12e1b06a.cc1fc8","type":"inject","z":"95264241.85f59","name":"Kitchen","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":760,"y":870,"wires":[["7760c9b.749efb8"]]},{"id":"7760c9b.749efb8","type":"change","z":"95264241.85f59","name":"Set variable to Kitchen","rules":[{"t":"set","p":"counter","pt":"flow","to":"kitchen","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":950,"y":870,"wires":[["9267b4d5.a136e"]]},{"id":"af27ffb2.3bc188","type":"change","z":"95264241.85f59","name":"Set variable to Office","rules":[{"t":"set","p":"counter","pt":"flow","to":"office","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":950,"y":930,"wires":[["9267b4d5.a136e"]]},{"id":"f9cebe20.fc8b28","type":"inject","z":"95264241.85f59","name":"Office","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":760,"y":930,"wires":[["af27ffb2.3bc188"]]},{"id":"9267b4d5.a136e","type":"delay","z":"95264241.85f59","name":"Dim motion delay","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":1300,"y":900,"wires":[["2d17756b.dd01da"]]}]

without analyzing your flow: yes, NR applies OOP (object oriented programming) paradigms to data which are being processed.

That means, if you define json object in one location (ie by setting flow variable to json object), then change one of its attributes in other place of the flow (using replace or function node) you will change the original one.

The same applies to the messages. However if I remember correctly a few years ago NR got update where message comming from function nodes are being ‘deep copied’ by default (to create new objects). It is in order to avoid unwanted interference between messages which originate from the same message but have been sent to different processing paths.

article bellow says that for other nodes, each node is responsible for that on its own. So maybe there are nodes which don’t create new msg objects, instead passes their references.

however… your example is not about preserving copies of variable.

You are literally changing the same variable flow.counter.
Flow variables are common for the flow (while flow is not meant “a message” but the “current messaging diagram” instead. And there is the only one run-time instance of each flow (diagram) while all messages are processed by this single instance.

In order to minimize code redundancy, you can look at sub-flows.

So it took me a bit of trial and error, but I think this is what you mean? I first tried having both buttons go into one subflow, but ran into the same problem with variables being overwritten. When i used separate instances of the subflow as shown below, they all seem to get their own local variables, and it works well… Thanks!

[{"id":"3c8ba9f8.c0b9c6","type":"subflow","name":"Subflow 1","info":"","category":"","in":[{"x":80,"y":80,"wires":[{"id":"b33314fc.917d68"}]}],"out":[],"env":[],"meta":{},"color":"#DDAA99"},{"id":"eba53e56.e936c","type":"debug","z":"3c8ba9f8.c0b9c6","name":"Turn off","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":780,"y":80,"wires":[]},{"id":"665577a5.a52b","type":"template","z":"3c8ba9f8.c0b9c6","name":"debug msg","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"Switch off in {{flow.room}}.","output":"str","x":610,"y":80,"wires":[["eba53e56.e936c"]]},{"id":"93a045ba.c84618","type":"delay","z":"3c8ba9f8.c0b9c6","name":"Dim motion delay","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":410,"y":80,"wires":[["665577a5.a52b"]]},{"id":"b33314fc.917d68","type":"change","z":"3c8ba9f8.c0b9c6","name":"","rules":[{"t":"set","p":"room","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":210,"y":80,"wires":[["93a045ba.c84618"]]},{"id":"1fcbcbd9.344974","type":"inject","z":"95264241.85f59","name":"Kitchen","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":760,"y":630,"wires":[["707e8c0e.dd248c"]]},{"id":"707e8c0e.dd248c","type":"change","z":"95264241.85f59","name":"Set variable to Kitchen","rules":[{"t":"set","p":"payload","pt":"msg","to":"kitchen","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":950,"y":630,"wires":[["108eb07d.ed5eb"]]},{"id":"7ed89934.822e08","type":"change","z":"95264241.85f59","name":"Set variable to Office","rules":[{"t":"set","p":"payload","pt":"msg","to":"office","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":950,"y":690,"wires":[["5b4ad320.38113c"]]},{"id":"3643980.3b5cce8","type":"inject","z":"95264241.85f59","name":"Office","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":760,"y":690,"wires":[["7ed89934.822e08"]]},{"id":"108eb07d.ed5eb","type":"subflow:3c8ba9f8.c0b9c6","z":"95264241.85f59","name":"Dimmer subflow","env":[],"x":1180,"y":630,"wires":[]},{"id":"5b4ad320.38113c","type":"subflow:3c8ba9f8.c0b9c6","z":"95264241.85f59","name":"Dimmer subflow","env":[],"x":1180,"y":690,"wires":[]}]