I use a variation of a previously published backup to Dropbox to backup to a local directory. (Uses a dsm
node) (I also backup to Dropbox)
This was designed to run on a Debian instance in a VM, hence the use of a function node to create the Date (creating it in Debian was beyond me as the Pi version didn't work)
The only remaining issue for me is how to exclude the node_modules
folder in uibuilder - without specifying all the folders I DO want.
[{"id":"216f880395c9bdcf","type":"group","z":"8428164b1645b4b8","name":"Backup Node-RED Flows to Local Drive","style":{"label":true,"fill":"#e3f3d3","label-position":"n","color":"#000000"},"nodes":["8aaff02f6aa94d51","7ac4cb95d54817ad","52950de559414189","b5233c43e1cea7f1","e2dbf7db77d0c7ad","76dd9fe208e111cc","3903b94699774ca5","8d51bf8c3e6d0ccc"],"x":1434,"y":1019,"w":912,"h":154},{"id":"8aaff02f6aa94d51","type":"inject","z":"8428164b1645b4b8","g":"216f880395c9bdcf","name":"reset","props":[{"p":"payload","v":"","vt":"date"},{"p":"topic","v":"reset","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"reset","payload":"","payloadType":"date","x":1530,"y":1120,"wires":[["52950de559414189"]]},{"id":"7ac4cb95d54817ad","type":"inject","z":"8428164b1645b4b8","g":"216f880395c9bdcf","name":"Start Backup","props":[{"p":"payload"},{"p":"backup","v":"start","vt":"str"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"15 03 * * *","once":false,"onceDelay":0.1,"topic":"Backup","payload":"IoTDevelopment","payloadType":"str","x":1560,"y":1060,"wires":[["e2dbf7db77d0c7ad"]]},{"id":"52950de559414189","type":"dsm","z":"8428164b1645b4b8","g":"216f880395c9bdcf","name":"Zip Node-RED \\n Directory","sm_config":"{\n \"triggerInput\": \"backup\",\n \"stateOutput\": \"postState\",\n \"currentState\": \"step1\",\n \"states\": {\n \"step1\": {\n \"start\": \"step2\",\n \"reset\": \"step1\"\n },\n \"step2\": {\n \"zip\": \"step3\",\n \"reset\": \"step1\"\n },\n \"step3\": {\n \"upload\": \"step1\",\n \"reset\": \"step1\"\n }\n },\n \"data\": {\n },\n \"methods\": {\n \"init\": [\n \"sm.udir = RED.settings.userDir + '/';\",\n \"sm.exec = require('child_process').exec;\",\n \"sm.hostname = require('os').hostname();\",\n \"sm.unlink = require('fs').unlink;\"\n ],\n \"start\": [\n \"/* delete old backup file */\",\n \"var zipfile = sm.udir + 'node-red.zip';\",\n \n \"sm.fill = 'grey';\",\n \"sm.text = 'deleting';\",\n \"output = false;\",\n\n \"sm.unlink(zipfile, function (err) {\",\n \" if (err) {\",\n \" node.warn('no file '+zipfile);\",\n \" }\",\n \" resume('zip', msg);\",\n \"});\"\n ],\n \"zip\": [\n \"let pre = ' ' + sm.udir;\",\n \"let cmd = 'zip -r';\",\n \"cmd += pre + 'node-red.zip';\",\n \"cmd += pre + 'flows*.json';\",\n \"cmd += pre + '.config*.json';\",\n \"cmd += pre + 'settings.js';\",\n \"cmd += pre + 'package.json';\",\n \"cmd += pre + 'package-lock.json';\",\n \"cmd += pre + '.config.modules.json';\",\n \"cmd += pre + 'lib/*';\",\n \"cmd += pre + 'context/*';\",\n \"cmd += pre + 'cronplusdata/*';\",\n \"cmd += pre + 'uibuilder/*';\",\n\n \"sm.fill = 'grey';\",\n \"sm.text = 'zipping';\",\n \"output = false;\",\n \n \"sm.exec(cmd, function(error, stdout, stderr) {\",\n \" if (error) {\",\n \" node.warn(error);\",\n \" } else {\",\n \" resume('upload', msg);\",\n \" }\",\n \"});\"\n ],\n \"upload\": [\n \"let localFilename = sm.udir + 'node-red.zip';\",\n \"let targetDirectory = '/home/pi/documents/data/';\",\n \"msg.payload = localFilename + ' ' + targetDirectory + msg.payload;\",\n\n \"sm.fill = 'green';\",\n \"sm.text = sm.day;\"\n ],\n \"reset\": [\n \"sm.fill = 'grey';\",\n \"sm.text = 'reset';\",\n \"output = false;\"\n ],\n \"status\": {\n \"fill\": {\n \"get\": \"sm.fill\"\n },\n \"shape\": \"dot\",\n \"text\": {\n \"get\": \"sm.text\"\n }\n }\n }\n}","x":1900,"y":1120,"wires":[["76dd9fe208e111cc","8d51bf8c3e6d0ccc"]],"info":" \"sm.ts = msg.payload.ts;\",\r\n \"sm.days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];\",\r\n \"sm.day = msg.payload.day;\", \r\n \"msg.filename = msg.payload + '_' + sm.day + '_nodered.zip';\",\r\n\r\n "},{"id":"b5233c43e1cea7f1","type":"debug","z":"8428164b1645b4b8","g":"216f880395c9bdcf","name":"Copy Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":2230,"y":1120,"wires":[]},{"id":"e2dbf7db77d0c7ad","type":"function","z":"8428164b1645b4b8","g":"216f880395c9bdcf","name":"Create Filename","func":"/** \n * Input\n * mgs.payload - Name of system to be backed up\n */\n\nconst currentDate = new Date()\nconst weekDays = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']\nconst currentDay = weekDays[currentDate.getDay()]\n\nmsg.payload = msg.payload + '_' + currentDay + '_nodered.zip'\n\nreturn msg","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1740,"y":1060,"wires":[["52950de559414189"]]},{"id":"76dd9fe208e111cc","type":"exec","z":"8428164b1645b4b8","g":"216f880395c9bdcf","command":"cp ","addpay":"payload","append":"","useSpawn":"false","timer":"","winHide":false,"oldrc":false,"name":"Copy File","x":2080,"y":1120,"wires":[["b5233c43e1cea7f1"],[],[]]},{"id":"3903b94699774ca5","type":"debug","z":"8428164b1645b4b8","g":"216f880395c9bdcf","name":"DSM Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":2230,"y":1060,"wires":[]},{"id":"8d51bf8c3e6d0ccc","type":"junction","z":"8428164b1645b4b8","g":"216f880395c9bdcf","x":2020,"y":1060,"wires":[["3903b94699774ca5"]]}]