Where is local storage when using FTP and Nodered?

Have a nodered flow using FTP in node GET filename msg.payload[0] and localfilename home/media/Camera/. Running the flow I can login to my remote FTP server list files and then GET the file but get this error Error: msg.payload[0]: No such file or directory.

Q. localfile location where is this? Sort of though I could create a directory under media called Camera and try to save the file from the FTP GET there?

Any advice? I simply want to download a image from a remote FTP server to local storage then display in home assistant.

Hi,
I can’t find the exact details now, but to get camera images pushed to HASS to be available on the GUI and for remote push messages, I had to use a shell to create and configure a www directory under /root/config/ and store the images there.

  • Web shell file path: /root/config/www/camera.jpg
  • Automation path (e.g. service: camera.snapshot): filename: /config/www/camera.jpg
  • HTTP URL: http://homeassistant.local:8123/local/camera.jpg

Hope this helps,

James

I assume your Node Red and FTP capability are running as add-ons, and are therefore in their own docker container. The “/home” directory is not mapped to a host directory on either, so not only will they be pointing at different locations (within container storage), the content will be lost when you upgrade.

You need directories on each that are mapped to the same host location. Node Red has 3 suitably mapped ones: “/config”, “/share” and “/media”. I don’t use the FTP add-on, but according to the documentation, it has the same mapped folders, which are undoubtedly pointing to the same host directories. Given you’re talking media, the last one looks like a good bet.

If you want to know where the host directories are, on HAOS:

/config       /mnt/data/supervisor/homeassistant
/share        /mnt/data/supervisor/share
/media        /mnt/data/supervisor/media

Thanks for the response. NodeRed yes as a add on but FTP no. I dont need a local FTP so just using the FTP In node under storage in NR. node-red-contrib-ftp.

Tried but still comes up with the error - payload[0].name: No such file or directory

Have a function node msg.payload = msg.payload[0]; which in the screen shot shows the file exists on the remote FTP server but its the local directory that is errors.

/media        /mnt/data/supervisor/media

image

ftp node

This node will allow you to LIST, GET, PUT, APPEND, DELETE and MKDIR files on a remote FTP server.

The GET, PUT and APPEND options use msg.filename (the path/name of the file on the remote machine) and msg.localFilename (buffer or the path/name of the file on the local machine - i.e. the one running NR)

Thanks, the photo/image sits on a remote FTP server that I want to bring back locally to Hassio/PI to then display the image.

Its a remote 5g ESP SIM with a serially attached ESP32CAM with a wide angle acting as a alarm, shake, PIR, temp and takes a photo when triggered the uploads to a remote externally hosted FTP server. For security reasons best to have a local copy of the image rather than just the FTP version.

Ah now I understand better. Since your FTP-in node is running in the Node Red add-on, it will have to use folders visible to the add-ons container. So use “/media” instead, as that is local to the container. I’ve not used this node before, but since it says “Local Filename” it might not like being given a folder, so you may have to put in “/media/my-file.jpg” (for example).

Can you post your flow? I’m not clear where the debug node sits - is it after an ftp node doing a list? I’m also confused why the ftp in node is producing an error about “payload[0].name” (assuming ‘List’ and ‘List’ are the same node)…

flow below minus FTP server

[{"id":"467354e6dd094a5f","type":"tab","label":"FTP","disabled":false,"info":"","env":[]},{"id":"24626896040b533b","type":"inject","z":"467354e6dd094a5f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"domain.com/Camera","payloadType":"str","x":150,"y":80,"wires":[["20526ae0a26ae312"]]},{"id":"908688915e0316a5","type":"debug","z":"467354e6dd094a5f","name":"debug 3","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":920,"y":400,"wires":[]},{"id":"b5b6413096f7a827","type":"function","z":"467354e6dd094a5f","name":"Modification time","func":"msg.payload = msg.payload.filter(f => f.type === '-' && f.name.endsWith('.jpg'));\nmsg.payload.sort((a, b) => b.mtime - a.mtime);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":710,"y":140,"wires":[["c39a2fefed02e46a"]]},{"id":"c39a2fefed02e46a","type":"function","z":"467354e6dd094a5f","name":"Get lastest JPG","func":"msg.payload = msg.payload[0];\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":920,"y":140,"wires":[["822764f7c8c60202"]]},{"id":"cb113c4c0235ae0a","type":"ftp in","z":"467354e6dd094a5f","ftp":"","operation":"list","filename":"","localFilename":"","name":"List","x":530,"y":140,"wires":[["b5b6413096f7a827","908688915e0316a5"]]},{"id":"20526ae0a26ae312","type":"change","z":"467354e6dd094a5f","name":"pay to filename","rules":[{"t":"move","p":"payload","pt":"msg","to":"filename","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":140,"wires":[["cb113c4c0235ae0a"]]},{"id":"822764f7c8c60202","type":"ftp in","z":"467354e6dd094a5f","ftp":"","operation":"get","filename":"payload[0].name","localFilename":"/media","name":"List","x":970,"y":260,"wires":[["908688915e0316a5"]]}]

The filename on the ftp node is a string, not a property on the message. In your case you need to leave that field empty and set msg.filename on the incoming message - perhaps in your “Get latest JPG” function instead of setting msg.payload.

Thanks,

this works based on some of your info, need to change it from the actual last file e,g, 181222192850.jpg to a var such as payload[0] rather than the file name.

[{"id":"467354e6dd094a5f","type":"tab","label":"FTP","disabled":false,"info":"","env":[]},{"id":"24626896040b533b","type":"inject","z":"467354e6dd094a5f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"domain.com/Camera","payloadType":"str","x":160,"y":80,"wires":[["20526ae0a26ae312"]]},{"id":"908688915e0316a5","type":"debug","z":"467354e6dd094a5f","name":"debug 3","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":980,"y":580,"wires":[]},{"id":"b5b6413096f7a827","type":"function","z":"467354e6dd094a5f","name":"Modification time","func":"msg.payload = msg.payload.filter(f => f.type === '-' && f.name.endsWith('.jpg'));\nmsg.payload.sort((a, b) => b.mtime - a.mtime);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":710,"y":140,"wires":[["c39a2fefed02e46a"]]},{"id":"c39a2fefed02e46a","type":"function","z":"467354e6dd094a5f","name":"Get lastest JPG","func":"msg.payload = msg.payload[0];\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":920,"y":140,"wires":[["92d8024d72c3ec93"]]},{"id":"cb113c4c0235ae0a","type":"ftp in","z":"467354e6dd094a5f","ftp":"e4dabfec9bae8847","operation":"list","filename":"","localFilename":"","name":"List","x":530,"y":140,"wires":[["b5b6413096f7a827","908688915e0316a5"]]},{"id":"20526ae0a26ae312","type":"change","z":"467354e6dd094a5f","name":"pay to filename","rules":[{"t":"move","p":"payload","pt":"msg","to":"filename","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":140,"wires":[["cb113c4c0235ae0a"]]},{"id":"92d8024d72c3ec93","type":"ftp in","z":"467354e6dd094a5f","ftp":"e4dabfec9bae8847","operation":"get","filename":"domain.com/Camera/181222192850.jpg","localFilename":"/media/camera/181222192850.jpg","name":"List","x":890,"y":300,"wires":[["908688915e0316a5"]]},{"id":"e4dabfec9bae8847","type":"ftp","host":"0.0.0.0","port":"21","secureOptions":"","user":"FTPuser","connTimeout":"","pasvTimeout":"","keepalive":""}]

Need or want to display the last file picked up, ideas?

This works.

Store from NR to /config/www/camera/CamImage.jpg as NR has access to this folder.

[{"id":"467354e6dd094a5f","type":"tab","label":"FTP","disabled":false,"info":"","env":[]},{"id":"693ccb5aebc659fc","type":"inject","z":"467354e6dd094a5f","name":"Get Image every 15 min","props":[{"p":"payload"}],"repeat":"14400","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"domain.com/Camera","payloadType":"str","x":170,"y":60,"wires":[["31ff6b36e0b622f5"]]},{"id":"db3c92f6d1276edb","type":"debug","z":"467354e6dd094a5f","name":"Debug Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1060,"y":120,"wires":[]},{"id":"7a6112c6c872a215","type":"function","z":"467354e6dd094a5f","name":"Filter by modification time","func":"// Extracts the creation time stamp from a file name in the format yymmddHHMMSS.jpg\nfunction getCreationTime(name) {\n    const match = name.match(/(\\d{12})\\.jpg/);\n    if (match) {\n        return parseInt(match[1]);\n    } else {\n        return 0;\n    }\n}\n\n// Sorts an array of file objects by their creation time stamp in descending order\nmsg.payload.sort((a, b) => getCreationTime(b.name) - getCreationTime(a.name));\n\n// Return the sorted array\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":450,"y":200,"wires":[["f1bb984e6636c890"]]},{"id":"f1bb984e6636c890","type":"function","z":"467354e6dd094a5f","name":"Get lastest JPG","func":"msg.payload = msg.payload[0];\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":440,"y":260,"wires":[["db3c92f6d1276edb","48739aa8b805ab67"]]},{"id":"31ff6b36e0b622f5","type":"change","z":"467354e6dd094a5f","name":"Move Payload to Filename","rules":[{"t":"move","p":"payload","pt":"msg","to":"filename","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":460,"y":60,"wires":[["edb48ac579207041"]]},{"id":"48739aa8b805ab67","type":"function","z":"467354e6dd094a5f","name":"Fn add remote file path + image","func":"msg.filename = \"/domain.com/Camera/\" + msg.payload.name;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":430,"y":320,"wires":[["db3c92f6d1276edb","d5c53eae596e0b98"]]},{"id":"edb48ac579207041","type":"ftp in","z":"467354e6dd094a5f","ftp":"88b86ecb9b39502e","operation":"list","filename":"","localFilename":"","name":"List","x":430,"y":140,"wires":[["7a6112c6c872a215","db3c92f6d1276edb"]]},{"id":"d5c53eae596e0b98","type":"ftp in","z":"467354e6dd094a5f","ftp":"88b86ecb9b39502e","operation":"get","filename":"","localFilename":"/config/www/camera/CamImage.jpg","name":"Get latest image","x":440,"y":400,"wires":[["db3c92f6d1276edb"]]},{"id":"3bafc7b37597d33a","type":"comment","z":"467354e6dd094a5f","name":"Details and Links","info":"","x":120,"y":400,"wires":[]},{"id":"88b86ecb9b39502e","type":"ftp","host":"00.00.00.00","port":"21","secureOptions":"","user":"FTPuser","connTimeout":"30000","pasvTimeout":"10000","keepalive":"10000"}]