Node Red Initialisation

This is a post from back in March 2017 – but as I’d forgotten all about it, I thought you might like to share my renewed enthusiasm if you are a Node-Red user.  NR introduces non-volatile flow and global variables in version 0.19 but if that doesn’t work for you, well there is always this:

There have been various conversations about Node-Red initialisation of variables recently. Here’s a solution.

So firstly – what’s the problem? Well, because of the asynchronous nature of Node-Red, it seems to be that sometimes you find yourself using a global variable before it has been defined. No lectures on using global variables please. I can see in my own systems, in the log, incidences of uninitialized variables.

My own solution to the issue of non-volatile storage has been to save global variables as a single object, into a file – and restore said on power up (thermostat settings etc.) – you could store them in MQTT, in a database, anywhere – doesn’t matter. The issue is restoring them.

On power up one assumes the left most tab in Node-Red will run first and that is generally true – but where anything asynchronous is happening – like getting a file for example (hint) there could be delays and other code could run using one of your variables before you’ve actually set it up. This usually does NOT result in Node-Red crashing but you can get rubbish results. Of course you can check every time you use a variable if it exists but that can get messy REAL quick.

A conversation started in the Node-Red discussion groups recently – one of many – and I just latched onto an idea and ran with it.  Of course my first few attempts resulted in suicidal feelings as they failed time after time – but just mid- morning it all started to come together.

So, first things first – the Node-Red settings.js (created when Node-Red is installed and could be for example at /home/pi/.node-red/settings.js)  file runs BEFORE Node-Red comes online – so you know that if you initialise stuff in there, it will be set up in time for you to use – but messing with that file from within Node-Red could be dangerous and you could kill the whole installation. It also  defeats the object of having everything in one nice visual interface.

Here’s another way

Within settings.js there is “functionGlobalContext” which sets up any globals you might need for example – fs object for using files. Here is that section (typically) with one line added into settings.js

functionGlobalContext: {

os:require('os'),

moment:require('moment'),

fs:require('fs'),

mySettings:require("/home/pi/.node-red/redvars.js")

    },

See that last line with “mySettings” –  you can call that what you like.

In (for example) your /home/pi directory, create a simple file called redvars.js (or anything you like really). In there you could put this..

and thanks to Nick O’Leary for the specifics…

module.exports = {

    "fred": 1,

    "brian": 2

}

However, what happens if the redvars.js file is corrupt for any reason – answer? Node-Red crashes..

Here then is a better way:

At the VERY START of setting.js add this..

var mySettings;

try {

mySettings = require("/home/pi/.node-red/redvars.js");

    } catch(err) {

mySettings = {};

    }

So mySettings is either populated or made empty. No crashing. Now you only need to add ONE line to the functionGlobalContext – here it is in my case… yours might be different…

functionGlobalContext: {

os:require('os'),

moment:require('moment'),

fs:require('fs'),

mySettings:mySettings

    },

As you can see, with an additional comma then one line, a foolproof version of mySettings has been added.

Run Node-Red and you will now find that (for example)  global.get(“mySettings.fred”)  returns 1.  SO – now all you have to do is to put what you need in that file redvars.js – and if you need to update them you can do that within Node-Red.

In my case I have a variable called counter in there.   Every time I update something, I update that counter to 10;   I have a little timer job running that checks that var and if not zero, decrements it – if it is now zero, it updates the file… see how I did that below.

If you look at my original article on this subject – all seemed well, simply stringify the object and save it to disk – and that’s really how I’d like it to be – but my mechanism for RETRIEVING the object on power-up failed miserably because of the async nature of the file read – often resulting in use of the variables before they existed. This way, that won’t happen and all it needs is to stringify the object and add “module exports-“ at the start.

In the unlikely event that the redvars.file is corrupt, on power-up, mySettings will be undefined – easy to check and if necessary overwrite.

So one simple change on initial setup of Node-Red – and from there on you can create or amend non-volatile global variables from within Node-Red.  You could expand on this of course – that is up to you.

Update 26/03/2017 – This modification is now in the script!

16 thoughts on “Node Red Initialisation

  1. just a weird observation.

    After attempting to flash Tasmota on my 13th Sonoff [12 others flashed fine] with a new USB/serial 3.3 volt converter, my laptop refused to recognize the USB comm port after a few “failed to connect” messages. Win 7 machine.

    Then the next morning my Laptop HD refused to boot [even the recovery partition failed].

    So now the weird part. I am using a DVD version of Linux Mint to see if I could live in the Linux world, running on the defective laptop and a few minutes ago I entered the IP of my Node-Red Raspberry Pi and got a splash screen “Pete’s Utilities” which I had never seen before. Node-Red still works perfect but just wondering why this splash screen appeared.

    1. that page is on port 80 (apache, now caddy, too) from months, while nodered is on port 1880… we created that so you don’t have to remember every service port, but needs updates to add grafana and other newer additions to the script…

      1. Thanks my friend. Just surprised to see it as I know I typed in just the IP address a bunch of times last week without any port#.

        This is all great stuff.
        Cheers.

    1. Until you mentioned that, Gary, I’d forgotten that was on the cards – so I went off to the Node-Red site to look for “persistent global variables”. User guide – working with context. It IS there, sure enough and that’s good – clear as mud to me but I guess it’ll sink in eventually. One of my few gripes about NR has always been initialisation. Hopefully with file-based persistence that will be history – what do you reckon?

      1. It’s a great step forwards for the usability Pete, although I did get around it by using a database for a while, now if they get your colourwheel sorted…………….. 🙂

        1. That’s not looking like a go-er Garry – they are stuck using Angular components and the author of that wheel isn’t interested, apparently. The discovery I made yesterday 0 iro.js – truly looks lovely but doing anything with it could be troublesome – especially bringing it into NR… I have it running stand alone in my NR PUBLIC folder but I can’t even effect changes right now other than to stop it working. Ah, well, for a moment…

  2. Hey Peter. I took a look at this and looked in my /home/pi/.node-red folder and created your sample file (redvars.js). I then went into the settings.js, and uncommented the section for ‘functionGlobalContext’, and added the mySettings:mySettings to it. Restarted Node Red (rebooted actually,) and added a function node and added simply: var fred = global.get(“mySettings.fred”); return msg

    But I get the error: SyntaxError: Invalid or unexpected token.

    Am I missing something? I am using your version of “the Script” and verified that your ‘mySettings’ is defined in settings.js as you explained above. So not sure why this is failing.

  3. Hi Peter!
    Please do you have a sample from using the “node-red-contrib-google” node for speech API on the node-red? thanks a lot! Linda

  4. Not relevant to this post but…..
    Can anyone tell me where to find the logs created eg

    console.log(“buf[“+i+”] = “+buf[i]+” = “+buf[i].toString(2)+” b”);
    thanks
    John

  5. Hi Peter
    Very good idea! I used your newest script and created a file called redvars.js with a copy-paste content of your “fred – brian” example above. I had to place the file in the node-red folder (not in the /home/pi directory). But still, I cannot access the variable with the statement
    var over=global.get(‘mySettings.fred’);
    node.status({fill:”blue”,shape:”ring”,text:”Override: “+over});
    I always get: Override undefined. Where is my mistake?

Comments are closed.