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.

Lecture 7: Node-Red dashboards (Part 3)

Example 7.3 Using a simple JavaScript chart library to build a custom dashboard

For our final example of building Dashboards and UIs we’ll use a generic technique we’ve experimented with before. That’s the web service approach that uses a http node to allow us to accept http requests and return web pages. We used this approach in example 1.3 but didn’t explain the details.

Sticking with the openweathermap node, let’s use it to generate a simple JSON structure that we then visualize using the popular Morris.JS chart library (). The library supports 4 basic chart types line charts, area charts, bar charts and the donut chart. We’ll be using the donut chart but the approach is the same for all the chart types.

The flow is shown below and consists of 4 nodes. The first and final nodes are http input and output nodes that work together to listen for HTTP requests and send HTTP responses. This flow listens for a HTTP request from any source, but let’s assume a regular browser here. When it arrives, it queries the weather using your openweathermap nodethen uses a template node to build a HTTP page using the weather data, and passes that to the http output node which sends back the webpage to the browser.

Screen Shot 2016-05-17 at 2.37.43 PM.png

Figure. A simple web server example to graph weather data using a pi chart

Double click on the http input node and configure it with your URL, e.g. /public/weather. Remember, to access it, you will need to use,

https://{user name}.fred.sensetecnic.com/api/public/weather

where {user name} is replaced by your own FRED user name. Obviously /weather is because that’s how you configured it, if you’d used another name, e.g. /public/test, then the URL would end /public/test

When a HTTP request comes in, the http input node creates a message to trigger the openweathermap node, which is the next node in the flow. The openweather node gets the current statistics for the location you configured it for, and then passes those statistics, as a JSON structure in the usual message payload field, to a template node. The html template node is another pre-built node in Node-RED, which, like the function node, allows you to build arbitrary code. However, rather than using JavaScript like the function node, the template node works with text such as HTML.

The HTML code in the template node is shown in the listing below. As you can see, the code is a standard HTML structure with the <head> structure defining the external script libraries that we use. These are all required for the Morris.JS chart library and should be copied exactly.

Note, we are combining all the page elements into the one file (or node) which works for simple web pages but is not considered good practice.

Line 10 sets up a <div> and sets the name and height. Then the morris.js chart code  script begins at line 11 by defining a Morris.Donut element.

Listing  A simple HTML template to display a donut chart of calorie usage

  1. <!doctype html>
  2. <head>
  3.     <title>A Node RED Example</title>
  4.     <link rel=”stylesheet” href=”//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css”>
  5.     <script src=”//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js”></script>
  6.     <script src=”//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js”></script>
  7.     <script src=”//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js”></script>
  8. </head>
  9. <html>
  10.     <div id=”chart-example” style=”height: 250px;”></div>
  11.     <script>
  12.         Morris.Donut({
  13.            element: ‘chart-example’,
  14.            data: [
  15.              {label: “Temperature (Celcius)”, value: {{payload.tempc}} },
  16.              {label: “Humidity”, value: {{payload.humidity}} },
  17.              {label: “Wind Speed (knts)”, value: {{payload.windspeed}} }
  18.           ]
  19.        });
  20.     </script>
  21. </html>

Lines 15, 16 and 17 define the donut elements, you are using 3 to display the temperature, the humidity and the wind speed. The values from the openweathermap JSON structure can be used directly, i.e. payload.tempc, payload.humidity and payload.windspeed.

Once the template node has generated the HTML file, it passes it as a message to the final node, which is a http response node. This node packages up the HTML as a HTTP response which it sends back to the browser that made the original request.

If you deploy this flow and then point your browser to the URL you configured in the http input node, in your case should be:

https://{user name}.fred.sensetecnic.com/api/public/weather

You will then see a simple donut chart which you can mouse over to see the temperature, humidity and windspeed for the city you configured in the openweathermap node – all built and served by a simple Node-RED flow!

Screen Shot 2016-05-17 at 2.59.31 PM.png

Figure: A donut chart, served up by Node-RED showing Temperature for the configured city

Summary

In this lecture you have looked at three approaches to building simple dashboards and UIs. The FreeBoard node is a one stop shop allowing you to feed complex data as JSON structures to the Freeboard node and then using the powerful FreeBoard dashboard to configure and show the data.

With the nodered.contrib.ui nodes you have to do a little more work by having to build the UI elements into your flows. This approach gives you more control, and makes the UI elements part of your Node-RED flow, but requires a little more thought and work.

The final approach, using the html template node and a generic JavaScript charting library is the most flexible, but requires you know how to write simple html/css and JavaScript.

Part 1    Part 2


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.


© Lea, Blackstock, Calderon

This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.

Node-RED: Lecture 7 – Dashboards and UI techniques for Node-RED

In this lecture you will take a look at a few techniques to allow you to visualize data passing through flows. We’ll focus on three approaches, the use of a third party dashboard tool, FreeBoard (Part 1), using the default Dashboard UI nodes provided by default in Node-RED (Part 2) and a general technique using a standard JavaScript charting tool (Part 3).

By the end of the lecture you will have enough knowledge to decide which approach is best for your specific needs and how to quickly get a visualization of your data up in a web browser.

We use a cloud hosted version of Node-RED for these lectures called FRED. Sign up for a free account at FRED.sensetecnic.com. Examples in the early lectures will work with other installations of Node-RED, later lectures use nodes you will need to install yourself if you don’t use FRED.

Example 7.1 Using the FreeBoard dashboarding service

This is a simple example of reading and visualizing data using the FreeBoard node from a Node-RED flow. We’ll be using the Cloud based FRED service as our Node-RED engine and visualizing data from a web weather service . This guide will show you how to:

  • set up an openweathermap node in FRED using the built in node
  • display the data from the openweathermap node using the FreeBoard display node

To begin, head over to openweathermap.org and register for a free account. When you register/login you will be able to access your API Key. You will need your own API key which will look similar to the one below – you will use your own key in Node RED so make a copy.

 

01

Now, head over to FRED and create a new flow by starting with an openweathermap node (you will find this node under “weather”, or by using “filter nodes” to search at the top of the left pane) and connecting it to a debug node like this:

02

 

Now, double click on the openweathermap node to configure it. Enter your API Key from OpenWeatherMap, configure a location you’re interested in, and name your Node:

 

03

Click on Deploy on the top right corner of the Node-RED UI. You will see on the right pane, under “debug” the data that OpenWeatherMap provides us with a variety of information about the location including temperature (in C and K), humidity, windspeed etc:

 

04

As you can see, the data is already in JSON format; so we can use any of the values very easily. Let’s build a dashboard to visualize our data using the  node that allows you to create visualizations very easily. Find the freeboard node in the left pane by either browsing through the nodes or searching for it using “filter nodes”. Add it to the flow. Double click on it to give it a name, like so.

05

 

Click on Deploy. This will prompt the openweathermap to get data and send it to both the debug and freeboard nodes. The freeboard node is quite smart and will do its best to parse the data you send it and figure out how to make it available using the FreeBoard UI. We’ll look at that in a moment. If you inspect the “info” tab in the right panel you will see more information about the “freeboard” node:06Visit the link provided in the info panel, or at

https://{username}.fred.sensetecnic.com/api/freeboard/

This will open a new tab in your browser:

07

This tab will allow you to create visualization in FreeBoards, save them and load them. Let’s create a visualization of our weather data. We first need to add a datasource to our freeboard. Click on “Add” under “DATASOURCES”. Under “type” select the name of the “freeboard” node we configured above. In our case we named it “freeboard”. This will allow us to access ANY data we connect to the “freeboard” node in Node RED.

 

08

 

We will now add a Pane. Click on “ADD PANE”, this will add a new empty pane:

09

 

Now, we will add a “Widget”, click on the “+” (plus) sign in the new pane. Select “Gauge”. Under “DATASOURCE” select the “freeboard” node and select “tempc”. As you can see, all of the different data fields in the openweathermap JSON structure are available for you to visualize. FreeBoard essentially takes the JSON structure you pass it and breaks out any fields. If you can’t see this in the dropdown, go back to Node RED and click on “Deploy” again. So that the “freeboard” node can get some data and store the data it has received. Your configuration should look something like this:

 

10

 

Click on OK. Which will build your widget and add it to the pane you created!

11

 

To save your dashboard click on “save”, and select [pretty] or [minify] which will save it in FRED and will show you the URL to access the Dashboard. You need to save the URL used to access the dashboard, e.g. as a dashboard. From now on you can access your saved dashboard by accessing the saved url, which will be similar to the one below.

https://{username}.fred.sensetecnic.com/api/freeboard/#start-16091

Part 2  Part 3

 


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.


© Lea, Blackstock, Calderon

This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.