How to efficiently set and update global variables when received MQTT message

My rasberry pi is subscribed to MQTT topic called "counter". When I start my task, I receive an integer number for example 5.
I set my counter to flow.counter = 5.

I need to set this to flow or global scope because I need to modify this number when another message is received.

When I set my counter to certain number, Raspberry PI is listening for a message from any of the remote clients ( subscribed to +/status).
When raspberry PI received message in +/status "DONE", I need to substract 1 from counter and update it.
My current flow :
THe problem is that the flow.counter is not recognised in another function.

[{"id":"42c4bddf.2275d4","type":"mqtt in","z":"df177cb8.27882","name":"","topic":"counter","qos":"2","datatype":"auto","broker":"2727c5a5.a4fb6a","x":190,"y":1800,"wires":[["bbf33ce8.4d552","c93c7a54.47f698"]]},{"id":"bbf33ce8.4d552","type":"debug","z":"df177cb8.27882","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":400,"y":1800,"wires":[]},{"id":"275d83bd.ad9eec","type":"mqtt in","z":"df177cb8.27882","name":"","topic":"+/status","qos":"2","datatype":"auto","broker":"2727c5a5.a4fb6a","x":700,"y":1800,"wires":[["6bdf19ef.77f2a8","88eb8b89.498378"]]},{"id":"6bdf19ef.77f2a8","type":"debug","z":"df177cb8.27882","name":"status","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":880,"y":1860,"wires":[]},{"id":"88eb8b89.498378","type":"function","z":"df177cb8.27882","name":"function to substract  from counter","func":"msg.topic = 'counter'\nmsg.payload = flow.counter-1\nreturn msg\n\n\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":940,"y":1800,"wires":[["cf2f311e.2291","96944b21.777258"]]},{"id":"c93c7a54.47f698","type":"function","z":"df177cb8.27882","name":"function to make msg.payload to flow.counter","func":"flow.counter = msg.payload\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":510,"y":1700,"wires":[[]]},{"id":"cf2f311e.2291","type":"debug","z":"df177cb8.27882","name":"flow counter","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1230,"y":1800,"wires":[]},{"id":"96944b21.777258","type":"mqtt out","z":"df177cb8.27882","name":"","topic":"","qos":"","retain":"","broker":"2727c5a5.a4fb6a","x":1110,"y":1720,"wires":[]},{"id":"2727c5a5.a4fb6a","type":"mqtt-broker","z":"","name":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"1","birthRetain":"true","birthPayload":"","closeTopic":"","closeQos":"1","closeRetain":"true","closePayload":"","willTopic":"","willQos":"1","willRetain":"true","willPayload":""}]

I think you need to change the first function node to...

flow.set('counter',msg.payload);
return msg;

And the second to...

msg.topic = "counter";
msg.payload = flow.get('counter') -1;
return msg

PS:
You might want to do some 'bound checking'.
For example, what do you want to happen when the value of counter gets to zero or goes negative ??

In addition to what @dynamicdave said you don’t need a function node at all for the first part. You can just use a change node:

1 Like

Thank you for help guys. I have managed to do that with your suggested changes. I need to do one more complicated thing though:

I will explain briefly what is happening in my Program.

So lets say I have 5 remote devices (device1, device2, device3, device4, device5). My raspberry controls the whole flow and sends commands to various devices.

When the Task is started, raspberry PI selects multiple devices and assigns a random number to it("number_to_pick") -(the part with random number is not very important here).

So for example, raspberry PI selects device1, device 3, device4 and assigns "number_to_pick" for each device- The flow below subscribes to all devices and listens for which devices are activated and what number is assigned to them:

[{"id":"3df21402.3b489c","type":"mqtt in","z":"df177cb8.27882","name":"","topic":"+/number_to_pick","qos":"2","datatype":"auto","broker":"2727c5a5.a4fb6a","x":450,"y":2180,"wires":[["d686154b.5e83c8"]]},{"id":"4eeebc21.225364","type":"debug","z":"df177cb8.27882","name":"update number to pick","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":980,"y":2160,"wires":[]},{"id":"d686154b.5e83c8","type":"function","z":"df177cb8.27882","name":"Generate SQL","func":"//add the values to the msg so they can be debugged and used later\nquantity = msg.payload\nvar device_id = msg.topic.split(\"/\");// split the whole topic to devicex ( untill /)\nmsg.payload = device_id[0];\nmsg.topic=`UPDATE pack_to_light SET Quantity = '${quantity}' WHERE Device = '${device_id[0]}'`\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":700,"y":2180,"wires":[["4eeebc21.225364","d8635880.3f1878"]]},{"id":"d8635880.3f1878","type":"mysql","z":"df177cb8.27882","mydb":"97be0e96.67231","name":"update device quantity","x":980,"y":2200,"wires":[[]]},{"id":"2727c5a5.a4fb6a","type":"mqtt-broker","z":"","name":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"1","birthRetain":"true","birthPayload":"","closeTopic":"","closeQos":"1","closeRetain":"true","closePayload":"","willTopic":"","willQos":"1","willRetain":"true","willPayload":""},{"id":"97be0e96.67231","type":"MySQLdatabase","z":"","name":"","host":"localhost","port":"3306","db":"test","tz":""}]

At the same time, raspberry PI counts how many individual devices are activated ( It can vary), In our case 3 individual devices are activated so the counter is set to 3. (We already talked how to make counter a flow type variable so it can be recongnised in other parts of the flow and I will explain why its important)

  1. The second part of the task:

After activating device1, device3, device4, and updating the counter to 3 raspberry PI is waiting for an answer from all of these devices. When a remote device sends an answer(simple push button press) , I need to decrement the counter by 1 and "Deactivate" the device. When all of the devices send a response and are all deactivated, counter goes to 0.

The flow works almost okay, except that is missing one very important thing. When all of the devices are deactivated and counter goes to 0, I need to send a message to each device that was active during that period ( in our case, device1, device3, device4 needs to receive message "Good_Job" and device2 and device5 should not receive anything.

To make this work, I probably need to save device1,device3,device4 into a global or flow variable, so when the counter gets to 0, i know whom to send a message. After a messages are sent, I need to clear all the flow variable and prepare for the next task.

The function that I use to update "number_of_items" for activated devices:

//add the values to the msg so they can be debugged and used later
quantity = msg.payload
var device_id = msg.topic.split("/");// split the whole topic to devicex ( untill /)
msg.payload = device_id[0];
msg.topic=`UPDATE pack_to_light SET Quantity = '${quantity}' WHERE Device = '${device_id[0]}'`

return msg;

This function will be executed 3 times, because we receive 3 seperate messages for each active device (device1,device3,device4). If i change var device_id to global would that be a good solution? Also, I am not too sure how would I keep track of number of active devices.

Since this function executes 3 times, could I do something like:

flow.set('individual_device[0]',msg.topic.split("/"));

except that I am not too sure how would i dynamically change number [0], [1]. [2] to fill an array with different device names

Another option would be to use initial counter value, since it describes how many individual devices are active. If the counter initially is set to 3, maybe I could do something like:

for(i=0;i<counter;i++){
     flow.set('individual_device[i]',msg.topic.split("/"));
}

Any suggestions are welcome please
I hope I have explained task well enough

Complete flow:

[{"id":"42c4bddf.2275d4","type":"mqtt in","z":"df177cb8.27882","name":"","topic":"counter","qos":"2","datatype":"auto","broker":"2727c5a5.a4fb6a","x":150,"y":1800,"wires":[["c93c7a54.47f698","bbf33ce8.4d552"]]},{"id":"bbf33ce8.4d552","type":"debug","z":"df177cb8.27882","name":"counter","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":390,"y":1800,"wires":[]},{"id":"275d83bd.ad9eec","type":"mqtt in","z":"df177cb8.27882","name":"","topic":"+/status","qos":"2","datatype":"auto","broker":"2727c5a5.a4fb6a","x":700,"y":1800,"wires":[["88eb8b89.498378","6bdf19ef.77f2a8"]]},{"id":"6bdf19ef.77f2a8","type":"debug","z":"df177cb8.27882","name":"status","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":880,"y":1860,"wires":[]},{"id":"88eb8b89.498378","type":"function","z":"df177cb8.27882","name":"function to substract  from counter","func":"if (msg.payload = \"DONE\"){\nmsg.topic = \"counter\"\nmsg.payload = flow.get('counter')-1\nreturn msg\n}\nelse {\n\n}\n\n\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1020,"y":1800,"wires":[["96944b21.777258"]]},{"id":"c93c7a54.47f698","type":"function","z":"df177cb8.27882","name":"function to make msg.payload to flow.counter","func":"flow.set('counter',msg.payload);\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","x":410,"y":1720,"wires":[[]]},{"id":"96944b21.777258","type":"mqtt out","z":"df177cb8.27882","name":"update counter","topic":"","qos":"","retain":"","broker":"2727c5a5.a4fb6a","x":1340,"y":1700,"wires":[]},{"id":"3df21402.3b489c","type":"mqtt in","z":"df177cb8.27882","name":"","topic":"+/number_to_pick","qos":"2","datatype":"auto","broker":"2727c5a5.a4fb6a","x":410,"y":2060,"wires":[["d686154b.5e83c8"]]},{"id":"4eeebc21.225364","type":"debug","z":"df177cb8.27882","name":"update number to pick","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":940,"y":2040,"wires":[]},{"id":"d686154b.5e83c8","type":"function","z":"df177cb8.27882","name":"Generate SQL","func":"//add the values to the msg so they can be debugged and used later\nquantity = msg.payload\nvar device_id = msg.topic.split(\"/\");// split the whole topic to devicex ( untill /)\nmsg.payload = device_id[0];\nmsg.topic=`UPDATE pack_to_light SET Quantity = '${quantity}' WHERE Device = '${device_id[0]}'`\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":660,"y":2060,"wires":[["4eeebc21.225364","d8635880.3f1878"]]},{"id":"d8635880.3f1878","type":"mysql","z":"df177cb8.27882","mydb":"97be0e96.67231","name":"update device quantity","x":940,"y":2080,"wires":[[]]},{"id":"2727c5a5.a4fb6a","type":"mqtt-broker","z":"","name":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"1","birthRetain":"true","birthPayload":"","closeTopic":"","closeQos":"1","closeRetain":"true","closePayload":"","willTopic":"","willQos":"1","willRetain":"true","willPayload":""},{"id":"97be0e96.67231","type":"MySQLdatabase","z":"","name":"","host":"localhost","port":"3306","db":"test","tz":""}]

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