Help - mux2to1 logic using functions

Hello to everyone,
i have zero node-red and javascript experience. I want to choose between the output of 2 nodes. The selection will depend on the output of a third node.
I have a "solenoid valve switch" node and a "scheduler" node and i want to choose only one of those outputs to feed the rest of my flow.

i didn't find any build-in node to do it and I tried with functions.
Any help would be appreciated,
Thank you

[{"id":"fdfdb59a.dbf3f8","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"c4532bc.d3616d8","type":"file","z":"fdfdb59a.dbf3f8","name":"WriteFile","filename":"/data/time-schedule.txt","appendNewline":true,"createDir":true,"overwriteFile":"true","encoding":"none","x":340,"y":120,"wires":[[]]},{"id":"2d230dba.0ac172","type":"inject","z":"fdfdb59a.dbf3f8","name":"FireAfterReboot","props":[{"p":"payload","v":"","vt":"date"},{"p":"topic","v":"","vt":"string"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":120,"y":120,"wires":[["fa4881b6.63139"]]},{"id":"fa4881b6.63139","type":"file in","z":"fdfdb59a.dbf3f8","name":"ReadFile","filename":"/data/time-schedule.txt","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":120,"y":200,"wires":[["aaba4afb.f8a0a8"]]},{"id":"aaba4afb.f8a0a8","type":"ui_time_scheduler","z":"fdfdb59a.dbf3f8","group":"671f39c6.6d0858","name":"","startDay":"0","refresh":60,"devices":["Valve 1","Valve 2","Valve 3"],"customPayload":false,"eventMode":false,"sendTopic":false,"outputs":4,"order":8,"width":0,"height":0,"x":290,"y":200,"wires":[["c4532bc.d3616d8"],["b50bbad8.776ff8"],[],[]]},{"id":"dda2ebb.43c1118","type":"ui_template","z":"fdfdb59a.dbf3f8","group":"","name":"Clock Toolbar","order":2,"width":"0","height":"0","format":"<script id=\"titleScript\" type=\"text/javascript\">\n\n$(function() {\n    if($('.md-toolbar-tools').length != 0){\n        loadClock();\n    }else setTimeout(loadClock, 500)\n});\n\nfunction loadClock(){\n    $('#clock').remove();\n    var toolbar = $('.md-toolbar-tools');\n    \n    var div = $('<div/>');\n    var p = $('<p/ id=\"clock\">');\n    \n    div.append(p);\n    div[0].style.margin = '5px 5px 5px auto';\n    toolbar.append(div);\n\n    function displayTitle(lh) {\n        p.text(lh); \n    }\n    \n    function upTime() {\n        var d = new Date();\n        p.text(d.toLocaleString());\n    }\n\n    if(document.clockInterval){ \n            clearInterval(document.clockInterval);\n            document.clockInterval = null;\n    }\n        \n    document.clockInterval = setInterval(upTime,1000);\n}\n\n</script>","storeOutMessages":false,"fwdInMessages":false,"templateScope":"global","x":120,"y":40,"wires":[[]]},{"id":"8b90ee5a.56226","type":"ui_switch","z":"fdfdb59a.dbf3f8","name":"Solenoid Valve 1","label":"Solenoid Valve 1","tooltip":"","group":"671f39c6.6d0858","order":4,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"garden/node2/gpio2","style":"","onvalue":"1","onvalueType":"str","onicon":"","oncolor":"","offvalue":"0","offvalueType":"str","officon":"","offcolor":"","x":470,"y":280,"wires":[["af43250.73801d8"]]},{"id":"1042ad1f.5e3d03","type":"mqtt out","z":"fdfdb59a.dbf3f8","name":"Valve 1","topic":"garden/node2/gpio2","qos":"","retain":"","broker":"681b9d99.717f94","x":680,"y":480,"wires":[]},{"id":"f0f3dde8.b78f2","type":"mqtt in","z":"fdfdb59a.dbf3f8","name":"Valve 1 status","topic":"garden/node2/gpio2_stat","qos":"2","datatype":"auto","broker":"681b9d99.717f94","x":90,"y":600,"wires":[["14fd21e9.8345ce","cde0ca54.0ea7d8"]]},{"id":"14fd21e9.8345ce","type":"debug","z":"fdfdb59a.dbf3f8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":290,"y":640,"wires":[]},{"id":"cde0ca54.0ea7d8","type":"ui_text","z":"fdfdb59a.dbf3f8","group":"671f39c6.6d0858","order":6,"width":0,"height":0,"name":"Valve Current value","label":"Valve Current value","format":"{{msg.payload}}","layout":"row-center","x":310,"y":600,"wires":[]},{"id":"b50bbad8.776ff8","type":"change","z":"fdfdb59a.dbf3f8","name":"convert","rules":[{"t":"change","p":"payload","pt":"msg","from":"true","fromt":"bool","to":"1","tot":"str"},{"t":"change","p":"payload","pt":"msg","from":"false","fromt":"bool","to":"0","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":500,"y":180,"wires":[["b90d2e12.6f9bf"]]},{"id":"19ceb6c3.322569","type":"function","z":"fdfdb59a.dbf3f8","name":"Status of Switch","func":"global.set(\"Switch\",msg.payload);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":260,"y":420,"wires":[["1f578815.977fd8"]]},{"id":"cf5894c7.6c44d8","type":"ui_switch","z":"fdfdb59a.dbf3f8","name":"Switch","label":"Switch (Manual/Scheduler)","tooltip":"","group":"671f39c6.6d0858","order":1,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"1","onvalueType":"str","onicon":"","oncolor":"","offvalue":"0","offvalueType":"str","officon":"","offcolor":"","x":70,"y":420,"wires":[["19ceb6c3.322569"]]},{"id":"b90d2e12.6f9bf","type":"function","z":"fdfdb59a.dbf3f8","name":"Status of Scheduler","func":"global.set(\"Scheduler_stat\",msg.payload);\nreturn msg;\n\n\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":690,"y":180,"wires":[["e2f0e39f.10446"]]},{"id":"af43250.73801d8","type":"function","z":"fdfdb59a.dbf3f8","name":"Status of Valve 1","func":"global.set(\"SV1_stat\",msg.payload);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":690,"y":280,"wires":[["36cb5147.c7d2be"]]},{"id":"36cb5147.c7d2be","type":"debug","z":"fdfdb59a.dbf3f8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":710,"y":340,"wires":[]},{"id":"e2f0e39f.10446","type":"debug","z":"fdfdb59a.dbf3f8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":710,"y":120,"wires":[]},{"id":"da53790d.37b8d8","type":"debug","z":"fdfdb59a.dbf3f8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":690,"y":440,"wires":[]},{"id":"1f578815.977fd8","type":"debug","z":"fdfdb59a.dbf3f8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":250,"y":480,"wires":[]},{"id":"f4444809.61b3a8","type":"function","z":"fdfdb59a.dbf3f8","name":"Valve 1 control","func":"var switchstatus=global.get(\"Switch\");\nvar scheduler=global.get(\"Scheduler_stat\");\nvar SV1=global.get(\"SV1_stat\");\n\nif(switchstatus==\"1\")\n{\n    msg.payload = \"SV1\";\n}\nelse if(switchstatus==\"0\")\n{\n    msg.payload = \"scheduler\";\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":500,"y":440,"wires":[["1042ad1f.5e3d03","da53790d.37b8d8"]]},{"id":"31babaa1.3cffe6","type":"function","z":"fdfdb59a.dbf3f8","d":true,"name":"Valve 1 control test","func":"if (context.get(\"Switch\") == \"1\")\n{\n    msg.payload = \"1\";\n}\nelse if (context.get(\"Switch\") == \"0\")\n{\n    msg.payload = \"0\";\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":490,"y":480,"wires":[["1042ad1f.5e3d03","da53790d.37b8d8"]]},{"id":"671f39c6.6d0858","type":"ui_group","name":"Garden","tab":"a8281535.325108","order":1,"disp":true,"width":"6","collapse":false},{"id":"681b9d99.717f94","type":"mqtt-broker","name":"localhost","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"a8281535.325108","type":"ui_tab","name":"Garden","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

You could do this by adding two node-red-contrib-simple-gates into the outputs from the input nodes. Then use the signal from the control node to open one of these and close the other, as appropriate.

1 Like

@Colin thank you very much!!! I followed your instructions and it works as i wanted.
Can you recommend any simple to understand node-red cookbook for noob to more expert? more preferred with examples.
Did you take a look at the code in my functions? What was my error? Is there any IDE for code debuging?
Thank you again!!!

[{"id":"9149f75b.09c238","type":"tab","label":"Flow 5","disabled":false,"info":""},{"id":"5f29d56e.ce332c","type":"file","z":"9149f75b.09c238","name":"WriteFile","filename":"/data/time-schedule.txt","appendNewline":true,"createDir":true,"overwriteFile":"true","encoding":"none","x":320,"y":200,"wires":[[]]},{"id":"3565d3f6.d5c7ec","type":"inject","z":"9149f75b.09c238","name":"FireAfterReboot","props":[{"p":"payload","v":"","vt":"date"},{"p":"topic","v":"","vt":"string"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":100,"y":200,"wires":[["d0b1dd76.2b2ba"]]},{"id":"d0b1dd76.2b2ba","type":"file in","z":"9149f75b.09c238","name":"ReadFile","filename":"/data/time-schedule.txt","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":100,"y":280,"wires":[["b1cbe8a8.8d5df8"]]},{"id":"b1cbe8a8.8d5df8","type":"ui_time_scheduler","z":"9149f75b.09c238","group":"671f39c6.6d0858","name":"","startDay":"0","refresh":60,"devices":["Valve 1","Valve 2","Valve 3"],"customPayload":false,"eventMode":false,"sendTopic":false,"outputs":4,"order":8,"width":0,"height":0,"x":270,"y":280,"wires":[["5f29d56e.ce332c"],["8897a60e.c04058"],[],[]]},{"id":"c296d148.17114","type":"ui_template","z":"9149f75b.09c238","group":"","name":"Clock Toolbar","order":2,"width":"0","height":"0","format":"<script id=\"titleScript\" type=\"text/javascript\">\n\n$(function() {\n    if($('.md-toolbar-tools').length != 0){\n        loadClock();\n    }else setTimeout(loadClock, 500)\n});\n\nfunction loadClock(){\n    $('#clock').remove();\n    var toolbar = $('.md-toolbar-tools');\n    \n    var div = $('<div/>');\n    var p = $('<p/ id=\"clock\">');\n    \n    div.append(p);\n    div[0].style.margin = '5px 5px 5px auto';\n    toolbar.append(div);\n\n    function displayTitle(lh) {\n        p.text(lh); \n    }\n    \n    function upTime() {\n        var d = new Date();\n        p.text(d.toLocaleString());\n    }\n\n    if(document.clockInterval){ \n            clearInterval(document.clockInterval);\n            document.clockInterval = null;\n    }\n        \n    document.clockInterval = setInterval(upTime,1000);\n}\n\n</script>","storeOutMessages":false,"fwdInMessages":false,"templateScope":"global","x":100,"y":120,"wires":[[]]},{"id":"18f8c6d8.329479","type":"ui_switch","z":"9149f75b.09c238","name":"Solenoid Valve 1","label":"Solenoid Valve 1","tooltip":"","group":"671f39c6.6d0858","order":4,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"garden/node2/gpio2","style":"","onvalue":"1","onvalueType":"str","onicon":"","oncolor":"","offvalue":"0","offvalueType":"str","officon":"","offcolor":"","x":430,"y":380,"wires":[["ba2fcb02.4deb98"]]},{"id":"35229b5e.6eef24","type":"mqtt in","z":"9149f75b.09c238","name":"Valve 1 status","topic":"garden/node2/gpio2_stat","qos":"2","datatype":"auto","broker":"681b9d99.717f94","x":230,"y":500,"wires":[["e82d1cbc.275b7","679e9175.bb51c"]]},{"id":"e82d1cbc.275b7","type":"debug","z":"9149f75b.09c238","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":430,"y":540,"wires":[]},{"id":"679e9175.bb51c","type":"ui_text","z":"9149f75b.09c238","group":"671f39c6.6d0858","order":6,"width":0,"height":0,"name":"Valve Current value","label":"Valve Current value","format":"{{msg.payload}}","layout":"row-center","x":450,"y":500,"wires":[]},{"id":"8897a60e.c04058","type":"change","z":"9149f75b.09c238","name":"convert","rules":[{"t":"change","p":"payload","pt":"msg","from":"true","fromt":"bool","to":"1","tot":"str"},{"t":"change","p":"payload","pt":"msg","from":"false","fromt":"bool","to":"0","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":460,"y":260,"wires":[["a09df2ad.064cc"]]},{"id":"830818b3.49bc08","type":"mqtt out","z":"9149f75b.09c238","name":"Valve 1","topic":"garden/node2/gpio2","qos":"","retain":"","broker":"681b9d99.717f94","x":840,"y":320,"wires":[]},{"id":"9d7a922b.424c4","type":"debug","z":"9149f75b.09c238","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":790,"y":200,"wires":[]},{"id":"a09df2ad.064cc","type":"gate","z":"9149f75b.09c238","name":"gate scheduler","controlTopic":"control","defaultState":"closed","openCmd":"close","closeCmd":"open","toggleCmd":"toggle","defaultCmd":"default","statusCmd":"status","persist":true,"x":700,"y":260,"wires":[["830818b3.49bc08","9d7a922b.424c4"]]},{"id":"3d5d35c9.79949a","type":"ui_switch","z":"9149f75b.09c238","name":"Switch","label":"Switch (Manual/Scheduler)","tooltip":"","group":"671f39c6.6d0858","order":1,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"control","style":"","onvalue":"open","onvalueType":"str","onicon":"","oncolor":"","offvalue":"close","offvalueType":"str","officon":"","offcolor":"","x":490,"y":320,"wires":[["a09df2ad.064cc","ba2fcb02.4deb98"]]},{"id":"ba2fcb02.4deb98","type":"gate","z":"9149f75b.09c238","name":"gate SV1","controlTopic":"control","defaultState":"open","openCmd":"open","closeCmd":"close","toggleCmd":"toggle","defaultCmd":"default","statusCmd":"status","persist":true,"x":680,"y":380,"wires":[["830818b3.49bc08","c8c95672.758c28"]]},{"id":"c8c95672.758c28","type":"debug","z":"9149f75b.09c238","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":810,"y":440,"wires":[]},{"id":"671f39c6.6d0858","type":"ui_group","name":"Garden","tab":"a8281535.325108","order":1,"disp":true,"width":"6","collapse":false},{"id":"681b9d99.717f94","type":"mqtt-broker","name":"localhost","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"a8281535.325108","type":"ui_tab","name":"Garden","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

Your Valve 1 control function node has nothing connected to its input. Function nodes only do anything when they receive a message, so the function node will never do anything. I find it best to avoid global and flow context because it can become difficult to follow the flow (which you can see comparing the two methods) but also because of problems such as the one you found. If you want something to happen when a context value changes then you have to poll it.
In fact there is another method, which is probably the one I would use, which is to use a Join node to combine the messages from the three inputs into one message so that logic such as in your function can be performed. The example in the cookbook on Joining Streams is an example of how to do that.

To improve your knowledge I recommend watching this playlist: Node-RED Essentials. The videos are done by the developers of node-red. They're nice & short and to the point. You will understand a whole lot more in about 1 hour. A small investment for a lot of gain.

Then work your way through the examples in the node red cookbook and play with the ones that you find interesting.

Finally lurking here is a great way to learn, it is the main way that I use to learn new stuff about node red. In no time you will find yourself helping others, at least in the particular areas that interests you.

1 Like

i thought i can just call global variables in a function without connecting the variable's nodes to the function node. Thank you for making it clear. I did it as you say and it works.

I understand that it can become messy and difficult to follow the flow.

Thank you for the tip with joining messages.
As i understood join node will create msg objects and in the function side i'll use the object property "topic" as the key world in the conditions.
What confuse me is how i'll call the objects and their properties. For example, how can i call the msg.payload of the combined object with topic == "topic_name"?
I'll work with the node-red examples and watch the videos you recommended.
Thank you once again for the help!!!

Import the Join example in the cookbook and test it to understand how it works. The payloads of all the input messages are available in the join node output. So to answer your question

The payload of the input message with topic "topic_name" will be in msg.payload.topic_name
Also you can tell which was the last message received as the topic of the output message will be that of the last input message (as will everything else in the output message).

1 Like