remembering the value of a global variable across deploys and restarts

750 views
Skip to first unread message

Jamie Owst

unread,
Aug 18, 2016, 2:54:43 AM8/18/16
to Node-RED
I am currently working on a project using the dashboard ui.

Basically a user can enter a value into a text input on the ui for example they type in "hello", I set this as a global variable and I use it across my flow for various functions etc. But when I deploy or restart node-red it clears the text input and the user has to type in "hello" again.

is there a way of making a global variable which remembers its value across deploys ? 

thank you for any replies in advance 

kind regards,

Jamie Owst 

Walter Kraembring

unread,
Aug 18, 2016, 3:47:20 AM8/18/16
to Node-RED


I had the similar requirement and for small data I think you could just use a file. In the pictures below I read a file holding public and private holidays from a file at deploy and it populates the dashboard if changed. If you change it from dashboard the new content will update the file. Besides I the inject node is repeating this every minute (maybe overkill). At the same time the global variable myHolidays is refreshed. (Sorry for some text in Swedish)

The sample flow

[{"id":"bef83aaa.0b9478","type":"file","z":"de348058.d0367","name":"","filename":"/home/pi/holidays","appendNewline":false,"createDir":false,"overwriteFile":"true","x":390,"y":780,"wires":[]},{"id":"d68d5518.0f51f8","type":"file in","z":"de348058.d0367","name":"","filename":"/home/pi/holidays","format":"utf8","x":390,"y":540,"wires":[["f2a38930.27db58","a6999537.607348"]]},{"id":"6f6f910b.aa1d5","type":"inject","z":"de348058.d0367","name":"","topic":"","payload":"","payloadType":"str","repeat":"60","crontab":"","once":true,"x":130,"y":540,"wires":[["d68d5518.0f51f8"]]},{"id":"f2a38930.27db58","type":"function","z":"de348058.d0367","name":"Holidays","func":"// initialise the variables if they doesn't exist already\nglobal.set('myHolidays',global.get('myHolidays')||[]);\nglobal.set('myHolidays',msg.payload.split(','));\nmsg.payload = global.get('myHolidays');\nreturn msg;","outputs":"0","noerr":0,"x":680,"y":540,"wires":[]},{"id":"3eb346a5.73b76a","type":"comment","z":"de348058.d0367","name":"Just insert all your public & private holidays. Remember to update each year","info":"Just insert all your public & private holidays. Remember to update each year","x":350,"y":500,"wires":[]},{"id":"6662bd90.120534","type":"ui_text_input","z":"de348058.d0367","group":"85f02e3a.e1017","order":1,"width":"6","height":"4","name":"Ändra dina helgdagar här. Kom ihåg att uppdatera dessa varje år","mode":"text","delay":"900","label":"Ändra dina helgdagar här. Kom ihåg att uppdatera dessa varje år","topic":"","x":320,"y":660,"wires":[["25e8e065.acf"]]},{"id":"25e8e065.acf","type":"rbe","z":"de348058.d0367","name":"","func":"rbe","gap":"","start":"","inout":"out","x":350,"y":720,"wires":[["bef83aaa.0b9478"]]},{"id":"a6999537.607348","type":"rbe","z":"de348058.d0367","name":"","func":"rbe","gap":"","start":"","inout":"out","x":350,"y":600,"wires":[["6662bd90.120534"]]},{"id":"85f02e3a.e1017","type":"ui_group","z":"de348058.d0367","name":"Default","tab":"b73d5d78.f5799","disp":false,"width":"6"},{"id":"b73d5d78.f5799","type":"ui_tab","z":"","name":"Konfiguration","icon":"dashboard","order":"1"}]







Jamie Owst

unread,
Aug 18, 2016, 4:09:25 AM8/18/16
to Node-RED
Thank you so much for this !!!!!!

Julian Knight

unread,
Aug 18, 2016, 5:37:39 AM8/18/16
to Node-RED
There is also a JSON "database" node someone contributed that can make life a little easier. You could also use MQTT with the retain flag, it should refire the message when you reconnect after a restart of NR and will be retained even if the power goes off. That can simplify your startup logic.

Csongor Varga

unread,
Dec 7, 2016, 1:44:34 PM12/7/16
to Node-RED
Hi Guys,

I had the same issue and I made some logic to store global variables to a JSON file and restore them on startup.
On top there is an inject which starts the backup. It is manual at the moment, but you can set up to trigger every hour, or daily.
Next, open up the "Prep data" function. In the second line of the code, there is a variable which lists all the variables that should be backed up separated by semicolon. I have string, boolean, integer variables. I designed the code to back them up with the type, so gets restored in the correct type.
Next, update the file name based on your setup.
The second inject triggers restore. Don't forget to check "Inject once at startup", this is manual at the moment. The rest should be straight forward. The function logic returns an array of string stating which global variable got restored.

The code handles cases when the global variable is not created, or does not have a valid value. If your global variable is set from a UI node, do not forget to add logic to update the UI to reflect the restored value.


[{"id":"43f75a01.74e884","type":"inject","z":"15e1f6a1.aeab19","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":128,"y":378,"wires":[["d547483e.775438"]]},{"id":"d547483e.775438","type":"function","z":"15e1f6a1.aeab19","name":"Prep data","func":"// global variables separated by semicolon to be saved\nvar globallist = \"btn_state;btn_time;timehour;timeminute;start;irrenable;irrdays;alert1_triggered;alert1_value;alert2_triggered;alert2_value;torrent_keywords;tonernotification\";\nvar mylist = globallist.split(\";\");\n\nvar outputs = [];\n\nfor (i=0; i<mylist.length; i++) {\n    // SQL test\n    //sql = \"INSERT OR REPLACE INTO global (key,type,value) \" +\n    //        \"VALUES ('\"+mylist[i]+\"','\"+typeof global.get(mylist[i])+\"','\"+global.get(mylist[i])+\"')\";\n    //outputs.push({topic:sql});        \n    outputs.push({ key : mylist[i], type: typeof global.get(mylist[i]), value: global.get(mylist[i])});\n}\n      \n      \nmsg.payload = outputs;\nreturn msg;\n\n//msg.payload=typeof global.get(\"torrent_keywords\");\n","outputs":1,"noerr":0,"x":321,"y":381,"wires":[["62e92b02.8905c4","2c2d4269.a876de"]]},{"id":"62e92b02.8905c4","type":"debug","z":"15e1f6a1.aeab19","name":"","active":true,"console":"false","complete":"false","x":643,"y":298,"wires":[]},{"id":"9cec5c0d.e6de","type":"comment","z":"15e1f6a1.aeab19","name":"Save global variables","info":"","x":140,"y":333,"wires":[]},{"id":"666ca426.5be96c","type":"comment","z":"15e1f6a1.aeab19","name":"Restore global variables","info":"","x":148,"y":424,"wires":[]},{"id":"8e7e958d.ce6698","type":"inject","z":"15e1f6a1.aeab19","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":119,"y":471,"wires":[["d8fa7064.9f60a"]]},{"id":"4cb14d0.afc25b4","type":"file","z":"15e1f6a1.aeab19","name":"","filename":"/home/pi/global.json","appendNewline":true,"createDir":false,"overwriteFile":"true","x":749,"y":392,"wires":[]},{"id":"d8fa7064.9f60a","type":"file in","z":"15e1f6a1.aeab19","name":"","filename":"/home/pi/global.json","format":"utf8","x":328,"y":471,"wires":[["3cdb4133.0d461e"]]},{"id":"14b4208c.99aaaf","type":"function","z":"15e1f6a1.aeab19","name":"Restore","func":"var output = [];\n\nfor (var i=0; i<msg.payload.length; i++) {\n    switch (msg.payload[i].type) {\n        case 'undefined': \n            // the global variable probably had no value, nothing needs to be restored\n            output.push(msg.payload[i].key + \" is undefined.\");\n            break;\n        case 'number':\n            if (msg.payload[i].value===\"NaN\") {\n                // there is no valid value to be restored, skip this variable\n                output.push(msg.payload[i].key + \" is NaN.\");\n            } else {\n                if (msg.payload[i].value.toString().indexOf(\".\")>-1) {\n                    // the value appears to be a float\n                    global.set(msg.payload[i].key,parseFloat(msg.payload[i].value));\n                    output.push(msg.payload[i].key + \" is restored to \" + msg.payload[i].value);\n                } else {\n                    global.set(msg.payload[i].key,parseInt(msg.payload[i].value));\n                    output.push(msg.payload[i].key + \" is restored to \" + msg.payload[i].value);\n                }\n            }\n            break;\n        case 'string':\n            global.set(msg.payload[i].key,msg.payload[i].value);\n            output.push(msg.payload[i].key + \" is restored to \" + msg.payload[i].value);\n            break;\n        case 'boolean':\n            global.set(msg.payload[i].key,msg.payload[i].value===\"true\");\n            output.push(msg.payload[i].key + \" is restored to \" + msg.payload[i].value);\n            break;\n    }\n}\n\nmsg.payload = output;\nreturn msg;","outputs":1,"noerr":0,"x":715,"y":470,"wires":[["f06e2739.a69298"]]},{"id":"2c2d4269.a876de","type":"json","z":"15e1f6a1.aeab19","name":"","x":550,"y":390,"wires":[["4cb14d0.afc25b4"]]},{"id":"3cdb4133.0d461e","type":"json","z":"15e1f6a1.aeab19","name":"","x":534,"y":471,"wires":[["14b4208c.99aaaf"]]},{"id":"f06e2739.a69298","type":"debug","z":"15e1f6a1.aeab19","name":"","active":true,"console":"false","complete":"false","x":695,"y":549,"wires":[]}]
Reply all
Reply to author
Forward
0 new messages