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

22 thoughts on “A Node-Red Websockets Web Page

  1. Peter, I don't know if you've considered another option, talking directly to your (websocket enabled) mqtt broker using the paho javascript client.

    This was the approach my 'team' used in a challenge we entered a year or so ago.
    https://www.ibm.com/developerworks/community/blogs/9b0ad654-ff3d-4c87-bb54-867ffbdff1bb/entry/ibm_hackathon_the_great_cluster_code_off?lang=en
    We produced a video and I wrote some blog articles to accompany the challenge https://www.youtube.com/watch?v=lhD4_aNojxs , http://jekw.co.uk/2014/01/05/the-thing/ , http://jekw.co.uk/2014/01/06/arduino-code-for-the-robot-arm/ and http://jekw.co.uk/2014/01/12/node-red-flow-for-the-robot-arm/

    The thing that may interest you the most is the html control app that you can get from http://gcco.jekw.co.uk/mostly_armless_webapp.zip.

    A handy side effect of doing it this way is that if the mqtt messages are published 'retained', as soon as the app connects and subscribes it is sent the latest status messages without requesting them. The control buttons could then be enabled/disabled based on that status e.g a light is on, only enable the off button.

    Jim....

    1. Do let us know when you get it working with Node-Red. On the surface it seems overy complicated considering you could make that from DIVS with one of the CSS frameworks I can't remember the name of but which re-arranges blocks... and although I'm a great Microsoft fan I really do not like their new blocky interface, seems like a backward steep.. still - as I happen to have a spare Nexus 7, Node-Red or indeed MQTT integration would probably make that worth investigating!

  2. Peter, you mentioned: "f you want to use in and out together you need to kill msg._session in the flow."
    That's only true if you want to broadcast the msg.
    From the info:"If the message arriving at this node started at a WebSocket In node, the message will be sent back to the client that triggered the flow. Otherwise, the message will be broadcast to all connected clients.

    If you want to broadcast a message that started at a WebSocket In node, you should delete the msg._session property within the flow"

    1. So... If I am simply taking the information in from the page - and sending it back to the page - do I need to kill msg._session or not (I am doing right now and all is working).

      Pete

          1. Say you have client1 and client2 both connecting to the same websocket.
            When client1 sends a message it will receive the reply if you don't kill msg._session.
            If you do, they both will receive the reply.

  3. Beware cut and paste. I read your html, thought I understood it but it would not work on my system. The cause was the difference between your pretty left and right quotes and the standard ".

    I'm guessing you did not write it that way but some "clever" system has kindly made all the quotes handed to neatly frame the quoted text.

    1. Hi Bruce

      Right - I have tried my damnest to get a syntax highlighter plug-in working on this self-hosted WordPress - and they just don't work - they either won't play with Live Writer or if I put a decent editor in the blog they won't work with that - so as of the last blog you'll see I've included a link to GITHUB. So the plan is I've a repository called VARIOUS (under scargill) and I'll just put code snippets in there and link to them - so although the embedded code (needed really for the flow of explanation) might have those daft special quotes, the GITHUB won't. While I'm on I'll see if I can find a special quotes remover. Anyone any ideas on this please fire away but don't ask me to abandon Live Writer.

        1. I wonder if you can help here... having introduced the idea of Gists.  One of the options there is to actually embed a github item rather than a Gist  (same technology) so on the blog I've embedded  a page called blog2.html - and thats' fine - that works a treat.. but I noted despite linking to the latest page ie master/blog2.html if I update that page on Github and refresh the blog web page - the latest version does NOT come through - its' as if it is buffered somewhere.. Have you had experience of this - and the actual Gists - do they do the same thing?

  4. I realy love your blog, very informative.

    However, I did run into some issues:

    1. The dreaded " and ' signs (needed to replace all, was a real pain).

    2. I did not see this mentioned, I used bluemix node red, and your code did not work for me.

    From this code: http://flows.nodered.org/flow/d7a45e7e693f43c9d47b I saw that nowhere did he add the 1880 port number to any url.

    After I removed the :1880 from everywhere things started to wrok.

    Very nice indeed.... 

    Thanks you sir!!!

    1. I am hoping that I've just fixed that awful quotes issue - I added CKEDITOR to the blog in the hope it would give you guys a little extra control over output (colour etc) and it seems to have brought some purist nonsense about the use of quotes with it. I have turned of a setting called HTML ENTITIES in the hope that this fixes the issue, if not the editor is coming out. Please let me know if you continue to have issues.

  5. I decided to play a bit with websockets and I'm stuck.

    Basically I can't connect to the websocket.

    Basically I add 2 nodes, a websocket input and an output and I connect these two, and I set them as:
    Type: Listen on
    Path: /myapp where I have it to send/receive payload and not the entire message

    When I make an html page and load it, I get a "not connected" message that then turns into a "status unknown".

    I tried the example from the part 2 as well, I placed the 2 inject nodes and connected them to the websocket output, then connected a debug node to the websocket input. When I press the inject nodes nothing comes out to the debug node.

    As if the two websocket nodes are not connected at all.

    Any ideas what is wrong?

    I know this is pretty basic, but I can't even make this work.

  6. Hi Peter,

    Firstly, thanks for taking the time to document your adventures with the ESP8266 and MQTT + Node-Red !

    I'm having a play with the same technologies and love the speed that projects can be put together using the 8266 and MQTT/Node-Red.

    Like yourself, I'm running the Mosquitto broker on my Synology NAS and this evening I've got Node-Red running on it too. It took some head scratching but nothing too heavy duty and now the broker and Node-Red are co-located then I'll benefit from the NAS resilience and also low network latency.

    Cheers!

    Andy.

    1. Excellent Andy - pleased to hear that - I'd like to get MQTT+PHP+NODE-RED running on the NAS but I don't find it as easy to use as a normal Linux box or a Raspberry Pi but I too have MQTT running on my NAS and it has been very reliable. Thanks for the feedback - enjoy - and remember to check in here next week as I'll be wandering around the stands at FAB11 Boston looking for new and exciting ideas.

Comments are closed.