The Design

Since one of my goals is to force myself to use Node-Red, I have to work inside the parameters of Node-Red. While I am at it, I want to make something practical, so I am going to write this as being more module so that I could isolate the Edison from the real world. Lets start with a block diagram.

Block diagram: User Interface

Now let me tell you what is happening:

  1. Node-Red is running on the Edison, I call it Eddy2.
    1. This has access to the GPIO
    2. Exposes the GPIO to websockets (WS) and MQTT
    3. Logic to control GPIO without consulting outside sources, but could take input from outside sources. Example right now is if you touch the touch sensor or push the button, the LED lights up. But in the future there could be input via a WS or MQTT that says if the LED is locked out.
    4. Could also use Node-Red as a MQTT to WS bridge.  In the past I have found this to be difficult with Mosquitto, a MQTT broker, as it has to be compiled from source and causes the Mosquitto server to become unstable.
  2. The LCD Node will be a node process that will get messages to be displayed on the LCD.
  3. Web Interface Node will be running Express to be a web server
    1. Receives and sends WS messages from Node-Red
    2. Serves the Web Interface (HTML and Javascript) to the client
    3. Provides Socket.io to the client for two way messages

 

All of this adds a layer of complexity to the stack, but I think it will be the best solution. Other options that I could have used and why I did not (still could if needed):

  1. Node-Red does all the functions
    1. I have a demo of Node-Red on the Edison running Socket.io and has a chat client and serving the web page, so I know it is all possible, but...
      1. When changes happen in Node-Red with WS and Socket.io, I have found that the sockets are delicate and do not re-connect or the client crashes.
      2. Editing HTML and Javascript in Node-Red is not the best.  This is not a problem when the product is stable.
    2. Scalability: If I add a second PDU or additional controls and I want them all in one interface, then Node-Red would need a bridge to talk to other bridge.
    3. Exposure: If needed I can add a layer of security by moving the node web interface to another device and not expose the PDU Edison to the world
  2. Run all Node.  This would be simpler and something I understand much better, but I need to push myself and use Node-Red.

 

 

Proof Of Concept

Lets make sure this is going to work before we get to far down the road. To start with, I want to do a proof of concept that what I layed out above will work.  Will WS messages be received, formated and sent out via Socket.io? I have never tried that before, I have done abstract layers using all Socket.io and this is simple and works well, but I have never even worked with WS before.  I did some experimenting with WS and Node-Red.  I created a topic for the temperature data to be sent out via a WS of /ws/temperature and used "wscat -c eddy2:1880/ws/temperature" to watch the data being sent out and it worked. Then I created more sockets with the same name and could not get them all to work, so I pounded my head against the wall until I decided they needed new names. So I create /ws/led1 and I hook it up to the light output, us wscat to send messages of 0 or 1 to turn the LED off or on. Then I graduate to testing with node and replicate the same results.  This is good.  (More about wscat at the bottom of this BLOG entry)

 

So now to build my POC to make sure information can flow from start to end nicely.  The following diagram show how I plan to do the POC.  Node-Red will have three items that the information from them will be passed to the web interface. These are the temperature sensor hooked up to A0, touch sensor hooked up to D3, and the button to D4.

POC Diagram

First of all here are two shots of the Node-Red flow:

NodeRed1.pngNodeRed2.png

 

There is both WS and MQTT there.  I have been testing with both and both work great.

 

Full code is referenced below, but here are some examples of converting from WS to Socket.io.

 

Setting up WS in node:

const wscTemperature = new WebSocket('ws://192.168.2.138:1880/ws/temperature');
const wscButton1 = new WebSocket('ws://192.168.2.138:1880/ws/button1');
const wscTouch1 = new WebSocket('ws://192.168.2.138:1880/ws/touch1');

 

Now when message come in on wscButton1, display it on the console of the server, and then emit it via Socket.io with some formatting. Exact same thing with the touch sensor data.

wscButton1.on('message', function(data,flags) {
        console.log("Button1 is: " + data);
        io.emit('eddy2', {
            event: 'Button1',
            value: data
        });
    });

 

Temperature sensor takes in the raw analog data and outputs the temperature in Celsius and Fahrenheit, like this:

wscTemperature.on('message', function(data,flags) {
        console.log("Data: ",data);
        let a = data;
        let B = 4275;
        let R = 1023.0/a - 1.0;
        R *= 100000.0;
        let temperature = 1.0 / (Math.log(R / 100000.0) / B + 1 / 298.15) - 273.15;
        let tempC = Math.round((temperature*100))/100;
        console.log("temperature: ", tempC);
        let tempF = Math.round((temperature * 9 / 5 + 32) * 100) / 100;
        console.log("or "+ tempF + " F");
        io.emit('eddy2', {
            event: 'Temperature',
            value: a,
            cel: tempC,
            far: tempF
        });
    });

 

On the web interface there is some javascript to bring connect and listen for Socket.io messages and then update the DOM with that data.

$(function() {
    var socket = io();

    socket.on('eddy2', function (data) {
      addChatMessage(data);
        console.log(data);
    });

});

function addChatMessage (data, options) {
    switch (data.event) {
        case "Temperature":
            $('span#tempC').html(data.cel);
            $('span#tempF').html(data.far);
            break;
        case "Button1":
            var button = "Off";
            if (data.value == "1") button = "On";
            $('span#button1').html(button);
            break;
        case "Touch1":
            var button = "Not Touched";
            if (data.value == "1") button = "Touched";
            $('span#touch1').html(button);
            break;
    }
}

 

 

I have put together a short, simple video using the code above to demo the proof of concept works:

 

What's Next?

  • Sockets flowing back to Node-Red and the Edison. Maybe control the LED and a relay via Sockets and MQTT
  • LCD Node controller to be able to send messages from Node-Red
    • Node-Red gets a message from either a sensor input, MQTT, or WS and sends a message to the LCD
    • Mine information in Node-Red as information to be displayed
    • Alerts and alarms with color
    • Maybe this information and color can also be displayed on the web interface
  • Initial state on page load.  I think this will consist of storing this information in Node-Red or reading the state of GPIO
  • Pretty up the web interface

 

References

  • I used wscat and I found it to be a great tool. If you want to try it, it is easy to install and use.
    • To install type "npm install -g wscat"
    • To use it is just "wscat -c server:port/path/topic"
  • Full code including all the Node-Red flow can be found at this Github repo.