Node Red - Write file data into Pac write node

I tried to create a backup and restore on groov view using Nodered. I used pac read node to get data from the float table and the write node to write into a USB stick as a txt file. When I tried to read the file and write into pac it shows -

Status code 301. HTTP response error: 301

Can anyone advise me on this? I am new to NodeRed

Hi Naren, welcome to the forums.

Can we break things down a bit to start…
Lets just start with reading the the PAC Control float table for a start.
(Also, lets leave out groov View since I don’t think it has anything to do with what you are trying to do?)

Put an inject node down, then a pac read node and then a debug node.
When you click the inject it will do a read of the float table and the debug will show the data.
Make sure you set the debug node to show the full output, not just msg.payload.
Some screen shots of these three nodes and the debug tab will help us help you.

If we break it down like this then we have a better chance of getting your whole task running bit by bit till we find the error.

Thanks Beno for the reply. I tried debugging found out that I entered ip address for host where I was using local host to get the values. Now I am able to get the values.

I will explain my idea of this node. Currently I need to backup and restore variables, tables in pac control. Something similar to backup and restore on pac display. Currently I am able to get float table from pac control using read pac node and moved to file using write file node as txt file. As I am new to node red and Java script. I don’t know how to get multiple array table from pac control and store them into one single txt file.
For restore I am looking to grab all saved variables from txt file and over write in pac control.
Sorry for the huge explanation. Thanks in advance.

In groov view I am planning to have button called backup and restore which will be tied up to nodered to do function.

Glad you found the IP address typo.

Is there a specific reason you are wanting to put different tables into one text file?
What are you doing to do when you need to go from the one text file back to different tables?
How are you going to know where in the one text file that each table starts and stops?
If you write each table to its own file, it will be a lot easier to restore?

Since you just seem to want to do a backup and restore, have you considered using the optotagpreserve utility?

https://opto22.com/support/resources-tools/downloads/optotagpreserve

I run it from Node-RED every day and before and after a I do a firmware update.
Might that do exactly what you are looking to do?

Currently, I have a project which is climate control. Where it gets input as temperature and humidity. I used pac control to program and groov view as HMI. This climate control has 10 different start times, stop times, and various other set points. Once the user has entered those values. If the user wanted to preserve those data he wanted to backup the file. So I thought of gathering all data from Pac control and storing it as text. If each table has its own file will not the user seem to be overwhelmed by it? As the user is from a university and they do research on this climate control and they do data gathering with different setpoints for temperature and humidity. optotag preserve is something I never heard of. Maybe I think that might help me out in this application. In simple words, i just wanted to store all the tags in the strategy and restore it later.

This optotagpreserve is windows based application right?! What if the user uses only web-based hmi like groov view (Which I am currently working on) Will this optotagperserve work on that or node-red without using a computer? The pac control is only used at the time for uploading the strategy to the epic. Once it is uploaded the epic controller is standalone. Where I made groov screen on epic touch screen. The project I am working on is completely web-based (Only Groov). No Windows application or any computer or pc is installed at the customer’s place.

Sorry, I was under the impression that you had a Windows PC in the mix.

Back to Node-RED and groov View on EPIC then.

One button in groov View (for the operator) for back up and one for restore.
Node-RED will then back up each PAC Control table to a file and restore from each file to each table.

Using the same method as you did to find the issue with the saving (ie, three basic node flow), do the same now for writing.
Then do the same for restoring.
Then finally join the three together as needed with groov View.

(Please keep this thread going vs emailing me - its going to be really helpful for everyone going forward and pretty soon others will chime in with their thoughts).

Yes, of course you can merge all the tables together into one file.
Take a look at the file write node properties, notice one of the options is append to file, so you just tick that and write each table to the same file… BUT…

When the operator wants to restore his settings and clicks the button in groov View to do that, how are you going to program Node-RED to sift through that one big file and find all the table breaks and load just the right number of indexes to each and every table?
That sounds a LOT more work than simply having a file for each table. Easy in and easy out.

Whats your objection to having one button fire off saving each table to its own file?

Having all tables and variables get saved to different files will make the programming lot easier. I have working node till this point. Current I backup all the tables and variables into different files. But as a end user they might have multiple different files. Chances of losing files or files getting corrupt might be higher ?!

One click button saves all the data into file.

Finally was able to create a backup and restore file by storing all tables in json format.
Thanks, Beno for helping me out.

[{"id":"c3dcf24229af0667","type":"tab","label":"Flow 1","disabled":false,"info":"","env":[]},{"id":"e37de5e27a13976b","type":"file","z":"c3dcf24229af0667","name":"Backup","filename":"/home/dev/secured/backup.txt","filenameType":"str","appendNewline":true,"createDir":false,"overwriteFile":"true","encoding":"none","x":1060,"y":740,"wires":[[]]},{"id":"08d0e214ecfa8440","type":"pac-read","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"int32-table","tagName":"uiScheduleHumidControl","tableStartIndex":"","tableLength":"","value":"","valueType":"msg.payload","topic":"ScheduleHumidControl","topicType":"user","name":"ScheduleHumidControl","x":570,"y":660,"wires":[["617ff8e95cb4f8b8"]]},{"id":"ab97fb905c405a58","type":"pac-read","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"float-table","tagName":"uiScheduleHumidityDB","tableStartIndex":"","tableLength":"","value":"","valueType":"msg.payload","topic":"ScheduleHumidityDB","topicType":"user","name":"ScheduleHumidityDB","x":560,"y":700,"wires":[["617ff8e95cb4f8b8"]]},{"id":"e7fcf22ab15b8e40","type":"pac-read","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"float-table","tagName":"uiScheduleHumiditySP","tableStartIndex":"","tableLength":"","value":"","valueType":"msg.payload","topic":"ScheduleHumiditySP","topicType":"user","name":"ScheduleHumiditySP","x":560,"y":740,"wires":[["617ff8e95cb4f8b8"]]},{"id":"5c23ea24f9f0c425","type":"pac-read","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"int32-table","tagName":"uiScheduleLightControl","tableStartIndex":"","tableLength":"","value":"","valueType":"msg.payload","topic":"ScheduleLightControl","topicType":"user","name":"ScheduleLightControl","x":560,"y":780,"wires":[["617ff8e95cb4f8b8"]]},{"id":"90e0a66aa615352d","type":"pac-read","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"int32-table","tagName":"uiScheduleLightOnOff","tableStartIndex":"","tableLength":"","value":"","valueType":"msg.payload","topic":"ScheduleLightOnOff","topicType":"user","name":"ScheduleLightOnOff","x":560,"y":820,"wires":[["617ff8e95cb4f8b8"]]},{"id":"313fc1b557b1eb0e","type":"pac-read","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"int32-table","tagName":"uiScheduleTempControl","tableStartIndex":"","tableLength":"","value":"","valueType":"msg.payload","topic":"ScheduleTempControl","topicType":"user","name":"ScheduleTempControl","x":560,"y":860,"wires":[["617ff8e95cb4f8b8"]]},{"id":"9a710da3f4e60f7b","type":"pac-read","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"float-table","tagName":"uiScheduleTempertureSP","tableStartIndex":"","tableLength":"","value":"","valueType":"msg.payload","topic":"ScheduleTempertureSP","topicType":"user","name":"ScheduleTempertureSP","x":570,"y":900,"wires":[["617ff8e95cb4f8b8"]]},{"id":"5b2cac933bef8330","type":"inject","z":"c3dcf24229af0667","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"combine","payloadType":"str","x":240,"y":860,"wires":[["08d0e214ecfa8440","ab97fb905c405a58","e7fcf22ab15b8e40","5c23ea24f9f0c425","90e0a66aa615352d","313fc1b557b1eb0e","9a710da3f4e60f7b","cd8edce43be66323","232a85f6b98aaa6a","296d858cc05de02e","77d3b5971c98952a"]]},{"id":"919252b18b051d1c","type":"delay","z":"c3dcf24229af0667","name":"Delay to Allow All Data","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":940,"y":860,"wires":[["90094118de1e9975"]]},{"id":"90094118de1e9975","type":"function","z":"c3dcf24229af0667","name":"Prepare Data for Writing","func":"// Initialize accumulatedData if it doesn't exist\nif (!flow.get(\"accumulatedData\")) {\n    flow.set(\"accumulatedData\", {});\n}\n\nvar accumulatedData = flow.get(\"accumulatedData\");\nvar topic = msg.topic;\n\n// Store the payload data under the corresponding topic\naccumulatedData[topic] = msg.payload;\n\n// Update the accumulated data in flow context\nflow.set(\"accumulatedData\", accumulatedData);\n\n// Check if all topics have been received\nvar allReceived = true;\nvar allData = Object.keys(accumulatedData);\nvar expectedTopics = [\"ScheduleHumidControl\", \"ScheduleHumidityDB\", \"ScheduleHumiditySP\", \"ScheduleLightControl\", \"ScheduleLightOnOff\", \"ScheduleTempControl\", \"ScheduleTempertureSP\", \"Options\", \"ScheduleFlags\", \"ScheduleStartTime\", \"ScheduleStopTime\"];\n\nfor (var i = 0; i < expectedTopics.length; i++) {\n    if (!allData.includes(expectedTopics[i])) {\n        allReceived = false;\n        break;\n    }\n}\n\n// If all topics have been received, pass the accumulated data to the next node\nif (allReceived) {\n    msg.payload = accumulatedData;\n    flow.set(\"accumulatedData\", null); // Clear accumulated data\n    return msg;\n} else {\n    return null; // Don't send the message until all topics are received\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":990,"y":800,"wires":[["e37de5e27a13976b"]]},{"id":"617ff8e95cb4f8b8","type":"change","z":"c3dcf24229af0667","name":"Accumulate Data","rules":[{"t":"set","p":"accumulatedData","pt":"msg","to":"{}","tot":"json"},{"t":"set","p":"accumulatedData[msg.topic]","pt":"msg","to":"payload[0]","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":870,"y":920,"wires":[["919252b18b051d1c"]]},{"id":"cd8edce43be66323","type":"pac-read","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"float-table","tagName":"uiOptions","tableStartIndex":"","tableLength":"","value":"","valueType":"msg.payload","topic":"Options","topicType":"user","name":"Options ","x":520,"y":940,"wires":[["617ff8e95cb4f8b8"]]},{"id":"232a85f6b98aaa6a","type":"pac-read","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"int32-table","tagName":"uiScheduleFlags","tableStartIndex":"","tableLength":"","value":"","valueType":"msg.payload","topic":"ScheduleFlags","topicType":"user","name":"ScheduleFlags","x":540,"y":980,"wires":[["617ff8e95cb4f8b8"]]},{"id":"296d858cc05de02e","type":"pac-read","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"float-table","tagName":"uiScheduleStartTime","tableStartIndex":"","tableLength":"","value":"","valueType":"msg.payload","topic":"ScheduleStartTime","topicType":"user","name":"ScheduleStartTime","x":550,"y":1020,"wires":[["617ff8e95cb4f8b8"]]},{"id":"77d3b5971c98952a","type":"pac-read","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"float-table","tagName":"uiScheduleStopTime","tableStartIndex":"","tableLength":"","value":"","valueType":"msg.payload","topic":"ScheduleStopTime","topicType":"user","name":"ScheduleStopTime","x":550,"y":1060,"wires":[["617ff8e95cb4f8b8"]]},{"id":"a1c8ad818a8b6fa4","type":"split","z":"c3dcf24229af0667","name":"Split Lines","splt":"\\n","spltType":"str","arraySplt":"1","arraySpltType":"len","stream":true,"addname":"topic","x":470,"y":1400,"wires":[["1c74eb84d6abda81"]]},{"id":"b9d59eb3d4acb4ee","type":"json","z":"c3dcf24229af0667","name":"Parse JSON","property":"payload","action":"","pretty":false,"x":350,"y":1340,"wires":[["a1c8ad818a8b6fa4"]]},{"id":"1c74eb84d6abda81","type":"switch","z":"c3dcf24229af0667","name":"Route Data","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"ScheduleHumidControl","vt":"str"},{"t":"eq","v":"ScheduleHumidityDB","vt":"str"},{"t":"eq","v":"ScheduleHumiditySP","vt":"str"},{"t":"eq","v":"ScheduleLightControl","vt":"str"},{"t":"eq","v":"ScheduleLightOnOff","vt":"str"},{"t":"eq","v":"ScheduleTempControl","vt":"str"},{"t":"eq","v":"ScheduleTempertureSP","vt":"str"},{"t":"eq","v":"Options","vt":"str"},{"t":"eq","v":"ScheduleFlags","vt":"str"},{"t":"eq","v":"ScheduleStartTime","vt":"str"},{"t":"eq","v":"ScheduleStopTime","vt":"str"}],"checkall":"true","repair":false,"outputs":11,"x":670,"y":1400,"wires":[["b9fa313578127ffd"],["1ddbdf4c2453f676"],["508c42cdbc186aa2"],["7d6f0f4b17f76d17"],["7b458ef6d7acd472"],["cb71c33204f48076"],["7e11c6f0defe1b71"],["bf9307d79af95f20"],["81687b3ca9da481d"],["3abddcb5a133bf0d"],["382a25d125933465"]]},{"id":"b9fa313578127ffd","type":"pac-write","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"int32-table","tagName":"uiScheduleHumidControl","tableStartIndex":"","value":"","valueType":"msg.payload","name":"ScheduleHumidControl","x":1030,"y":1160,"wires":[[]]},{"id":"1ddbdf4c2453f676","type":"pac-write","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"float-table","tagName":"uiScheduleHumidityDB","tableStartIndex":"","value":"","valueType":"msg.payload","name":"ScheduleHumidityDB","x":1020,"y":1220,"wires":[[]]},{"id":"508c42cdbc186aa2","type":"pac-write","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"float-table","tagName":"uiScheduleHumiditySP","tableStartIndex":"","value":"","valueType":"msg.payload","name":"ScheduleHumiditySP","x":1020,"y":1280,"wires":[[]]},{"id":"7d6f0f4b17f76d17","type":"pac-write","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"int32-table","tagName":"uiScheduleLightControl","tableStartIndex":"","value":"","valueType":"msg.payload","name":"ScheduleLightControl","x":1020,"y":1340,"wires":[[]]},{"id":"7b458ef6d7acd472","type":"pac-write","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"int32-table","tagName":"uiScheduleLightOnOff","tableStartIndex":"","value":"","valueType":"msg.payload","name":"ScheduleLightOnOff","x":1021,"y":1400,"wires":[[]]},{"id":"cb71c33204f48076","type":"pac-write","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"int32-table","tagName":"uiScheduleTempControl","tableStartIndex":"","value":"","valueType":"msg.payload","name":"ScheduleTempControl","x":1020,"y":1460,"wires":[[]]},{"id":"7e11c6f0defe1b71","type":"pac-write","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"float-table","tagName":"uiScheduleTempertureSP","tableStartIndex":"","value":"","valueType":"msg.payload","name":"ScheduleTempertureSP","x":1030,"y":1520,"wires":[[]]},{"id":"7b9674205a2c4bfb","type":"inject","z":"c3dcf24229af0667","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"combine","payloadType":"str","x":240,"y":1180,"wires":[["9ebda30bdd8fcf4f"]]},{"id":"9ebda30bdd8fcf4f","type":"file in","z":"c3dcf24229af0667","name":"","filename":"/home/dev/secured/backup.txt","filenameType":"str","format":"utf8","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":350,"y":1260,"wires":[["b9d59eb3d4acb4ee"]]},{"id":"bf9307d79af95f20","type":"pac-write","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"float-table","tagName":"uiOptions","tableStartIndex":"","value":"","valueType":"msg.payload","name":"Options","x":980,"y":1580,"wires":[[]]},{"id":"81687b3ca9da481d","type":"pac-write","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"int32-table","tagName":"uiScheduleFlags","tableStartIndex":"","value":"","valueType":"msg.payload","name":"ScheduleFlags","x":1000,"y":1640,"wires":[[]]},{"id":"3abddcb5a133bf0d","type":"pac-write","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"float-table","tagName":"uiScheduleStartTime","tableStartIndex":"","value":"","valueType":"msg.payload","name":"ScheduleStartTime","x":1010,"y":1700,"wires":[[]]},{"id":"382a25d125933465","type":"pac-write","z":"c3dcf24229af0667","device":"e2305c3c5ec2d815","dataType":"float-table","tagName":"uiScheduleStopTime","tableStartIndex":"","value":"","valueType":"msg.payload","name":"ScheduleStopTime","x":1010,"y":1760,"wires":[[]]},{"id":"d53ba4d6611fd02d","type":"comment","z":"c3dcf24229af0667","name":"Backup the variables","info":"","x":250,"y":800,"wires":[]},{"id":"8de59836c5e6f0ad","type":"comment","z":"c3dcf24229af0667","name":"Restore the variables","info":"","x":260,"y":1120,"wires":[]},{"id":"e2305c3c5ec2d815","type":"pac-device","address":"localhost","protocol":"https","msgQueueFullBehavior":"DROP_OLD"}]

Keep in mind that as your users change the table data, this flow will break in different (and fun) ways.
Also you wont need that delay node if you switch the construction from parallel as you have, to serial like this:

Its never (ever) a good idea to do parallel reads like that with Node-RED as it places a really large sudden load on the controller as it tries to do all those RESTful calls to the controller to get the data.
As the data changes, the RESTful response will change.

This post will help you with a whole bunch of resources:

Note the one comment toward the bottom that exactly replicates your setup…I have found in the past that if you fetch ‘all at once’ (triggering several PAC Read nodes at once), especially when reading tables, you can get connection errors. Daisy chaining from a single Inject node, as Beno shows in his example flow, overcame this problem.

Saving each PAC table into its own file would be another way around this issue.
Don’t forget you can use the time function to create a time stamp directory so the user knows exactly his latest data.

(Simply use your file write node vs the email one).

So, bottom line, you are very close to having things break, before you deploy into production, you really should rearrange it from parallel to serial so you don’t get any surprises down the road.

1 Like

Yes I got it. Before adding the function I was facing the queuing error on some of the pac read nodes. Will convert this parallel construction to series.