# My effort at remote shutdown for ras-pi's

**URL:** <https://discourse.nodered.org/t/my-effort-at-remote-shutdown-for-ras-pis/18926>\
**Category:** Share Your Projects\
**Created:** [8 December 2019 20:28 UTC](https://discourse.nodered.org/t/my-effort-at-remote-shutdown-for-ras-pis/18926 "2019-12-08T20:28:58Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Trying\_to\_learn](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/trying_to_learn/32/28400_2.png) [@Trying\_to\_learn](https://discourse.nodered.org/u/Trying_to_learn)\
**Post date:** [8 December 2019 20:28 UTC](https://discourse.nodered.org/t/my-effort-at-remote-shutdown-for-ras-pis/18926/1 "2019-12-08T20:28:58Z")

</div>

(No offence @dynamicdave but seeing his flow, I thought I would submit mine.)

As in his post/thread I have a few RPIs running and need to be able to remote control them.  
And by that I mean:  
Shut them down,  
Reboot them,  
Back up the node-red settings,  
Test them for error detection (two ways)  
and update/upgrade them. This part is work-in-progress.

This is the basic flow layout:

 ![Screenshot from 2019-12-09 06-53-03](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/8/8b40cf632d395a85d525eeaa898bd7d5f133d497.png)

The structure is pretty much as the flow posted by @dynamicdave but also slightly different.

Starting top left:  
MQTT node receives the command. It is then converted from `JSON` format and the `switch` node filters out other commands for other machines.

It is then sent to **logging** with a time stamp. I'll get back to that soon.  
Then the command is `delayed` 1 second and sent to another `switch` node.

This one routes the command depending on what it is: Shutdown, reboot, etc.  
There are a couple more `delay` nodes which allow replies to be sent before the actual command happens. Useful for acknowledgement.

Next you see the group of `exec` nodes which do their commands.  
Another `delay` node and all these messages are sent along to a `function` node and then sent out of an `MQTT` node, acknowledging the command's receipt.

I did have an option where it echoed the command back, but that was a bit problematic so I stopped doing that. Though the node is still there to allow that.

You will also see there are two `command received` nodes. That is because the flow acknowledges the receipt of the command and if it is a shutdown or reboot command, it sends back a message to the sender so things can be done there. (That's me being me about messages and sequences.)

I have `debug` nodes along the way - which shouldn't see much use - but are handy all the same.

The `test1` and `test2` parts are where a local script/command is run and one works and the other generates an error. This checks that the machine is sending back correct _status_ messages when commands are done. (Not really useful but there for central monitoring of all machines and **all** states so if a machine has an error, it is correctly reported back.)

I have _skipped_ one node. A `link` node above the two `delay` nodes.  
That sends a signal to other parts of the flow _stopping_ them as the machine is about to be shut down or rebooted.

Now the logging part:

 ![Screenshot from 2019-12-09 06-53-19](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/a/a63d20a8453ad576ee9a82b67442e1e79adc2185.png)  
This is way overkill for most people but again: I like to log things.

There are a few buttons to allow logging and displaying of the data.  
You can edit the respective `function` nodes (setup) to set the default state of the button.

Then you see a list of command received - with date - and a log file is also created.  
I included an extra queue only to save me having to read the log files. Mostly during design/set up of the flow. That is in the bottom right of the flow.

**extra** nodes needed:  
`node-red-contrib-ui-led`  
`node-red-contrib-simple-gate`  
`node-red-contrib-simple-message-queue`

Message/command format:  
`{"DEVICE":"<device name>", "COMMAND":"<command>","state":1}`

device\_name: Text determining the computer's name. Used in the first `switch` node.  
command: Text either: `Shutdown``Reboot``Backup``Test1``Test2``Update` or `Upgrade`

state, used to check sequence of messages. Probably not needed for most people.

Now the flow:

```auto
[{"id":"52bb799a.59cbb","type":"mqtt in","z":"bf66eea1.cd99d","name":"COMMAND","topic":"DO_THIS/#","qos":"2","datatype":"auto","broker":"2d7fe08c.3d8c6","x":90,"y":270,"wires":[["6acc5b2b.3ab6c4"]]},{"id":"6acc5b2b.3ab6c4","type":"json","z":"bf66eea1.cd99d","name":"","property":"payload","action":"","pretty":false,"x":230,"y":270,"wires":[["e820bc50.e988b"]]},{"id":"e820bc50.e988b","type":"switch","z":"bf66eea1.cd99d","name":"","property":"payload.DEVICE","propertyType":"msg","rules":[{"t":"eq","v":"MUSICPI","vt":"str"},{"t":"eq","v":"BEDPI","vt":"str"},{"t":"eq","v":"PIFACE","vt":"str"},{"t":"eq","v":"CAMERAPI","vt":"str"},{"t":"eq","v":"PORTAPI","vt":"str"},{"t":"eq","v":"TelePi","vt":"str"},{"t":"eq","v":"BEEFPI","vt":"str"}],"checkall":"true","repair":false,"outputs":7,"x":350,"y":270,"wires":[[],[],[],[],[],["e3145860.227448","358d5b09.719924","5017c95a.e350c"],[]]},{"id":"15eb299c.11bdc6","type":"debug","z":"bf66eea1.cd99d","name":"Final command","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":485,"y":210,"wires":[]},{"id":"60147ec.1e3d7","type":"switch","z":"bf66eea1.cd99d","name":"","property":"payload.COMMAND","propertyType":"msg","rules":[{"t":"eq","v":"Shutdown","vt":"str"},{"t":"eq","v":"Reboot","vt":"str"},{"t":"eq","v":"Backup","vt":"str"},{"t":"eq","v":"Update","vt":"str"},{"t":"eq","v":"Upgrade","vt":"str"},{"t":"eq","v":"Test1","vt":"str"},{"t":"eq","v":"Test2","vt":"str"}],"checkall":"true","repair":false,"outputs":7,"x":630,"y":260,"wires":[["c661b884.39269","65ee48e3.88f68","94cd03b0.b0e15"],["f17604f2.dc80f","65ee48e3.88f68","94cd03b0.b0e15"],["dd1ee7ca.460238"],["862b9d38.55fb08"],["b29a395e.305608"],["9ad3b375.e16318"],["6b5bfc46.abc8ac"]]},{"id":"2c83c765.67e608","type":"comment","z":"bf66eea1.cd99d","name":"Allow remote shutdown","info":"","x":280,"y":180,"wires":[]},{"id":"dd1ee7ca.460238","type":"exec","z":"bf66eea1.cd99d","command":"bash /home/pi/Mine/NR_Backup.sh","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Backup","x":940,"y":320,"wires":[[],[],["e5c6398a.c09c8"]]},{"id":"436ab820.4a052","type":"comment","z":"bf66eea1.cd99d","name":"Command response reply","info":"","x":155,"y":380,"wires":[]},{"id":"ee286.1a157d7b","type":"debug","z":"bf66eea1.cd99d","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":345,"y":540,"wires":[]},{"id":"b01bc6d1.08ba88","type":"function","z":"bf66eea1.cd99d","name":"","func":"var prefix = 'COMMAND_REPLY/';\nmsg.topic = global.get('myDeviceName');\nmsg.topic = prefix + msg.topic;\nreturn msg;","outputs":1,"noerr":0,"x":175,"y":440,"wires":[["9430eebb.e5fbf","ee286.1a157d7b","ee242c91.d29e"]]},{"id":"ee242c91.d29e","type":"debug","z":"bf66eea1.cd99d","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"topic","x":335,"y":500,"wires":[]},{"id":"9430eebb.e5fbf","type":"mqtt out","z":"bf66eea1.cd99d","name":"Results from commands issued.","topic":"","qos":"2","retain":"","broker":"2d7fe08c.3d8c6","x":405,"y":440,"wires":[]},{"id":"ef02182c.8dfaa8","type":"exec","z":"bf66eea1.cd99d","command":"sudo shutdown -h now","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Shut down","x":950,"y":220,"wires":[[],[],["e5c6398a.c09c8"]]},{"id":"fc6a851a.ba85b","type":"exec","z":"bf66eea1.cd99d","command":"sudo reboot","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Reboot","x":940,"y":270,"wires":[[],[],["e5c6398a.c09c8"]]},{"id":"e5c6398a.c09c8","type":"delay","z":"bf66eea1.cd99d","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":1160,"y":340,"wires":[["b01bc6d1.08ba88"]]},{"id":"65ee48e3.88f68","type":"function","z":"bf66eea1.cd99d","name":"CMD received","func":"if (msg.payload.length !== 0 ) \n{\n msg = {payload: \"Shutdown/Restart Command received\"};\n}\nreturn msg;","outputs":1,"noerr":0,"x":960,"y":170,"wires":[["b01bc6d1.08ba88"]]},{"id":"c661b884.39269","type":"delay","z":"bf66eea1.cd99d","name":"","pauseType":"delay","timeout":"3","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":760,"y":230,"wires":[["ef02182c.8dfaa8"]]},{"id":"f17604f2.dc80f","type":"delay","z":"bf66eea1.cd99d","name":"","pauseType":"delay","timeout":"3","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":760,"y":260,"wires":[["fc6a851a.ba85b"]]},{"id":"6b5bfc46.abc8ac","type":"exec","z":"bf66eea1.cd99d","command":"dirfdgdfg","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Test2","x":930,"y":517,"wires":[[],[],["e5c6398a.c09c8"]]},{"id":"e3145860.227448","type":"function","z":"bf66eea1.cd99d","name":"Time Stamp","func":"var a = msg.payload;\nvar b = new Date().toString();\nmsg = {payload: b + \" >> \" + a + \" << \"};\nreturn msg;\n","outputs":1,"noerr":0,"x":530,"y":500,"wires":[["af8cf4da.b922"]]},{"id":"9ad3b375.e16318","type":"exec","z":"bf66eea1.cd99d","command":"dir","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Test1","x":930,"y":467,"wires":[[],[],["e5c6398a.c09c8"]]},{"id":"862b9d38.55fb08","type":"exec","z":"bf66eea1.cd99d","command":"sudo apt update","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Update","x":940,"y":370,"wires":[[],[],["e5c6398a.c09c8"]]},{"id":"21ce64a9.ab1394","type":"function","z":"bf66eea1.cd99d","name":"Echo command","func":"var c = msg.payload.COMMAND;\nif (msg.payload.length !== 0 ) \n{\n msg = {payload: c};\n}\nreturn msg;","outputs":1,"noerr":0,"x":661,"y":359,"wires":[["b01bc6d1.08ba88"]]},{"id":"358d5b09.719924","type":"delay","z":"bf66eea1.cd99d","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":485,"y":260,"wires":[["15eb299c.11bdc6","60147ec.1e3d7"]]},{"id":"5017c95a.e350c","type":"function","z":"bf66eea1.cd99d","name":"CMD received","func":"var c = msg.payload;\nif (msg.payload.length !== 0 ) \n{\n msg = {payload: \"Command received\"};\n}\nreturn msg;","outputs":1,"noerr":0,"x":661,"y":329,"wires":[["b01bc6d1.08ba88"]]},{"id":"94cd03b0.b0e15","type":"link out","z":"bf66eea1.cd99d","name":"STOP","links":["79b7a172.22a23"],"x":715,"y":200,"wires":[]},{"id":"b29a395e.305608","type":"exec","z":"bf66eea1.cd99d","command":"sudo apt update","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Upgrade","x":940,"y":419,"wires":[[],[],["e5c6398a.c09c8"]]},{"id":"a6b22c78.fbf3b8","type":"link in","z":"bf66eea1.cd99d","name":"Received commands log","links":["af8cf4da.b922"],"x":170,"y":970,"wires":[["eb7b85c3.166df8","10d4b561.200853"]],"l":true},{"id":"eb7b85c3.166df8","type":"gate","z":"bf66eea1.cd99d","name":"","controlTopic":"control","defaultState":"open","openCmd":"GO","closeCmd":"STOP","toggleCmd":"toggle","defaultCmd":"default","persist":false,"x":460,"y":970,"wires":[["66379bb.ffaa264"]]},{"id":"10d4b561.200853","type":"gate","z":"bf66eea1.cd99d","name":"","controlTopic":"control","defaultState":"open","openCmd":"GO","closeCmd":"STOP","toggleCmd":"toggle","defaultCmd":"default","persist":false,"x":460,"y":1140,"wires":[["eada4d73.4b00c"]]},{"id":"66379bb.ffaa264","type":"function","z":"bf66eea1.cd99d","name":"name","func":"var path = global.get(\"event_paths\");\nmsg.filename = path + \"commands_received.txt\";\n\nvar time = new Date().toLocaleString();\nmsg.date = time;\nmsg.payload = time + \" \" + msg.payload;\nreturn msg;\n","outputs":1,"noerr":0,"x":650,"y":970,"wires":[["a3327beb.30191","fbc14ad5.b6458"]]},{"id":"443c9c7d.fdcbc4","type":"fan","z":"bf66eea1.cd99d","x":1210,"y":920,"wires":[["eb7b85c3.166df8"]]},{"id":"ec3563eb.269a08","type":"fan","z":"bf66eea1.cd99d","x":650,"y":920,"wires":[["7fbe1dff.688fa4","eb7b85c3.166df8"]]},{"id":"62991004.a73a38","type":"link in","z":"bf66eea1.cd99d","name":"Mark log","links":["7183b790.8f0af8"],"x":265,"y":920,"wires":[["eb7b85c3.166df8"]]},{"id":"4b85f3f9.c1142c","type":"fan","z":"bf66eea1.cd99d","x":760,"y":1100,"wires":[["10d4b561.200853","97ae3de8.dc9b78"]]},{"id":"eada4d73.4b00c","type":"ring-buffer","z":"bf66eea1.cd99d","name":"CMDs","capacity":16,"order":"new-to-old","sendOnlyIfFull":false,"pushAfterClear":false,"extra":false,"perTopic":false,"x":610,"y":1140,"wires":[["4128f2ad.f02f6c"]]},{"id":"a3327beb.30191","type":"file","z":"bf66eea1.cd99d","name":"Commands received","filename":"","appendNewline":true,"createDir":true,"overwriteFile":"false","x":890,"y":970,"wires":[[]]},{"id":"fbc14ad5.b6458","type":"function","z":"bf66eea1.cd99d","name":"Time stamp","func":"msg.time = new Date().toLocaleString();\nreturn msg;","outputs":1,"noerr":0,"x":1285,"y":1020,"wires":[["20247c00.c0e05c"]]},{"id":"522c1d42.8cd2ec","type":"inject","z":"bf66eea1.cd99d","name":"STOP","topic":"CONTROL","payload":"STOP","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":460,"y":880,"wires":[["ec3563eb.269a08"]],"icon":"node-red/alert.png"},{"id":"135ee29c.488bad","type":"inject","z":"bf66eea1.cd99d","name":"GO","topic":"CONTROL","payload":"GO","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":"2","x":460,"y":920,"wires":[["ec3563eb.269a08"]]},{"id":"1eace28d.94aa4d","type":"switch","z":"bf66eea1.cd99d","name":"","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"CONTROL","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":650,"y":880,"wires":[["271dbaca.9c6566","ec3563eb.269a08"]]},{"id":"7fbe1dff.688fa4","type":"ui_led","z":"bf66eea1.cd99d","group":"43459bd7.7150a4","order":4,"width":"1","height":"1","label":"","labelPlacement":"left","labelAlignment":"left","colorForValue":[{"color":"red","value":"STOP","valueType":"str"},{"color":"green","value":"GO","valueType":"str"}],"name":"Commands Logging LED","x":900,"y":920,"wires":[]},{"id":"1c3a939a.2d7064","type":"switch","z":"bf66eea1.cd99d","name":"","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"CONTROL","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":760,"y":1060,"wires":[["5a138d7c.e9c7f4","4b85f3f9.c1142c"]]},{"id":"97ae3de8.dc9b78","type":"ui_led","z":"bf66eea1.cd99d","group":"43459bd7.7150a4","order":2,"width":"1","height":"1","label":"","labelPlacement":"left","labelAlignment":"left","colorForValue":[{"color":"red","value":"STOP","valueType":"str"},{"color":"green","value":"GO","valueType":"str"}],"name":"Commands List LED","x":950,"y":1100,"wires":[]},{"id":"ce53ed99.6a5028","type":"inject","z":"bf66eea1.cd99d","name":"GO","topic":"CONTROL","payload":"GO","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":"5","x":620,"y":1100,"wires":[["4b85f3f9.c1142c"]]},{"id":"4128f2ad.f02f6c","type":"ui_template","z":"bf66eea1.cd99d","group":"43459bd7.7150a4","name":"Commands RX log","order":5,"width":"6","height":"6","format":"<table id=\"table\" border=\"1\">\n <tr>\n <th>Commands RX log</th> \n </tr>\n <tbody>\n <tr ng-repeat=\"row in msg.payload track by $index\">\n <td class=\"text\" >{{row}}</td>\n </tr>\n </tbody>\n</table>\n","storeOutMessages":false,"fwdInMessages":false,"templateScope":"local","x":800,"y":1140,"wires":[[]]},{"id":"20247c00.c0e05c","type":"simple-queue","z":"bf66eea1.cd99d","name":"queue1","firstMessageBypass":false,"bypassInterval":"0","x":1480,"y":1021,"wires":[["bca0c12.5c4b1c"]]},{"id":"4761869b.81dbd8","type":"function","z":"bf66eea1.cd99d","name":"Push Button","func":"var state = context.get(\"STATE\")||0;\nvar enabled = context.get(\"ENABLED\")||0;\n\n// Look for a message with topic set to SETUP to set values.\nif (msg.topic == \"SETUP\") //Do this if the message is NOT \"X\"\n{\n //\n // Background colours first.\n //\n context.set(\"ABGC\", msg.colourA);\n context.set(\"BBGC\", msg.colourB);\n //\n // Disabled button background colour.\n //\n context.set(\"DISABLEDCLR\",msg.disabledColour);\n //\n // Now do text.\n //\n context.set(\"Atxt\", msg.txtA);\n context.set(\"Btxt\", msg.txtB);\n //\n // Font colours.\n //\n context.set(\"AFC\",msg.txtclrA);\n context.set(\"BFC\",msg.txtclrB);\n //\n // Payloads.\n //\n context.set(\"PayloadA\", msg.payloadA);\n context.set(\"PayloadB\", msg.payloadB);\n //\n // Topic.\n //\n if (msg.topicSET !== null)\n {\n context.set(\"Topic\",msg.topicSET);\n } else\n {\n context.set(\"Topic\",\"~\");\n }\n msg.txt = msg.txtA;\n msg.colour = msg.disabledColour;\n msg.fontclr = msg.txtclrA;\n return msg;\n}\n\n// Now on to the real stuff.\nif (msg.payload == \"X\")\n{\n //node.warn(\"X detected\");\n // Insert here code to enable other stuff.\n// if (context.get(\"ENABLED\") === 0)\n if (enabled === 0)\n {\n //\n // Old code.\n //\n //node.warn(\"Setting enable\");\n// context.set(\"ENABLED\",1);\n// msg.txt = context.get(\"Atxt\");\n// msg.colour = context.get(\"ABGC\");\n// msg.fontclr = context.get(\"AFC\");\n\n // New code.\n \n //node.warn(\"State = \" + state);\n\n if (state === 0)\n {\n //\n // Set things for state 0\n //\n //node.warn(\"State 0 detected\");\n msg.payload = context.get(\"PayloadA\");\n msg.colour = context.get(\"ABGC\");\n msg.txt = context.get(\"Atxt\");\n msg.fontclr = context.get(\"AFC\");\n }\n else if (state === 1)\n {\n //\n // Set things for state 1\n //\n //node.warn(\"State 1 detected\");\n msg.payload = context.get(\"PayloadB\");\n msg.colour = context.get(\"BBGC\");\n msg.txt = context.get(\"Btxt\");\n msg.fontclr = context.get(\"BFC\");\n }\n context.set(\"ENABLED\",1);\n return msg;\n }\n\n// if (context.get(\"ENABLED\") === 1)\n state = (state + 1)% 2;\n //node.warn(state);\n context.set(\"STATE\",state);\n if (enabled === 1)\n {\n if (state === 0)\n {\n // Condition A\n msg.payload = context.get(\"PayloadA\");\n msg.colour = context.get(\"ABGC\");\n msg.txt = context.get(\"Atxt\");\n msg.fontclr = context.get(\"AFC\");\n } else\n if (state === 1)\n {\n // Condition B\n msg.payload = context.get(\"PayloadB\");\n msg.colour = context.get(\"BBGC\");\n msg.txt = context.get(\"Btxt\");\n msg.fontclr = context.get(\"BFC\");\n }\n }\n \n if (context.get(\"Topic\") == \"~\")\n {\n msg.topic = \"\";\n } else\n {\n msg.topic = context.get(\"Topic\");\n }\n return msg;\n}\nif (msg.payload == \"Z\")\n{\n //\n ////node.warn(\"Timed out\");\n //\n context.set(\"ENABLED\",0);\n if (state === 0)\n {\n //\n // Set things for state 1\n //\n msg.payload = context.get(\"PayloadA\");\n msg.colour = context.get(\"DISABLEDCLR\");\n msg.txt = context.get(\"Atxt\");\n msg.fontclr = context.get(\"AFC\");\n }\n else if (state === 1)\n {\n //\n // Set things for state 2\n //\n msg.payload = context.get(\"PayloadB\");\n msg.colour = context.get(\"DISABLEDCLR\");\n msg.txt = context.get(\"Btxt\");\n msg.fontclr = context.get(\"BFC\");\n }\n return msg;\n}\n","outputs":1,"noerr":0,"x":480,"y":800,"wires":[["b941b592.355d7","1eace28d.94aa4d"]]},{"id":"271dbaca.9c6566","type":"debug","z":"bf66eea1.cd99d","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":650,"y":840,"wires":[]},{"id":"ab7514b9.7b3438","type":"function","z":"bf66eea1.cd99d","name":"Push Button","func":"var state = context.get(\"STATE\")||0;\nvar enabled = context.get(\"ENABLED\")||0;\n\n// Look for a message with topic set to SETUP to set values.\nif (msg.topic == \"SETUP\") //Do this if the message is NOT \"X\"\n{\n //\n // Background colours first.\n //\n context.set(\"ABGC\", msg.colourA);\n context.set(\"BBGC\", msg.colourB);\n //\n // Disabled button background colour.\n //\n context.set(\"DISABLEDCLR\",msg.disabledColour);\n //\n // Now do text.\n //\n context.set(\"Atxt\", msg.txtA);\n context.set(\"Btxt\", msg.txtB);\n //\n // Font colours.\n //\n context.set(\"AFC\",msg.txtclrA);\n context.set(\"BFC\",msg.txtclrB);\n //\n // Payloads.\n //\n context.set(\"PayloadA\", msg.payloadA);\n context.set(\"PayloadB\", msg.payloadB);\n //\n // Topic.\n //\n if (msg.topicSET !== null)\n {\n context.set(\"Topic\",msg.topicSET);\n } else\n {\n context.set(\"Topic\",\"~\");\n }\n msg.txt = msg.txtA;\n msg.colour = msg.disabledColour;\n msg.fontclr = msg.txtclrA;\n return msg;\n}\n\n// Now on to the real stuff.\nif (msg.payload == \"X\")\n{\n //node.warn(\"X detected\");\n // Insert here code to enable other stuff.\n// if (context.get(\"ENABLED\") === 0)\n if (enabled === 0)\n {\n //\n // Old code.\n //\n //node.warn(\"Setting enable\");\n// context.set(\"ENABLED\",1);\n// msg.txt = context.get(\"Atxt\");\n// msg.colour = context.get(\"ABGC\");\n// msg.fontclr = context.get(\"AFC\");\n\n // New code.\n \n //node.warn(\"State = \" + state);\n\n if (state === 0)\n {\n //\n // Set things for state 0\n //\n //node.warn(\"State 0 detected\");\n msg.payload = context.get(\"PayloadA\");\n msg.colour = context.get(\"ABGC\");\n msg.txt = context.get(\"Atxt\");\n msg.fontclr = context.get(\"AFC\");\n }\n else if (state === 1)\n {\n //\n // Set things for state 1\n //\n //node.warn(\"State 1 detected\");\n msg.payload = context.get(\"PayloadB\");\n msg.colour = context.get(\"BBGC\");\n msg.txt = context.get(\"Btxt\");\n msg.fontclr = context.get(\"BFC\");\n }\n context.set(\"ENABLED\",1);\n return msg;\n }\n\n// if (context.get(\"ENABLED\") === 1)\n state = (state + 1)% 2;\n //node.warn(state);\n context.set(\"STATE\",state);\n if (enabled === 1)\n {\n if (state === 0)\n {\n // Condition A\n msg.payload = context.get(\"PayloadA\");\n msg.colour = context.get(\"ABGC\");\n msg.txt = context.get(\"Atxt\");\n msg.fontclr = context.get(\"AFC\");\n } else\n if (state === 1)\n {\n // Condition B\n msg.payload = context.get(\"PayloadB\");\n msg.colour = context.get(\"BBGC\");\n msg.txt = context.get(\"Btxt\");\n msg.fontclr = context.get(\"BFC\");\n }\n }\n \n if (context.get(\"Topic\") == \"~\")\n {\n msg.topic = \"\";\n } else\n {\n msg.topic = context.get(\"Topic\");\n }\n return msg;\n}\nif (msg.payload == \"Z\")\n{\n //\n ////node.warn(\"Timed out\");\n //\n context.set(\"ENABLED\",0);\n if (state === 0)\n {\n //\n // Set things for state 1\n //\n msg.payload = context.get(\"PayloadA\");\n msg.colour = context.get(\"DISABLEDCLR\");\n msg.txt = context.get(\"Atxt\");\n msg.fontclr = context.get(\"AFC\");\n }\n else if (state === 1)\n {\n //\n // Set things for state 2\n //\n msg.payload = context.get(\"PayloadB\");\n msg.colour = context.get(\"DISABLEDCLR\");\n msg.txt = context.get(\"Btxt\");\n msg.fontclr = context.get(\"BFC\");\n }\n return msg;\n}\n","outputs":1,"noerr":0,"x":480,"y":1060,"wires":[["c02127a5.268b7","1c3a939a.2d7064"]]},{"id":"5a138d7c.e9c7f4","type":"debug","z":"bf66eea1.cd99d","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":760,"y":1020,"wires":[]},{"id":"bca0c12.5c4b1c","type":"debug","z":"bf66eea1.cd99d","name":"Commands received","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1510,"y":1061,"wires":[]},{"id":"eb98df69.e6039","type":"change","z":"bf66eea1.cd99d","name":"Read","rules":[{"t":"set","p":"trigger","pt":"msg","to":"1","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1270,"y":1060,"wires":[["20247c00.c0e05c"]]},{"id":"d92379cc.41683","type":"change","z":"bf66eea1.cd99d","name":"Wipe","rules":[{"t":"set","p":"reset","pt":"msg","to":"1","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1270,"y":1100,"wires":[["20247c00.c0e05c"]]},{"id":"780313ac.31733c","type":"function","z":"bf66eea1.cd99d","name":"Setup","func":"msg = {\n \"topic\":\"SETUP\",\n \"disabledColour\":\"brown\",\n \"colourA\": \"lime\",\n \"colourB\": \"green\",\n \"txtA\": \"Log\",\n \"txtB\": \"Log Stop\",\n \"txtclrA\": \"black\",\n \"txtclrB\": \"black\",\n \"payloadA\": \"GO\",\n \"payloadB\": \"STOP\",\n \"topicSET\": \"CONTROL\"\n}\nreturn msg;","outputs":1,"noerr":0,"x":280,"y":800,"wires":[["4761869b.81dbd8"]]},{"id":"b941b592.355d7","type":"ui_button","z":"bf66eea1.cd99d","name":"Commands RX Logging","group":"43459bd7.7150a4","order":3,"width":"2","height":"1","passthru":false,"label":"{{msg.txt}}","tooltip":"","color":"{{msg.fontclr}}","bgcolor":"{{msg.colour}}","icon":"","payload":"X","payloadType":"str","topic":"","x":520,"y":760,"wires":[["4761869b.81dbd8","f67a9584.cefc28"]]},{"id":"f67a9584.cefc28","type":"trigger","z":"bf66eea1.cd99d","op1":"","op2":"Z","op1type":"nul","op2type":"str","duration":"3","extend":false,"units":"s","reset":"","bytopic":"all","name":"","x":470,"y":840,"wires":[["4761869b.81dbd8"]]},{"id":"824bbb91.23f2d","type":"function","z":"bf66eea1.cd99d","name":"Setup","func":"msg = {\n \"topic\":\"SETUP\",\n \"disabledColour\":\"brown\",\n \"colourA\": \"lime\",\n \"colourB\": \"green\",\n \"txtA\": \"Display\",\n \"txtB\": \"Display Stop\",\n \"txtclrA\": \"black\",\n \"txtclrB\": \"black\",\n \"payloadA\": \"GO\",\n \"payloadB\": \"STOP\",\n \"topicSET\": \"CONTROL\"\n}\nreturn msg;","outputs":1,"noerr":0,"x":280,"y":1060,"wires":[["ab7514b9.7b3438"]]},{"id":"c02127a5.268b7","type":"ui_button","z":"bf66eea1.cd99d","name":"Commands RX List","group":"43459bd7.7150a4","order":1,"width":"2","height":"1","passthru":false,"label":"{{msg.txt}}","tooltip":"","color":"{{msg.fontclr}}","bgcolor":"{{msg.colour}}","icon":"","payload":"X","payloadType":"str","topic":"","x":500,"y":1020,"wires":[["ab7514b9.7b3438","f6c03f7f.70e3f"]]},{"id":"f6c03f7f.70e3f","type":"trigger","z":"bf66eea1.cd99d","op1":"","op2":"Z","op1type":"nul","op2type":"str","duration":"3","extend":false,"units":"s","reset":"","bytopic":"all","name":"","x":470,"y":1100,"wires":[["ab7514b9.7b3438"]]},{"id":"843b64d0.d43238","type":"inject","z":"bf66eea1.cd99d","name":"Read","topic":"","payload":" ","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":"","x":1140,"y":1060,"wires":[["eb98df69.e6039"]]},{"id":"cd99ac04.6034e","type":"inject","z":"bf66eea1.cd99d","name":"Wipe","topic":"","payload":" ","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":"","x":1140,"y":1100,"wires":[["d92379cc.41683"]]},{"id":"c0c3b487.3cd558","type":"inject","z":"bf66eea1.cd99d","name":"Inject","topic":"","payload":"","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":"3","x":280,"y":760,"wires":[["780313ac.31733c"]]},{"id":"f08a2462.1698b","type":"inject","z":"bf66eea1.cd99d","name":"Inject","topic":"","payload":"","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":"3","x":280,"y":1020,"wires":[["824bbb91.23f2d"]]},{"id":"af8cf4da.b922","type":"link out","z":"bf66eea1.cd99d","name":"LOGGING","links":["a6b22c78.fbf3b8"],"x":690,"y":500,"wires":[],"l":true},{"id":"887fda2c.675b38","type":"comment","z":"bf66eea1.cd99d","name":"Logging","info":"","x":520,"y":710,"wires":[]},{"id":"2d7fe08c.3d8c6","type":"mqtt-broker","z":"","name":"MQTT host","broker":"192.168.0.99","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"SOM","birthQos":"0","birthPayload":"TelePi comms up","closeTopic":"EOM","closePayload":"TelePi shutting down","willTopic":"EOM","willQos":"0","willPayload":"TelePi Comms Failure"},{"id":"43459bd7.7150a4","type":"ui_group","z":"","name":"Cmds Received","tab":"fb960b7a.961008","order":3,"disp":true,"width":"6","collapse":false},{"id":"fb960b7a.961008","type":"ui_tab","z":"","name":"Logging","icon":"list","order":3,"disabled":false,"hidden":false}]

```

---

<div class="post-metadata">

**Author:** ![dynamicdave](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/dynamicdave/32/96_2.png) [@dynamicdave](https://discourse.nodered.org/u/dynamicdave)\
**Post date:** [9 December 2019 06:48 UTC](https://discourse.nodered.org/t/my-effort-at-remote-shutdown-for-ras-pis/18926/2 "2019-12-09T06:48:05Z")

</div>

Hi Andrew @Trying_to_learn - no offence taken.  
It's always interesting to see how other people solve a similar problem.  
Thanks for sharing.

As you know, programming is such an interesting subject as there is normally more than one way to solve a particular problem, and by looking at other people's solutions one can pick up tips and ideas.

Although this particular exercise [i.e. shutting down one or more Pi(es)] had a clear objective and specific need, I wanted the group of students who helped create the flow to learn something from the experience.

In fact two other projects came out of this work.

1. Interrogating a set of simple weather stations at remote locations.
2. Chat-RED, a point-to-point or point-to-many text messaging system.
