Tutorial: Node-RED dashboards – creating your own UI widget II (using external charts)

Creating your own UI widget for a Node-RED dashboard using an external charting library

Node-RED’s dashboard nodes provide a comprehensive set of UI components for building basic dashboards suitable for the Internet of Things (IoT) – offering graphs, gauges, basic text as well as sliders and inputs. However, there will always be situations when you need something custom. The template node is the solution and in this tutorial we’ll show you a quick example of using it to create your own UI widget.

If you want a general introduction to the Node-RED dashboard or to UI techniques for Node-RED, then check out these resources which are part of our lecture series:

The template node

The ui template node is a generic node that takes valid html and Angular/Angular-Material directives and can be used to create a dynamic user interface element.

In this example, we’ll create a simple dashboard element that displays some fake random data mimicking data from the UK’s power generation network.

The dashboard widget using morris.js

We want our UI element to look as shown on the right of the screen shot below (you can read the tutorials on how to create the Table UI widget and the 2 line chart seperately)

To build this widget, we’re going to use a 3rd party JavaScript charting library morris.js – which is simple, quite powerful, but very easy to use. It has several charts including excellent line and area charts. For this example we’ll use a donut chart since it’s not available in the Node-RED dashboard widget set.

Apart from setting up the fake data, and drawing the donut chart, two key aspects of this tutorial which are generic issues and will be needed whatever external libraries you use are:

  • loading the external libraries – and making sure they are loaded before we get started
  • watching for new messages as they arrive at the template node and using the msg.payload to update the chart.

The Node-RED flow

We’ll create a very simple flow for this example consisting of a timer to trigger action every 10 seconds, a function node to generate the fake data and the template node to display the data.

The timestamp node can be configured to fire every 10 seconds. The function node (Generate fake Electricity data) is a simple as possible. It generates a random number and then uses that as a seed to calculate fake values for the different generation types, ie Gas,Wind, Coal, Oil and Nuclear.

The fake data is dropped into the output msg.payload and sent on to the template node.

The template node is a little more complex than previous examples because we are pulling in an external charting library (morris.js) and it’s dependencies and we are writing some JavaScript code to use the incoming data (from the function node) to draw the donut chart.

The first part of the template node is fairly standard and uses script tags to define the src for the JavaScript libraries that we will be using. These are hosted on cloudflare.com or googleapis.com (they can be hosted anywhere – although if you are using FRED, you can’t store them locally).

After the libraries are referenced, we define a <div> (line 10) that is the element that the chart library will use and a simple header for the chart (line 14).

The actual javscript starts at the <script> tag at line 18 and is shown below.




There are 3 main pieces of this code -checking that the external libraries are loaded (line 20-22), the creation of the Morris.Donut object and its initialization (lines 26-35), watching for new Node-RED messages and updating the chart (lines 37-49). All of this is wrapped in a function that accesses the Angular scope for this DOM object.

Check external libraries are loaded

Lines 20-22 use a setInterval function to set up a simple repeating function that firstly checks that the external libraries are loaded. It does this by checking to see if the Morris object exists (line 21). If not the function returns and exits at line 50 where we wait (100 ms) before trying again. This simple code pattern is critical and is required whenever you use external libraries in the template node. This is because Angular is async and will happily tell the browser to start loading external libraries and then get on with running your code without waiting for them to finish loading. If the libraries aren’t loaded, the first time you try and use them you’ll get an undefined error.

Create the morris.js donut chart element and initialize it

It’s beyond the scope of this tutorial to explain the details of the morris.js library. You can check out an example we’ve written previously or the many examples available online, eg here or  donut example

However, as can be seen, line 26 creates a new instance of the Morris.Donut object. Creation requires a minimum of an element (the HTML element that will be used for displaying the donut chart) and an array of data to display structured as <label:labelname><value:actualvalue>. We create a dummy array with all values set to 1.

Watch for incoming msg.payload

To update the donut chart, we want to look at the incoming Node-RED message, and use its payload to update the donut chart. To do this, we use a watch function at line 37 to look for changes to the scope variable msg, which contains the incoming Node-RED message.

Again, the details of how Angular works is beyond this simple tutorial. A good overview is available on the Angular docs page. Briefly, Angular implements a Model-View-Controller (MVC) in which the model (the data) is separate from the view (the DOM). Controllers (code), Expressions and Directives manipulate the data which dynamically updates the view (the Dom) so you see the changes. The model is managed in a structure referred to as the scope.

So coming back to our example, the code at line 37 tells the template node to look at the scope (all our data) and watch for changes to the variable msg. When msg changes, in this case because a new Node-RED message has arrived, the function then executes (lines 38-48) and simply extracts the new data from the msg.payload and uses it to call the setData() function on the Morris.Donut object (myDonut) which dynamically updates the donut chart.

All of the above is wrapped in a function (lines 18-51) which passes the scope so that it can be accessed using the watch method.

Conclusion

Once you setup the flow, you’ll be able see the new UI element on your dashboard and as the flow triggers a new message the donut chart will update.

We’ve chosen to use a simple external charting library for this example, Morris.js – which is quite simple. However the techniques used here are the same for all external libraries so feel free to replace Morris.js with any of the many other charting libraries out there.

 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css">
 <script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js"></script>

<div id="chart-example" style="height: 250px;"></div>

<h3 align="center">UK power generation by type (in GigaWatt) </h3>

<script>

(function(scope) {
 var timer = setInterval(function() { //check that the Morris libs are loaded, if not wait
 if (!window.Morris) return;
 clearInterval(timer);
 
 var myData;
 
 var myDonut = Morris.Donut({
 element: 'chart-example',
 data: [
 {label: "Coal GW", value: 1 },
 {label: "Gas GW", value: 1 },
 {label: "Nuclear GW", value: 1 },
 {label: "Oil GW", value: 1 },
 {label: "Wind GW", value: 1 }
 ]
 });
 
 scope.$watch('msg', function (msg) { //watch for an incoming NR msg
 if (msg) {
 
 myData = msg;
 myDonut.setData([
 {label: "Coal GW", value: myData.payload.coalPct },
 {label: "Gas GW", value: myData.payload.gasPct },
 {label: "Nuclear GW", value: myData.payload.nucPct },
 {label: "Oil GW", value: myData.payload.oilPct },
 {label: "Wind GW", value: myData.payload.windPct }
 ])
 };
 }); //close out the watch 
 }, 100); // close out the setInterval 
})(scope);


</script>

About Sense TecnicSense Tecnic Systems Inc have been building IoT applications and services since 2010. We provide these lectures and FRED, cloud hosted Node-RED as a service to the community. We also offer a commercial version to our customers, as well as professional services. Learn more.

Tutorial: Node-RED dashboards – creating your own UI widget

Creating your own UI widget for a Node-RED dashboard

Node-RED’s dashboard nodes provide a comprehensive set of UI components for building basic dashboards suitable for the Internet of Things (IoT) – offering graphs, gauges, basic text as well as sliders and inputs. However, there will always be situations when you need something custom. The template node is the solution and in this tutorial we’ll show you a quick example of using it to create your own UI widget.

If you want a general introduction to the Node-RED dashboard or to UI techniques for Node-RED, then check out these resources which are part of our lecture series:

You can also check out a related tutorial that describes how to use an external charting library (morris.js) to create your own UI widgets with alternative graphs/charts.

The template node

The ui template node is a generic node that takes valid html and Angular/Angular-Material directives and can be used to create a dynamic user interface element.

In this example, we’ll create a simple dashboard element that displays some fake random data mimicking data from a factory machine sensor.

We want our UI element to look as shown on the right of the screen shot below (you can see how to create the 2 line chart in this tutorial)

screen-shot-2016-12-07-at-7-31-32-am

As you can see – our UI widget is named “and more” and has four data columns. These data column show the fake factory machine data and are dynamically updated as new data arrives.

We’ll set up a flow as shown below – the function node will generate the fake data, and the UI template node, which we name Machine status, will format and present the data in the table shown above.

screen-shot-2016-12-07-at-7-21-49-am

If we take a look inside the function node, you can see we use the usual Math.random function to generate some fake data. However, instead of just passing this data in as payload, we insert the data into a JSON structure called factory. Factory has two elements -machine00 and machine01 which in turn have four elements min, max, failProb and name.

screen-shot-2016-12-07-at-7-22-44-am

Once we have set up our function node to create the fake data. We now need to create a UI template node and set it up to display on our dashboard. As you can see below, we assign it to the Home dashboard and use a new group name “and more”. (Details on setting up dashboard groups can be found here)

screen-shot-2016-12-07-at-7-23-09-am

Let’s take a look in more detail at the HTML used to display the data we generate in the function node.

The first <div> sets out the labels for the columns defining them using the <span flex> tag so they will fit the space nicely.

<div layout=”row” layout-align=”start center”>
<span flex>RPM Min</span>
<span flex>RPM Max</span>
<span flex>Failure Prob</span>
<span flex>Machine type</span>
</div>
<div layout=”row” layout-align=”start center” ng-repeat=”machine in msg.payload.factory”>
<span flex style=”color: green”>{{machine.min}}</span>
<span flex style=”color: red”>{{machine.max}}</span>
<span flex style=”color: black”>{{machine.failProb}}%</span>
<span flex style=”color: black”>{{machine.name}}</span>
</div>

The second <div> then uses the ng-repeat command to iterate through the JSON structure in payload and display the data in the columns. It works by looking for each element named machine in the factory element. Remember, we named each set of data associated with a machine, machine00, machine01 – so we iterate through those.

For each machine element, we use the sub-elements min, max, failProb and name to fill the data fields. Note how we also use a style directive to set the colour for the text. The result is shown below.

screen-shot-2016-12-07-at-7-22-08-am

This is a simple use of the template node, but it should be enough to get you started. However, the template node is much more sophisticated, it can be used to dynamically set styles (e.g. colours), show images, create clickable elements that generate messages etc – so once you master the basics, you can go on to create some sophisticated UI widgets for your own dashboards.


About Sense TecnicSense Tecnic Systems Inc have been building IoT applications and services since 2010. We provide these lectures and FRED, cloud hosted Node-RED as a service to the community. We also offer a commercial version to our customers, as well as professional services. Learn more.

Tutorial: Node-RED dashboards – multiple lines on a chart

Showing multiple lines on a single chart in Node-RED

This simple tutorial explains how to display multiple lines on a Node-RED chart. We’ll be building on a previous example in our lecture series (Example 7.2 in lecture 7)

As discussed in that lecture, let’s set up a simple flow to generate a random number and display it on a chart.

We use a cloud hosted version of Node-RED for these tutorials called FRED. Sign up for a free account at FRED. You can use this tutorial with a vanilla N0de-RED, eg on a Pi, but make sure you are accessing the correct URL for the dashboard (and not the FRED specific one).

To start, let’s wire up a simple flow that sends a random number between 0 and 99 to a simple chart. For that you’ll need an inject node to repeatedly fire every few seconds, a function node to generate the random number and one of the  node-red-dashboard nodes – in this case the chart node.

screen-shot-2016-10-12-at-4-38-47-pm

Before we look a how the chart node works, let’s configure the inject node to send a timestamp every 5 seconds by setting the payload to timestamp and the repeat field to an interval of 5 seconds.

Screen Shot 2016-05-16 at 12.46.11 PM

This will act as our repeating trigger. Now we need to set up the function node to generate a random number – we’ll use a simple JS math function to do this:

msg.payload = Math.round(Math.random()*100);
return msg;

Screen Shot 2016-05-16 at 12.48.42 PM

This will generate a random number between 0 ~ 99 which is passed to the chart node.

So now let’s take a look at the chart node. When you double click it, you’ll see it’s configuration options:screen-shot-2016-10-12-at-4-46-53-pm

If you click on the button of the Group field, you will be prompted  to configure the tabs of the UI.

screen-shot-2016-10-12-at-4-42-04-pm

The Tab option allows you to specify which tab of the UI page you will see the UI element on – in this case our chart. The default tab is Home – which we are using here. If you select the edit button to the right of the Tab field you can create a new tab and then select that. However, we’ll use the default home for now.

The Name field is the standard Node-RED node name – by default this is chart but you can set it to anything you like.

The Group field allows you to group UI elements – we’ll show you how that works when we add another UI element so let’s use group “Default[Home]” for now – of course, you can use any string you like.

The X-axis field allows you to tell the chart how much data it should store and display – the longer the ‘last‘ filed is set to, the more data is stored and displayed by the chart. Let’s use a short 5 mins which will start to throw away the data that is 5 minutes old.

Lastly the Interpolate field defines how the chart will interpolate values in between actual data values it receives, you can select between linear, step, b-spline and cardinal – which are standard interpolation algorithms. We’ll use the default linear.

Wire these nodes up, hit the deploy button – check that your debug node is showing that random values are showing. Then head over to your default dashboard page to see the results. By default, under FRED, you’ll see your UI at:

https://{your user name}.fred.sensetecnic.com/api/ui/

When you visit that page you’ll see your initial chart as shown below:

screen-shot-2016-10-12-at-4-48-47-pm

As you can see, you get a nice line chart, scaled for your data values (X axis) and the time they arrived (y axis). You can also see “Default” at the top left of the chart, indicating this is UI group “Default” – which is the group name we set in the configuration fields for the chart node.

 

Adding a second line to our chart

Ok, now let’s see how to add another line to the same chart.

If you take a look at the info box for the chart node, you’ll see it mentions that the the msg.topic field can be used to show multiple lines. Essentially the chart node will receive messages, take a look at the msg.topic field, and then append the data to the appropriate line as defined by the topic.

So, to extend our example to handle multiple lines on a single chart, we have to do two things:

  1. update our function node to generate two random numbers and assign these to different messages with different topics
  2. Wire up a second output from the function node to handle the second message

To do that, open up the function node and update the code inside as shown below. As you can see we explicitly create two messages, msg and msg1 (lines 1-2).

At line 4-5 we set msg.topic to ‘Line1’ and a random number is assigned to the payload. We repeat that at line7-8 setting msg1.topic to ‘Line2’ and assigning a different random number.

screen-shot-2016-12-05-at-5-28-56-pm

Both messages are returned using the return message (line 9) – because we are generating two return message, we need to tell the function node that it has two outputs by setting the outputs field to 2 (see above).

More details of generating multiple messages from nodes can be found in the main lectures Example 5.2 in lecture 5.

Once you’ve done this, your flow should look like the screen shot below.

screen-shot-2016-12-05-at-5-23-17-pm

Wire up both outputs from the function node to the chart node and then take a look at the dashboard and the chart. As you can see (shown below) the chart now shows two lines (Line1 and Line2) with different colours. Note we set the dashboard theme to dark to make the two lines clearer.screen-shot-2016-12-05-at-5-24-06-pm

Obviously this example is contrived, in a more realistic example you might have two sources of data, and so two function nodes delivering messages (rather than the single function node with two outputs).

In addition, you’d be pulling the data from a real source, e.g. a web scrape, an MQTT feed or perhaps a DB. You can see examples of these:


About Sense TecnicSense Tecnic Systems Inc have been building IoT applications and services since 2010. We provide these lectures and FRED, cloud hosted Node-RED as a service to the community. We also offer a commercial version to our customers, as well as professional services. Learn more.

Tutorial: SQLite and Node-RED

This tutorial will show you how to make use of an SQLite database using the litedb node on the FRED hosted Node-RED platform to create database tables and store data. Under the hood, the litedb node uses SQLite.  As a very lightweight relational database, SQLite does not need complex setup procedures, making it an ideal database management system to use for embedded systems and rapid prototyping.

The tutorial will cover the basics of:

  • Setting up the dblite (SQLite) node and creating a DB table
  • Generating random data and storing in the SQLite DB
  • Reading from the SQLite DB
  • Graphing the data from the DB using the standard Node-RED UI nodes

Read the full tutorial here