Category Archives: JSON

Node Red Initialisation

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!

Facebooktwittergoogle_pluspinterestlinkedin

A Node-Red Websockets Web Page

Updated 26/04/2015

I’ve been after this ever since I discovered Node-Red.. and right up until this yesterday I was tearing my hair out – having settled for NETIO as my interface of choice and constantly being annoyed by the slow pace of progress with this interface.

So what is this all about? At the end of this, if you don’t know how already, you should be able to put together your own mobile friendly web page which will talk to Node-Red and from there to and from whatever other gadgets you wish.

So what is involved?

Well, you need Node-Red to listen to incoming websocket requests and to be able to respond… that and a web-browser for now is ALL you need. You do NOT need (though you could use) the whole web server structure).  In my case, Node-Red on a Raspberry Pi – that’s it.  The PURPOSE for me at least is to control stuff by MQTT but I’ll not cover that here as I’ve talked about it elsewhere and that too can be handled with ease in Node-Red.

So in my case this is running on my Raspberry Pi locally but it doesn’t have to be – that’s just what I’m using for testing. What you see here above are three standard node-red nodes.. a websocket input – a function (DIY info) node and a websocket output.

Aside from giving them meaningful (or otherwise) names the only thing you need on the websocket bits is the URL. Any URL within reason staring with /.  I used /myapp but something more meaningful would be better. This is NOT the address of your web page – this is the address of the websocket connection. Read on.

Simple WSWhen you hover over the Websocket input  in Node-Red editor,  there’s a mention in the INFO box about killing msg._session in the flow. That meant nothing to me until one of my readers set me straight.. but it’s very simple in the example above, any information coming in from say a browser will be sent back out (second block market “ws out” to th same browser.

That’s it. Anything coming in to the websocket input node goes out of the websocket output node to the same browser but not another browser looking at the same page.

node-red websocketsThis version however with the function in the middle with nothing more than…

msg._session="";
return msg;

 

The information above kills the session info needed to lock down a given session so that in this scenario one browser may send a button press causing an action – and that will also be sent to any other browser looking in… as you can imagine a one-to-one chat window becomes… trivial.

So all we need now is a web page that will connect to this websocket  - one which can send information to Node Red and also receive information.

I wanted a simple test web page to have a field that I could fill in – and a submit button that would send information to the websocket without all that refresh stuff and which would return the information to the page. Clearly one can to things with that info as it passes through the middle orange function block if present (passed in msg.payload).

It is very convenient to have everything in Node-Red and it is perfectly sensible to have it serve up the web page AS WELL as handling web sockets….

node red sockets and web page

Note the addition of the bottom three boxes (see above, “kill session is not necessary unless you want to broadcast any changes to all browsers looking in – but you may want to use that block for something else – like handling traffic passing through from the web page and back to it).

For the web page itself, these are http, template and http response blocks respectively. The left most simply needs a URL – I’ve called it /testing  and a useful name - the rightmost needs nothing but a useful name.. the middle block contains a bog-standard webpage of your design – and within that the websocket connection.

Pretty basic but that’s the idea. No need to even construct a web page – the html and js can all sit in the block marked “html+js”.

My internal address is 192.168.0.15, unlike a normal web page, the pages you serve in here are on port 1880 by default so the internal address for this page would be http://192.168.0.15:1880/testing

Simples.

But herein lies the rub.. what if you want folders (css, images etc) – where would you put them?   I chose instead as I already had Apache web server running on the Pi to put my PAGE there instead. There is also the point that basic page security is easy to implement on Apache.

So – there are examples out there of a simple web page, there are other examples of mobile web pages – and even more of simplifying normal Javascript using JQuery (which is wonderful) and I guess all I’ve done here is merge all of this into a useable if trivial page for the purposes of demonstration. I could have complicated things by requiring loads of libraries, filling it up with images etc but I wanted to keep is simple and as you have to be online for this to work I figured I’d simply link to the popular CDNs.

So – I wanted a responsive design that would work well on the mobile phone and look nice, be expandable with ease – and that comes from the combination of JQuery and  JQuery mobile. In total we’re looking at no more than 4 lines of includes at the top of the web page to achieve all that.

As the web page and socket are on the same machine that simplifies the address link for the websocket – and so what you see in the code generates this page on first use. You are seeing this screenshot from a Google web browser but the phone image looks pretty similar without all that Google guff at the top.

 

web page[4]

Remember this is just for demonstration but I think you’ll agree it is quite clean. So what you’re looking at is default information in a web page. The page is connected to the websocket – just just does that – and it reconnects if you stop the socket for any reason and restart it. IT has a field that says “!empty!” – nothing special – just default text. .. and 0 – again just default text.  Notice the input box, the slider and the button.  I’ll put something in the input box and move the slider – which is just a test pretending I’m injecting temperature info. I decided for the purpose of this test to keep the traffic down and have the slider not return anything until you hi the button.

Test page view 2

and when I hit the Update button –

test page image 3

As you can see the info I sent out has gone through the websocket connection (and hence you can do something with it…. I made the individual form items into a JSON string (simple – see the code) and sent it off – it came back in – I used JSON.parse function to split them apart and JQUERY to dump the values back into the page.

There are of course a million ways to do this – mine is just one – but it looks nice and is very responsive. My thanks to the various bits of code, to the people who wrote the JQUERY libraries and the help I’ve had from the Node-Red guys for helping me get this far.

At this point of course, expansion is so easy… the code can be tested in an html visual editor – or just a local web page and NotePad++ and developed ad-infinitum. For sliders, buttons and a whole lot more – take a look at JQuery Mobile.  – the flip-switches look good too.

Colours? Try the JQuery Mobile Theme Site.

Colours?Colours

I’ve not quite figured out how to add the colours in given that everything is running in a box…. but that’ll come soon enough.

Here is the code. By the time you read this it will likely have morphed into something altogether more elaborate so I figured I’d put it in here before I get carried away. I’ve deliberately expanded the vertical spacing to chop this into blocks for you. Go through it slowly – it really isn’t that hard. The links below show the latest JQuery Google CDNs but if you don’t like Google there are many others.

<!DOCTYPE HTML>
<html>

    <head>
        <title>Simple Display</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.js"></script>
    </head>

    <script type="text/javascript">

        var server = window.location.hostname;
        var topics = {};
        var wsUriC = "ws://"+server+":1880/myapp";
        var ws;
        function wsConnectC() {
            console.log("connect",wsUriC);
            ws = new WebSocket(wsUriC);
            ws.onmessage = function(msg) {
                var line = "";
                console.log(msg.data);
                var fromPage=JSON.parse(msg.data);
                if (fromPage.part1!="") $("#part1").html(fromPage.part1); else $("#part1").html("!Empty!");
                $("#part2").html(fromPage.part2+"c");
            }
            ws.onopen = function() {
                $("#status").html("connected");
                console.log("connected");
            }
            ws.onclose = function() {
                $("#status").html("not connected");
                setTimeout(wsConnectC,1000);
            }
        }
       

    function sendMessage(){
    // send message back to page in simple JSON format
    // example {“part1”:”Hello”,”part2”:”50”}
    var toPage='{"part1":"'+$("#txtMsg_1").val()+'","part2":"'+$("#slider_1").val()+'","part3":"3"}';
    ws.send(toPage);
  } // end sendMessage
 
    </script>

 

<body onload="wsConnectC();" onunload="ws.disconnect;">
<div data-role="page" id="one">
        <div data-role="header">
            <h1>Websockets Test Page</h1>
        </div>
        <div role="main" class="ui-content">
            <h1>Temperature Display</h1>
            <div id="status">status unknown</div>   
            <input id="txtMsg_1" />           
            <div id="part1">!Empty!</div>
            <hr/>
            <div id="part2">0</div>
            <hr/>
            <label for="slider_1">Input slider:</label>
            <input type="range" id="slider_1" value="60" min="0" max="100"  />
            <input type="button" value="Update" onClick="sendMessage()" />
        </div>
    </div>
    </body>

</html>

See next blog item– Websockets Web Page part 2

Facebooktwittergoogle_pluspinterestlinkedin