Tuesday, December 19, 2017

An updated game for testing the dashboard

Some time ago I did a  Node_RED flow just for learning how to use Freeboard Dashboard (click here for the link)

I stopped using Freeboard since NodeRED team incorporated dashboard nodes to the core of Node-RED.


I decided then to update that game ,also for learning purposes.


Here is how the dashboard looks like while the game is running:




This is how the flow looks like:




Flow:

[{"id":"8b9c16c1.9d2c78","type":"inject","z":"ab22dba5.2bb948","name":"Fire","topic":"none","payload":"fire","payloadType":"str","repeat":"","crontab":"","once":false,"x":240,"y":411.0000171661377,"wires":[["90f89153.24b3e"]]},{"id":"2099b281.cc909e","type":"function","z":"ab22dba5.2bb948","name":"Random","func":"msg.value1=Math.floor(Math.random()*100);\nmsg.value2=Math.floor(Math.random()*100);\nmsg.light1=0;\nmsg.light2=0;\nmsg.light3=0;\n\nmsg.runs +=1;\nif (msg.value1>msg.value2) {\n    msg.win1+=1\n    msg.light1=1;\n    msg.light2=0;\n}else if (msg.value2>msg.value1) {\n    msg.win2+=1;\n    msg.light1=0;\n    msg.light2=1;\n}else {\n    msg.light1=1;\n    msg.light2=1;\n    msg.light3=1;\n    msg.stop = true;\n    if (msg.win1 > msg.win2) {\n        msg.winner = \"Player 1\";\n    } else if (msg.win2 > msg.win1) {\n            msg.winner = \"Player 2\";\n        } else {\n            msg.winner = \"It is a draw ! !\";\n        }\n    }\n\n\nreturn msg;","outputs":1,"noerr":0,"x":412.00001525878906,"y":318.0000114440918,"wires":[["f41892a5.e7945","29835b6a.459594","28416391.e7b69c"]]},{"id":"29835b6a.459594","type":"function","z":"ab22dba5.2bb948","name":"Test Stop","func":"\nif (msg.stop) {\n    \n    return null;  \n} else {return msg;}\n\nif (msg.start) {\n    return msg;\n}\n\n","outputs":1,"noerr":0,"x":550,"y":411.0000171661377,"wires":[["68f31cc0.517654"]]},{"id":"68f31cc0.517654","type":"delay","z":"ab22dba5.2bb948","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":252.00001525878906,"y":318.0000114440918,"wires":[["2099b281.cc909e"]]},{"id":"90f89153.24b3e","type":"function","z":"ab22dba5.2bb948","name":"Start","func":"msg.start = true;\nmsg.stop = false;\n\nif (msg.start) {\n    msg.value1=0;\n    msg.value2=0;\n    msg.light1=0;\n    msg.light2=0;\n    msg.light3=0;\n    msg.win1=0;\n    msg.win2=0;\n    msg.runs=0;\n    msg.winner=\"open game\";\n    msg.start=false;\n}\nreturn msg;\n","outputs":1,"noerr":0,"x":380,"y":411.0000171661377,"wires":[["29835b6a.459594","ef05496a.38a308"]]},{"id":"f41892a5.e7945","type":"debug","z":"ab22dba5.2bb948","name":"","active":true,"console":"false","complete":"true","x":582.0000152587891,"y":318.0000114440918,"wires":[]},{"id":"28416391.e7b69c","type":"function","z":"ab22dba5.2bb948","name":"Format Dashboard","func":"var msg1={payload:msg.value1};\nvar msg2={payload:msg.value2};\nvar msg3={payload:msg.runs};\nvar msg4={payload:msg.win1};\nvar msg5={payload:msg.win2};\nvar msg6={payload:msg.winner};\nreturn [msg1, msg2, msg3, msg4, msg5, msg6];","outputs":"6","noerr":0,"x":350,"y":120,"wires":[["f19a4aae.e10238"],["5f728cb7.96f5b4"],["66a9bc7c.0a63e4"],["7a6e1f5f.f64fe"],["456203cc.1a91dc"],["1ca0211e.906b1f"]]},{"id":"f19a4aae.e10238","type":"ui_gauge","z":"ab22dba5.2bb948","name":"","group":"d3e8886d.948888","order":1,"width":0,"height":0,"gtype":"donut","title":"Player 1","label":"","format":"{{value}}","min":0,"max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":560,"y":60,"wires":[]},{"id":"5f728cb7.96f5b4","type":"ui_gauge","z":"ab22dba5.2bb948","name":"","group":"d3e8886d.948888","order":2,"width":0,"height":0,"gtype":"donut","title":"Player 2","label":"","format":"{{value}}","min":0,"max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":560,"y":100,"wires":[]},{"id":"66a9bc7c.0a63e4","type":"ui_text","z":"ab22dba5.2bb948","group":"d3e8886d.948888","order":3,"width":"3","height":"1","name":"","label":"RUNS","format":"{{msg.payload}}","layout":"row-spread","x":550,"y":140,"wires":[]},{"id":"7a6e1f5f.f64fe","type":"ui_text","z":"ab22dba5.2bb948","group":"d3e8886d.948888","order":4,"width":0,"height":0,"name":"","label":"Wins Player 1","format":"{{msg.payload}}","layout":"row-spread","x":580,"y":180,"wires":[]},{"id":"456203cc.1a91dc","type":"ui_text","z":"ab22dba5.2bb948","group":"d3e8886d.948888","order":5,"width":0,"height":0,"name":"","label":"Wins Player 2","format":"{{msg.payload}}","layout":"row-spread","x":580,"y":220,"wires":[]},{"id":"1ca0211e.906b1f","type":"ui_text","z":"ab22dba5.2bb948","group":"d3e8886d.948888","order":5,"width":0,"height":0,"name":"","label":"The Winner is...","format":"{{msg.payload}}","layout":"row-spread","x":580,"y":260,"wires":[]},{"id":"ef05496a.38a308","type":"debug","z":"ab22dba5.2bb948","name":"","active":true,"console":"false","complete":"true","x":518.1000061035156,"y":493.0000171661377,"wires":[]},{"id":"d3e8886d.948888","type":"ui_group","z":"","name":"Button1","tab":"4ce637e8.4ba768","disp":true,"width":"6"},{"id":"4ce637e8.4ba768","type":"ui_tab","z":"","name":"Button Panel","icon":"dashboard"}]

The three relay problem


This was a request for help posted in the Node-RED group.


The requirements:

Use Node-RED to control three remote relays via MQTT.
Once the first relay is activated (by sending an ON command via MQTT) it should remain active for 5 minutes. When it turns off the second should start and run for 5 minutes, when it stops the third should start and run 5 min when it stops it should start the first one again and continue looping in such way until an OFF command is triggered.



Proposed Solution:

It was implemented a cycling engine, inside a function node, that "rotates" the desired outputs to the relays. The very first run will command all three relays OFF (without delays). I used a variable in the global context to store the user command to stop the flow. There is an inject node to stop the flow. It will stop immediately after the execution of the ongoing delay (which was configured for 15 seconds to speed up the flow - it should be changed to 5 minutes to comply with the requirements). The way the flow was written facilitates to change the logic if there are any changes in the requirements (more relays or relays being activated in a different sequence, for instance).






Flow:



[{"id":"f98def0.4f2101","type":"function","z":"108c9253.cb4bfe","name":"Cycle","func":"if (msg.firstRun || msg.lastRun) {\n    msg.payload1=\"OFF\"; \n    msg.payload2=\"OFF\"; \n    msg.payload3=\"OFF\";\n    if (msg.firstRun) msg.firstRun=false;\n    \n} else \n    \n\nswitch (msg.cycle) {\n    \n   \n        \n    case 1:\n        msg.payload1=\"ON\"; \n        msg.payload2=\"OFF\"; \n        msg.payload3=\"OFF\";\n        msg.cycle=2;\n        break;\n    case 2:\n        msg.payload1=\"OFF\"; \n        msg.payload2=\"ON\"; \n        msg.payload3=\"OFF\";\n        msg.cycle=3;\n        break;  \n        \n    case 3:\n        msg.payload1=\"OFF\"; \n        msg.payload2=\"OFF\"; \n        msg.payload3=\"ON\";\n        msg.cycle=1;\n        break;\n        \n}\n\n\n   \n    msg1={topic:msg.topic1, payload:msg.payload1};\n    msg2={topic:msg.topic2, payload:msg.payload2};\n    msg3={topic:msg.topic3, payload:msg.payload3}; \n    \n    \n    return [[msg1, msg2, msg3], msg];\n    \n\n\n\n\n\n\n","outputs":"2","noerr":0,"x":544,"y":169.00001430511475,"wires":[["6897db12.4f3d34"],["cb723b20.0ecee8","9019f171.0794a"]]},{"id":"4b6261af.a6b63","type":"function","z":"108c9253.cb4bfe","name":"Initialize","func":"    \n    global.set(\"keepWalking\",true);\n    msg.keepWalking = global.get(\"keepWalking\");\n    \n    msg.cycle = 1;\n    msg.firstRun = true;\n    msg.lastRun = false;\n    msg.topic1 = \"cmnd/kb1/power1\";\n    msg.topic2 = \"cmnd/kb1/power2\";\n    msg.topic3 = \"cmnd/kb1/power3\";\n    \n    msg.payload1 = \"OFF\";\n    msg.payload2 = \"OFF\";\n    msg.payload3 = \"OFF\";\n\nreturn msg;","outputs":1,"noerr":0,"x":379.9999580383301,"y":169.00003814697266,"wires":[["f98def0.4f2101"]]},{"id":"cb723b20.0ecee8","type":"debug","z":"108c9253.cb4bfe","name":"Debug only","active":true,"console":"false","complete":"true","x":744.1001205444336,"y":174.00003051757812,"wires":[]},{"id":"d7233232.fb09b","type":"delay","z":"108c9253.cb4bfe","name":"","pauseType":"delay","timeout":"15","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":579.1000709533691,"y":308.0000171661377,"wires":[["f98def0.4f2101"]]},{"id":"21c221de.0190de","type":"inject","z":"108c9253.cb4bfe","name":"Switch ON","topic":"","payload":"SON","payloadType":"str","repeat":"","crontab":"","once":false,"x":219.99996185302734,"y":170.00003719329834,"wires":[["4b6261af.a6b63"]]},{"id":"9019f171.0794a","type":"function","z":"108c9253.cb4bfe","name":"Test Stop","func":"// keepWalking: false, lastRun: false=> cycle last time\n// keepWalking: false, lastRun: true => end flow\n\n// keepWalking: true => just return msg\n//\n//\n\nif (!global.get(\"keepWalking\")) {\n    if (!msg.lastRun) {\n        msg.lastRun=true;\n        node.warn(\"Commanding Relays off...\");\n        return msg;\n    } else {\n        node.warn(\"Relays confirmed OFF\");\n        return null;}\n    \n} else {return msg;}\n","outputs":1,"noerr":0,"x":429.0999698638916,"y":308.000018119812,"wires":[["d7233232.fb09b"]]},{"id":"f7ab90b3.cf35f","type":"inject","z":"108c9253.cb4bfe","name":"Switch OFF","topic":"SOFF","payload":"","payloadType":"str","repeat":"","crontab":"","once":false,"x":345.09996795654297,"y":396.00002002716064,"wires":[["78a8b3e0.63e5fc"]]},{"id":"78a8b3e0.63e5fc","type":"function","z":"108c9253.cb4bfe","name":"Command Stop","func":"global.set(\"keepWalking\",false);\nmsg.keepWalking = global.get(\"keepWalking\");\nreturn msg;","outputs":1,"noerr":0,"x":540.0999717712402,"y":397.00002002716064,"wires":[[]]},{"id":"6897db12.4f3d34","type":"mqtt out","z":"108c9253.cb4bfe","name":"","topic":"","qos":"2","retain":"false","broker":"752751ba.451be","x":734.1000061035156,"y":104,"wires":[]},{"id":"752751ba.451be","type":"mqtt-broker","z":"","broker":"broker.mqttdashboard.com","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""}]