Another set of eyes on this "routine" please

No foreign nodes.

Scope:

I have a NAS (that is not always on).
When it is, I want to backup (via rsync to the NAS.
Not repeatedly. Maybe just once per it being turned on. (The NAS)

Walkthrough of the code seen:

heartbeat is a clock signal that happens about every 20 seconds.
global.BarnStatus is either true or false depending on the status of the NAS.
(This is set by the IP address being pingable.)
I have a file /etc/fstab which is the main MOUNT for the NAS.
So when the PING gets a true, the NAS is mounted, the rsync command is done.
When it starts, it sends a command to indicate things are happening.
When complete, it sends another message. (I kinda love messages)

But I don't know if I want to keep the MOUNT active.
Not critical, but I'm asking. The access is limited.

Wondering if it is possible to unmount when complete. Just for me being anal.

--

(Sorry, I forget how to make the thumbnail visible for the flow layout.)

[{"id":"716a55d4f277c2cd","type":"inject","z":"9b7e7466.a4b698","name":"GO","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"control","payload":"go","payloadType":"str","x":300,"y":5160,"wires":[["45eea8d0a3ecc9be"]]},{"id":"33375e274c80e6f5","type":"inject","z":"9b7e7466.a4b698","name":"STOP","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"control","payload":"stop","payloadType":"str","x":300,"y":5120,"wires":[["45eea8d0a3ecc9be"]],"icon":"font-awesome/fa-hand-paper-o"},{"id":"00b05ebe8e3bec6b","type":"comment","z":"9b7e7466.a4b698","name":"DRY RUN!!!","info":"","x":480,"y":5170,"wires":[]},{"id":"526b1622b642aeed","type":"inject","z":"9b7e7466.a4b698","name":"UnMount","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"edit `change` node","payloadType":"str","x":850,"y":5120,"wires":[["ce11acec735a15dc"]]},{"id":"bdafaa21a2be263b","type":"inject","z":"9b7e7466.a4b698","name":"Mount","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"edit `change` node","payloadType":"str","x":860,"y":5160,"wires":[["9e3287ebd41c89e0"]]},{"id":"091d26c9f75f1a08","type":"inject","z":"9b7e7466.a4b698","name":"Do","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"dryrun","payload":"false","payloadType":"bool","x":640,"y":5160,"wires":[["b1b76b52b9051457"]]},{"id":"0ec1eca5cda0360c","type":"inject","z":"9b7e7466.a4b698","name":"Simulate","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"dryrun","payload":"true","payloadType":"bool","x":650,"y":5120,"wires":[["b1b76b52b9051457"]]},{"id":"a503f1af20b69112","type":"inject","z":"9b7e7466.a4b698","name":"STOP","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"control","payload":"stop","payloadType":"str","x":470,"y":5550,"wires":[["540942e7f834cb81"]],"icon":"font-awesome/fa-hand-paper-o"},{"id":"dfaa25f5a5e515a5","type":"inject","z":"9b7e7466.a4b698","name":"GO","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"control","payload":"go","payloadType":"str","x":470,"y":5590,"wires":[["540942e7f834cb81"]]},{"id":"dd8b1520ad236e1c","type":"group","z":"9b7e7466.a4b698","name":"","style":{"stroke":"#000000","fill-opacity":"1","label":true},"nodes":["e4d287f87bc55feb","d3affa8f94a261ef","bc71410642c07a9a","6cd51b56501cfa7c","a2c6c3ead79a023a","4974f7fe81962fe5","d17b183ed8f904f7","c7e0742f9c03f5c9","e482f08b9dd26168","aa8956927291d309","d29798267fc0c4a1","b147a1326e0513c6","f69ee56562191d5d","d3a4a6f817bbea81","33b7a719324bc33b","1832e6e7874beb13","45eea8d0a3ecc9be","1c2095f4e85a05a0","bbe3a2de0123c698","13fc164c307f3aad","ce11acec735a15dc","9e3287ebd41c89e0","91cef2ba568fca87","b1b76b52b9051457","80684dfef7b1955e","540942e7f834cb81"],"x":204,"y":5191.5,"w":952,"h":329.5},{"id":"e4d287f87bc55feb","type":"function","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"Run next rsync","func":"//  Needed to indicate start/stop of sequence\nlet msg1 = {}\n// Stop if no more commands\nif (!msg.rsynccmds || msg.index >= msg.rsynccmds.length) {\n    msg1.payload = 0\n    return [null,msg1]\n}\n\n// Send current command to Exec node\nmsg.payload = msg.rsynccmds[msg.index]\nmsg1.payload = 1\nreturn [msg,msg1]","outputs":2,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":680,"y":5420,"wires":[["bc71410642c07a9a"],["540942e7f834cb81"]],"outputLabels":["","start/stop for LED"]},{"id":"d3affa8f94a261ef","type":"function","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"Next rsync","func":"msg.index++\nreturn msg","outputs":1,"x":1040,"y":5440,"wires":[["e4d287f87bc55feb"]]},{"id":"bc71410642c07a9a","type":"exec","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","command":"","addpay":"payload","append":"","useSpawn":"false","timer":"","winHide":false,"oldrc":false,"name":"Run rsync","x":850,"y":5420,"wires":[["4974f7fe81962fe5","d3affa8f94a261ef"],[],[]]},{"id":"6cd51b56501cfa7c","type":"change","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"add name","rules":[{"t":"set","p":"who","pt":"msg","to":"myDeviceName","tot":"global"}],"action":"","property":"","from":"","to":"","reg":false,"x":615,"y":5480,"wires":[["e482f08b9dd26168"]],"l":false},{"id":"a2c6c3ead79a023a","type":"exec","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","command":"find /home/pi/Public/NR -maxdepth 1 -type d -name '2026*' | sort","addpay":false,"append":"","useSpawn":"false","timer":"","winHide":false,"oldrc":false,"name":"List 2026+ dirs","x":680,"y":5350,"wires":[["b1b76b52b9051457"],[],[]]},{"id":"4974f7fe81962fe5","type":"debug","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"rsync output","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1040,"y":5400,"wires":[]},{"id":"d17b183ed8f904f7","type":"inject","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":470,"y":5440,"wires":[["6cd51b56501cfa7c"]]},{"id":"c7e0742f9c03f5c9","type":"inject","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":470,"y":5480,"wires":[["6cd51b56501cfa7c"]]},{"id":"e482f08b9dd26168","type":"function","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"MQTT cheat","func":"let msg1 = {}\nmsg1.payload = msg\nreturn msg1","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":675,"y":5480,"wires":[["1c2095f4e85a05a0"]],"l":false},{"id":"aa8956927291d309","type":"inject","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"Trigger Sync","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":450,"y":5370,"wires":[["a2c6c3ead79a023a"]]},{"id":"d29798267fc0c4a1","type":"rbe","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"","func":"rbe","gap":"","start":"","inout":"out","septopics":true,"property":"payload","topi":"topic","x":650,"y":5280,"wires":[["bbe3a2de0123c698","9e3287ebd41c89e0"]]},{"id":"b147a1326e0513c6","type":"switch","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"condition","property":"BarnStatus","propertyType":"global","rules":[{"t":"false"},{"t":"true"}],"checkall":"true","repair":false,"outputs":2,"x":460,"y":5280,"wires":[["d3a4a6f817bbea81"],["d29798267fc0c4a1"]]},{"id":"f69ee56562191d5d","type":"debug","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"Status","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":450,"y":5320,"wires":[]},{"id":"d3a4a6f817bbea81","type":"change","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"reset","rules":[{"t":"set","p":"reset","pt":"msg","to":"reset","tot":"str"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":615,"y":5240,"wires":[["d29798267fc0c4a1","ce11acec735a15dc"]],"l":false},{"id":"33b7a719324bc33b","type":"change","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"Barn status","rules":[{"t":"set","p":"payload","pt":"msg","to":"BarnStatus","tot":"global"}],"action":"","property":"","from":"","to":"","reg":false,"x":300,"y":5280,"wires":[["b147a1326e0513c6","f69ee56562191d5d"]]},{"id":"1832e6e7874beb13","type":"link in","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"Heart beat","links":["276adcc509e3ec1e"],"x":290,"y":5240,"wires":[["45eea8d0a3ecc9be"]],"l":true},{"id":"45eea8d0a3ecc9be","type":"gate","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"","controlTopic":"control","defaultState":"open","openCmd":"go","closeCmd":"stop","toggleCmd":"toggle","defaultCmd":"default","statusCmd":"","persist":false,"x":415,"y":5240,"wires":[["33b7a719324bc33b"]],"l":false},{"id":"1c2095f4e85a05a0","type":"mqtt out","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"","topic":"BARN","qos":"0","retain":"true","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"1bbfcdd.2d24532","x":760,"y":5480,"wires":[]},{"id":"bbe3a2de0123c698","type":"delay","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"Delay","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":555,"y":5330,"wires":[["a2c6c3ead79a023a"]],"l":false},{"id":"13fc164c307f3aad","type":"exec","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","command":"","addpay":"payload","append":"","useSpawn":"false","timer":"","winHide":false,"oldrc":false,"name":"Command","x":1040,"y":5240,"wires":[[],[],[]]},{"id":"ce11acec735a15dc","type":"change","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"UnMount","rules":[{"t":"set","p":"payload","pt":"msg","to":"sudo umount /mnt/smb/NR/TelePi","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":850,"y":5240,"wires":[["91cef2ba568fca87"]]},{"id":"9e3287ebd41c89e0","type":"change","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"Mount","rules":[{"t":"set","p":"payload","pt":"msg","to":"sudo mount -t cifs //barn.local/backups/NR/TelePi /mnt/smb/NR/TelePi -o credentials=/root/.smbcredentials,uid=pi,gid=pi,file_mode=0777,dir_mode=0777,noperm,iocharset=utf8","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":840,"y":5280,"wires":[["91cef2ba568fca87"]]},{"id":"91cef2ba568fca87","type":"junction","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","x":940,"y":5260,"wires":[["13fc164c307f3aad","80684dfef7b1955e"]]},{"id":"b1b76b52b9051457","type":"function","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"Prepare rsync commands","func":"// Check for dryrun toggle message\nif (msg.topic === 'dryrun') {\n    let dryRun = (msg.payload === true || msg.payload === 'true')\n    context.set('dryRun', dryRun)\n    node.status({ text: \"DryRun set to \" + dryRun })\n    return null  // exit early\n}\n\n// Normal processing of directory messages\n// Retrieve dryRun from node context\nlet dryRun = context.get('dryRun') // default undefined = simulate if not set\n\nnode.status({ text: \"DryRun \" + dryRun })\n\n// Split the output of 'find' into individual directories\nlet dirs = msg.payload.split('\\n').filter(s => s.trim() !== '')\n\n// Only include directories after this cutoff (YYYY-MM)\nconst cutoff = '2025-10'\n\n// Filter directories that are after the cutoff\nlet newDirs = dirs.filter(fullPath => {\n    let dirName = fullPath.trim().split('/').pop()  // get last part of path\n    let yearMonth = dirName.substring(0, 7)\n    return yearMonth >= cutoff\n})\n\n// Get the device name from global context\nconst myDevice = global.get(\"myDeviceName\")\n\n// Build rsync commands, including year folder dynamically\nmsg.rsynccmds = newDirs.map(d => {\n    const dryRunOption = dryRun ? '--dry-run ' : ''\n    const dirName = d.trim().split('/').pop()      // e.g., \"2025-11-21.21.51.11\"\n    const year = dirName.substring(0, 4)          // \"2025\"\n    const remoteBase = `/mnt/smb/NR/${myDevice}/${year}`\n\n    return `/usr/bin/rsync ${dryRunOption}-avh --no-o --no-g \"${d}\" \"${remoteBase}/\"`\n})\n\nmsg.index = 0\nreturn msg\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":900,"y":5350,"wires":[["e4d287f87bc55feb"]]},{"id":"80684dfef7b1955e","type":"function","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"Mount","func":"// Split on whitespace and trim each part\nlet parts = msg.payload.trim().split(/\\s+/).map(s => s.trim())\nmsg.payload = parts[1]  // second word\n\n// Determine color\nlet color = 'grey'  // default\nif (parts[1] === 'mount') color = 'green'\nelse if (parts[1] === 'umount') color = 'black'\n\nnode.status({fill: color, shape: 'dot', text: parts[1] + 'ed'})\n\nreturn msg\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1020,"y":5300,"wires":[[]]},{"id":"540942e7f834cb81","type":"gate","z":"9b7e7466.a4b698","g":"dd8b1520ad236e1c","name":"","controlTopic":"control","defaultState":"open","openCmd":"go","closeCmd":"stop","toggleCmd":"toggle","defaultCmd":"default","statusCmd":"","persist":false,"x":565,"y":5480,"wires":[["6cd51b56501cfa7c"]],"l":false},{"id":"1bbfcdd.2d24532","type":"mqtt-broker","name":"TIMEPI MQTT","broker":"192.168.17.39","port":"1883","clientid":"","autoConnect":true,"usetls":false,"compatmode":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"autoUnsubscribe":true,"birthTopic":"SOM","birthQos":"2","birthRetain":"false","birthPayload":"TelePi Comms UP","birthMsg":{},"closeTopic":"EOM","closeQos":"0","closeRetain":"false","closePayload":"TelePi shutting DOWN","closeMsg":{},"willTopic":"EOM","willQos":"0","willRetain":"false","willPayload":"TelePi Comms FAILURE","willMsg":{},"sessionExpiry":""}]

Hi Trying_to_learn,

one thing I learnt is, don't try and reinvent the wheel.
My advice would be use a program like syncthing and be done with it
It will do everything you require.

1 Like

Ok, I'll look into that program.

What I posted does work, if manually done.

But doesn't rsync do much the same as syncthing?