Configure TRIGGER node in a variable way to activate digital pin

Hello everyone, I am new to the community, I ask for your help.

I want to do a basic PH control: Phosphoric acid is dosed to lower it.

  • I check if the PH is in the required range (5-6).
  • If it is above:
    I calculate the difference.

The flow that I export corresponds to the function that calculates the proportion of acid to be dosed, this determined for 5 liters of water, at the exit I have a switch that depending on the value activates a metering motor for an average time, this engine is connected to a Arduino Nano, which has the Scketch StandardFirmata.ino loaded to control the digital pin.

So far things are going well, but that is in a tank that varies the level of water, between 5 liters to 50 liters of water, so I must determine the proportion for different quantities, and therefore I will have different proportions of acid to supply , I have the tank level with an ultrasound sensor.

For that I will have to do another function that takes the value of the tank level and calculate the proportion of acid for that amount of water, the problem is then:

How to modify the TRIGGER node, or what can I do to activate the arduino digital pin for 0.4s and maybe 10 seconds, in a variable way? without making many fixed TRIGGER.

The flow I made is not complex but it is how I managed to do that process.

Thank you for the help you can give me.

[{"id":"dc28a699.939808","type":"tab","label":"Flow 16","disabled":false,"info":""},{"id":"3b7a292b.426436","type":"function","z":"dc28a699.939808","name":"PH Control - dosing amount","func":"//variables de cantidad\n\nvar x = msg.payload;\nvar acid = 0.24;\nvar PH_modify = 0.3;\nvar msg1 = {};\nmsg1.payload = 0;\n\nvar time = 0.2; \nmsg1.payload = (acid * (x + 0.3))/ PH_modify; \n\nreturn [msg, msg1];\n\n","outputs":2,"noerr":0,"x":301.1906280517578,"y":262.1429557800293,"wires":[[],["82405b97.2a82a8","7046eb93.894434"]]},{"id":"82405b97.2a82a8","type":"debug","z":"dc28a699.939808","name":"PH OUT4","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":508.57167053222656,"y":333.57150650024414,"wires":[]},{"id":"7046eb93.894434","type":"switch","z":"dc28a699.939808","name":"How long to turn on?","property":"payload","propertyType":"msg","rules":[{"t":"btwn","v":"0.32","vt":"num","v2":"0.56","v2t":"num"},{"t":"btwn","v":"0.64","vt":"num","v2":"0.88","v2t":"num"},{"t":"btwn","v":"0.96","vt":"num","v2":"1.2","v2t":"num"},{"t":"btwn","v":"1.28","vt":"num","v2":"1.52","v2t":"num"},{"t":"btwn","v":"1.6","vt":"num","v2":"1.92","v2t":"num"}],"checkall":"true","repair":false,"outputs":5,"x":635.2382125854492,"y":254.04783248901367,"wires":[["aa2ab6b0.aed498"],["529dc11a.5579d"],["39751a3f.de4106"],["5a58ea64.05b084"],["7c7ff43f.27ebcc"]]},{"id":"aa2ab6b0.aed498","type":"trigger","z":"dc28a699.939808","op1":"1","op2":"0","op1type":"str","op2type":"str","duration":"0.44","extend":false,"units":"s","reset":"","bytopic":"all","name":"","x":949.5240097045898,"y":157.14295196533203,"wires":[["7463135c.a9e3ac","486d56dd.4c49b8"]]},{"id":"7463135c.a9e3ac","type":"rpi-gpio out","z":"dc28a699.939808","name":"Fan","pin":"11","set":true,"level":"0","freq":"","out":"out","x":1274.2860679626465,"y":149.04774475097656,"wires":[]},{"id":"529dc11a.5579d","type":"trigger","z":"dc28a699.939808","op1":"1","op2":"0","op1type":"str","op2type":"str","duration":"0.76","extend":false,"units":"s","reset":"","bytopic":"all","name":"","x":954.5238952636719,"y":200.47624397277832,"wires":[["7463135c.a9e3ac","486d56dd.4c49b8"]]},{"id":"39751a3f.de4106","type":"trigger","z":"dc28a699.939808","op1":"1","op2":"0","op1type":"str","op2type":"str","duration":"1.08","extend":false,"units":"s","reset":"","bytopic":"all","name":"","x":957.8571472167969,"y":243.80961799621582,"wires":[["7463135c.a9e3ac","486d56dd.4c49b8"]]},{"id":"5a58ea64.05b084","type":"trigger","z":"dc28a699.939808","op1":"1","op2":"0","op1type":"str","op2type":"str","duration":"1.4","extend":false,"units":"s","reset":"","bytopic":"all","name":"","x":957.8571472167969,"y":287.14293098449707,"wires":[["7463135c.a9e3ac","486d56dd.4c49b8"]]},{"id":"7c7ff43f.27ebcc","type":"trigger","z":"dc28a699.939808","op1":"1","op2":"0","op1type":"str","op2type":"str","duration":"1.76","extend":false,"units":"s","reset":"","bytopic":"all","name":"","x":957.8571472167969,"y":333.80955696105957,"wires":[["7463135c.a9e3ac","486d56dd.4c49b8"]]},{"id":"486d56dd.4c49b8","type":"function","z":"dc28a699.939808","name":"Toggle output on input","func":"\n// If it does exist make it the inverse of what it was or else initialise it to false\n// (context variables persist between calls to the function)\ncontext.level = !context.level || false;\n\n// set the payload to the level and return\nmsg.payload = context.level;\nreturn msg;","outputs":1,"noerr":0,"x":1300.8334922790527,"y":355.7144012451172,"wires":[["3c28c211.38cd0e"]]},{"id":"3c28c211.38cd0e","type":"arduino out","z":"dc28a699.939808","name":"","pin":"16","state":"OUTPUT","arduino":"31cddcf7.280c54","x":1510.8333625793457,"y":355.58343410491943,"wires":[]},{"id":"31cddcf7.280c54","type":"arduino-board","z":"","device":"/dev/ttyUSB0"}]

The trigger cannot be set programmatically.

Different approach:

[{"id":"61e094db.ba769c","type":"function","z":"6145a19b.92b9a","name":"","func":"i = msg.payload\n\ntime = [[0.32,0.56],[0.64,0.88]]\ntriggertime = [0.44,0.76]\n\nfor(x=0;x<time.length;x++){\n    \n    if(i >= time[x][0] && i<= time[x][1]){\n        \n        node.send({payload:1})\n        \n        setTimeout(function(){\n            node.send({payload:0})\n        },triggertime[x]*100)\n    }\n    \n}","outputs":1,"noerr":0,"x":625,"y":675,"wires":[["d760b91.0e183c8"]]},{"id":"e226129b.1fcf58","type":"inject","z":"6145a19b.92b9a","name":"","topic":"","payload":"0.45","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":400,"y":650,"wires":[["61e094db.ba769c"]]},{"id":"d760b91.0e183c8","type":"debug","z":"6145a19b.92b9a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":805,"y":675,"wires":[]},{"id":"7ba7b02c.681ff8","type":"inject","z":"6145a19b.92b9a","name":"","topic":"","payload":"0.76","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":400,"y":700,"wires":[["61e094db.ba769c"]]}]
1 Like

You could use a delay node to do similar though...

[{"id":"e7fa8d8a.806a2","type":"inject","z":"dfa1c83b.a5fa68","name":"","topic":"","payload":"10","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":40,"wires":[["7762da53.9e78e4"]]},{"id":"7762da53.9e78e4","type":"function","z":"dfa1c83b.a5fa68","name":"PH Control - dosing amount","func":"//variables de cantidad\n\nvar x = msg.payload;\nvar acid = 0.24;\nvar PH_modify = 0.3;\nvar msg1 = {};\nmsg1.payload = 0;\n\nvar time = 0.2; \nmsg1.payload = (acid * (x + 0.3))/ PH_modify * 1000; \n\nreturn [msg, msg1];\n\n","outputs":2,"noerr":0,"x":260,"y":100,"wires":[[],["57853e7.a0cc6c","42f63877.7b8c08","638d62c7.34805c"]]},{"id":"57853e7.a0cc6c","type":"debug","z":"dfa1c83b.a5fa68","name":"PH OUT4","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":500,"y":40,"wires":[]},{"id":"42f63877.7b8c08","type":"change","z":"dfa1c83b.a5fa68","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"1","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":100,"wires":[["50348305.1e408c"]]},{"id":"638d62c7.34805c","type":"change","z":"dfa1c83b.a5fa68","name":"","rules":[{"t":"set","p":"delay","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":440,"y":160,"wires":[["b8951281.9b068"]]},{"id":"50348305.1e408c","type":"rpi-gpio out","z":"dfa1c83b.a5fa68","name":"Fan","pin":"11","set":true,"level":"0","freq":"","out":"out","x":890,"y":120,"wires":[]},{"id":"b8951281.9b068","type":"delay","z":"dfa1c83b.a5fa68","name":"","pauseType":"delayv","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":480,"y":220,"wires":[["704021b7.1914a"]]},{"id":"704021b7.1914a","type":"change","z":"dfa1c83b.a5fa68","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":680,"y":220,"wires":[["50348305.1e408c"]]}]
1 Like

I expect that you are aware of this, but I would certainly be cautious about trying to control chemical processes in realtime using Node-RED.

At the very least, you should build some leaway into your Arduino code if you can to cater for the fact that Node-RED uses Node.js which is JavaScript which is largely single-threaded. Which is a long-winded way of saying that its realtime capability can be rather limited and challenging.

For example, Node.js uses a process called "garbage collection" to recover memory that was used but isn't needed any more. In some cases, this can take a considerable length of time (compared to other compute activities) and can completely or largely stop other code while it is happening. If you were unlucky enough to have this happen at a critical moment in your process, it could have nasty consequences.

In reality, using Arduino code is better since that is a realtime environment. Obviously though it is more complex to program. If you need to get really clever and need a more featurefull realtime OS, the ESP32 is a great platform since you can still program it via the Arduino IDE but it has a full realtime OS on-board & can do interupt-driven routines (e.g. a pin change can automatically trigger a process).

2 Likes

Thank you for the help provided and for the suggestions and observations.