Ask Node-red flow to wait until !!

6,194 views
Skip to first unread message

myIoT

unread,
Oct 4, 2015, 10:44:38 PM10/4/15
to Node-RED
Hi,

I have a node-red/RPi connected thermal printer (calling a python exec) which prints some messages. The message is based on MQTT subscription, which arrives randomly from various sources. It works fine as long as the current print job is finished. When MQTT node receives the second msg when the printer is still busy printing, then the lines mess with messages printing one after another. Ideally the serial printer keeps receiving and printing messages even before finishing its first job.

How do i control the flow of the MQTT subscription or have in-between some function to wait/pause until the current print job is done. Any pointers would help me move further.

EK
Message has been deleted

Walter Kraembring

unread,
Oct 5, 2015, 12:12:22 AM10/5/15
to Node-RED
If you know that all type of messages will be printed within a defined maximum time period (let's say 15 seconds), you could use the delay node as in-between



myIoT

unread,
Oct 5, 2015, 4:00:38 PM10/5/15
to Node-RED
Hi Walter,

Great, i did tried that option earlier but somehow missed the point. It works as per your idea.

I could see the rate limit/delay node queues the incoming messages nicely and passes to the next node automagically by averaging within that said period. 
Though its not a 100% solution, it solves my current problem. Perhaps is there any alternate foolproof method to handle such scenarios?

Any thoughts on real queue based solution which can be used in RPi, so that i can pick a message in the queue, process it, then come and pick the next one,  AFAIK mosquitto MQTT supports only pub/sub.

Regards
EK

Dave C-J

unread,
Oct 5, 2015, 4:24:10 PM10/5/15
to node...@googlegroups.com
can you get any feedback from the printer to say when it has finished a job ?
That can then be used to trigger the next message ?

myIoT

unread,
Oct 6, 2015, 12:06:39 AM10/6/15
to Node-RED
Yes, once the print job is done, it will return a status message as part of the exec node.

Now can you shed some light on how to trigger the next message?

Even i thought of having a global variable flag before starting the print and after finishing. But the messages from the MQTT won't wait, as soon as it receives, it just starts processing it.

Thanks
EK

Richard Ruston

unread,
Oct 6, 2015, 9:30:34 AM10/6/15
to Node-RED
You would need to implement your own little FIFO queue I would think - I've not done that in Python but I would hope it wouldn't be too tricky, and there might be a helper module out there.

You would then have one thread handling receipt of messages from MQTT, and pushing them onto the local queue to store them until your printer can get to them
and a different thread pulling messages off the queue and printing them in sequence.

HTH

Richard

Richard Ruston

unread,
Oct 6, 2015, 10:17:30 AM10/6/15
to Node-RED
Ooops, my brain isn't functioning today, I think I misunderstood what you want to do - which is receive an MQTT message in NodeRED, then fire a print job using exec (if I understand correctly) from NodeRED. You need the flow to pause for new invocations while the previous print finishes.

Are you simply reading the message and printing it or is there some manipulation being done by NR? If the former, is there a reason you need to use NR when it would be simple to do it in Python directly? If you do need specific processing done in NodeRed, you could have NR send the 'final' message to a different MQTT queue (and broker if required) and have a bit of python handing the print again as per the above.

My 'UnicornHAT' demo using NodeRed uses a similar construct which allows me to abstract the mechanics of controlling a UnicornHAT away from NodeRed (i.e. NR doesn't need to know the state of the HAT, it just feeds it messages). Something like that might remove the mechanics of the printer away from NR....

I hope that makes sense.

Richard

Dave C-J

unread,
Oct 6, 2015, 10:25:40 AM10/6/15
to node...@googlegroups.com

A simple in memory queue is hopefully all that's needed, using an array held in the global context. Example to follow later.

Dave C-J

unread,
Oct 6, 2015, 3:00:18 PM10/6/15
to node...@googlegroups.com
Here is an example - I'm using the exec to call say on my mac as that exhibits the same behaviour... ie if triggered multiple times it will overlap the spoken words... using the flow below it waits for the exec to finish before releasing the next message.

[{"id":"c503216.f3afce","type":"inject","z":"9e538f88.61ac7","name":"","topic":"","payload":"\"Isn't it nice to have a computer that will talk to you?\"","payloadType":"string","repeat":"","crontab":"","once":false,"x":149,"y":583,"wires":[["8d68ad.ff72975"]]},{"id":"8d68ad.ff72975","type":"function","z":"9e538f88.61ac7","name":"Simple triggered queue","func":"// if queue doesn't exist, create it\ncontext.queue = context.queue || [];\ncontext.busy = context.busy || false;\n\n// if the msg is a trigger one release next message\nif (msg.hasOwnProperty(\"trigger\")) {\n    if (context.queue.length > 0) {\n        var m = context.queue.shift();\n        return {payload:m};\n    }\n    else {\n        context.busy = false;\n    }\n}\nelse {\n    if (context.busy) {\n        // if busy add to queue\n        context.queue.push(msg.payload);\n    }\n    else {\n        // otherwise we are empty so just pass through and set busy flag\n        context.busy = true;\n        return msg;\n    }\n}\n\nreturn null;","outputs":1,"noerr":0,"x":374,"y":586,"wires":[["8bb0eecc.744f1"]]},{"id":"e872b22f.178d5","type":"function","z":"9e538f88.61ac7","name":"set trigger","func":"// handle the return from the exec in here \n// if all is good then set msg.trigger property to exist\nmsg.trigger = 1;\nreturn msg;","outputs":1,"noerr":0,"x":654,"y":740,"wires":[["8d68ad.ff72975"]]},{"id":"8bb0eecc.744f1","type":"exec","z":"9e538f88.61ac7","command":"say","addpay":true,"append":"","useSpawn":false,"name":"","x":589,"y":587,"wires":[["23263896.dcd9c8","e872b22f.178d5"],[],[]]},{"id":"23263896.dcd9c8","type":"debug","z":"9e538f88.61ac7","name":"","active":true,"console":"false","complete":"false","x":815,"y":576,"wires":[]}]

Richard Ruston

unread,
Oct 6, 2015, 6:33:50 PM10/6/15
to Node-RED
Thanks Dave, that's quite useful - for some reason the concept of looping back like that hadn't occurred to me. 

Cheers
Richard

myIoT

unread,
Oct 6, 2015, 7:53:33 PM10/6/15
to Node-RED
Perfect Dave. It just works.. Your idea of having an in-memory queue saved my day. 

Thanks
EK

myIoT

unread,
Oct 6, 2015, 8:00:18 PM10/6/15
to Node-RED
Hi Richard,

Print msg is part of other orchestration. I wanted to do everything in Node, but my thermal printer was not happy with npm printer library. So went with python lib to do the printing job alone.

Thanks.

Walter Kraembring

unread,
Oct 7, 2015, 12:36:54 AM10/7/15
to Node-RED
@ Dave,
Very elegant & useful, a candidate for a new 'queue' node or adding this feature to the delay node?

BR Walter

Dave C-J

unread,
Oct 10, 2015, 12:32:57 PM10/10/15
to node...@googlegroups.com
Walter,
I've added it as an example here

It probably need more thought before making into a node - as there are many possible behaviours that could be considered. For example in this case we let through the first message in order to start the queue running... but you may only want to let them through on a trigger. And there are probably edge cases I've missed :-) 

But always happy to discuss ideas and see what is generalisable...
Reply all
Reply to author
Forward
0 new messages