Develop your SCADA Application based on NodeRED


Course 8 Chapters of General Content [IS.AC002.GC]


NodeRED is a open source programming tool, based in NodeJS, to develop applications in order to interact with different hardware's. Also Node-RED provide a browser editor that make easier to program and configure your own applications.    

See more information of Node-RED in the official website: Node-RED about

The first step of this course w ill be how to install NodeRed application in your personal computer. Before install Node-RED we must install NodeJS.  


 Just go the official website of NodeJS and download the NodeJS source code or a pre-build installer for your OS: NodeJS Download 

If you want to install it from the Linux command line:   

Add the repository:  

 sudo apt install curl 

For the latest release, type:  

 curl -sL | sudo bash - 

For the LTS release, type:

curl -sL | sudo bash - 

 Finally to install NODEJS type: 

 sudo apt install nodejs 


After installing the NodeJS our computer is ready to install Node-RED.  The best way to install Node-RED is to use the node packae manager, npm, that already comes with Node.js.  


Type to the command prompt:

                            npm install -g --unsafe-perm node-red 


Type to command line:

sudo npm install -g --unsafe perm node-red

Take a look on the official installation guide to know more details: Node-RED install

Once you have installed the Node-RED you are able to proceed with the next chapter of the course, 

and now we will see how to install Node Red on your Raspberry Pi.

Install Node Red on your Raspberry Pi

The content of this chapter is how to install our NodeRED application to one of our Touchberry Pi or other Panels PC based in Linux. This type of applications are very used for our customers because it's a easy and robust way to have a SCADA touch panel next to the installation. Another point that we will focus during the chapter is how to  add the autostart capability, so once we torn on the panel the system will show us directly the NodeRED application. 

Installation and Upgrade

Depending which version of Panel PC we will have installed different version of Debian or Ubuntu. Upgrade or install the last version of NodeRED into your system typing in the terminal:   

bash <(curl -sL       

Update npm before installing any package using the following comands:

 cd ~/.node-red npm outdated npm update 

Running NodeRED

To start NodeRED open a new terminal window and type:


*Closing the terminal or ctrl-c does not stop the NodeRED running. It will continue running in the background. 

To stop, type:


Autostart on boot

Probably in your application you will want that the NodeRED start when you turn on your Touchberry Pi. In order to do that we will open the terminal again and type:

sudo systemctl enable nodered.service

and to disable type:

sudo systemctl disable nodered.service

These are the basics to install NodeRED to our Touchberry Pi or other Linux based Industrial Shields panel PC. 

If you need additional information about that follow the next link.

MQTT client for Arduino based PLC as a I/Os module.

In the chapter #1 is explained how to configure your Industrial Arduino based PLC as a MQTT I/Os Module. 

Before starting this chapter will be interesting to take a look on how MQTT protocol works, what is a JSON and their applications. 

After that, take a fast look on the next libraries:

The architecture of the code is made for a M-Duino21+, but is designed to be extended for others M-Duino's. There are four different arrays that include all available I/Os in   M-Duino 21+. 

These arrays are: digitalOutputsanalogOutputsdigitalInputsanalogInputs

So, every array will be structured as follows:

digitalOutputs[NUM_ZONES][NUM_DIGITAL_OUTPUTS_PER_ZONE] = {{Q0_0, Q0_1... }, {Q1_0, Q1_1...}, {Q2_0, Q2_1...} 

This last example will be for a M-Duino 58+, every zone is subdivided with their related pins nomenclature.

After explained how to access to the inputs mapping we are ready to explain the rest of the code. 

In the setup() we just are making the initialization of the Ethernet and MQTT client called mqtt, relating the callback function when we receive a message through MQTT and all the actual input values. After that we just have three main functions in the loop() function. We are calling the reconnect() function if there is no connection with the server,if   there is connection we are just using the mqtt.loop() function that will maintain the connectivity with our server. Apart of this twofunctions we have the updateInputs() that will update the real value of the inputs.

Lets go deeper in the functions to have a better understating of what they do:


Firs of all, we have the reconnect() function that will  subscribe to the "Q" and "A" topics. One topic is dedicated to analog outputs and the other is dedicated to the digital          outputs. If is not connected to the server, then they will stop the client connection in order to not cause any issue with the server ports. 

Second, to understand how the outputs control works we need to look into the callback function. In this program the callback function is receiveMqttMessage(). The receiveMqttMessage() function will run every time that we receive a message. So, when we receive a message the callback function will decide if the topic is for analog or digital pins and then will call the right function for it, setDigitalOutput() function or setAnalgoOutput() function.

setDigitalOutput() extract and analyzes the JSON file, confirm that the zone and the pin exists and then execute the digitalWrite() function to update the desired output. 

The setAnalogOutput() function work exactly the in the same way that setDigitalOutput()

ANALOG_OUTPUTS_OFFSET is used to offset the value of the analog pins. Analog pins are placed in the positions  5, 6 ,7. This is why the ANALOG_OUTPUTS_OFFSET is 5.


In the main loop we have the function updateInputs()  that will update all the values of the inputs. This function will be comparing all the previous values to the current ones  and if the new value have changed, then the program will publish the new value though MQTT. The digital values will be compering if there is a 0 or a 1, the function that make this work is updateDigitalInput().

In the analog site the program will compare if the analog value havechange more than 5 point, if the current value is higher or lower than the previous one, then will publish    the new value. The function that make this work is updateAnalogInput().

   Copyright (c) 2019 Boot&Work Corp., S.L. All rights reserved
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   GNU Lesser General Public License for more details.
   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <>.

// included library depending of M-Duino version 
#include <Ethernet2.h>
#include <Ethernet.h>

// libraries needed for MQTT communication
#include <ArduinoJson.h>
#include <PubSubClient.h>
#define MQTT_ID "demo"
#define NUM_ZONES 1

const int digitalOutputs[NUM_ZONES][NUM_DIGITAL_OUTPUTS_PER_ZONE] = {
  {Q0_0, Q0_1, Q0_2, Q0_3, Q0_4},

const int analogOutputs[NUM_ZONES][NUM_DIGITAL_OUTPUTS_PER_ZONE] = {
  {A0_5, A0_6, A0_7},

const int digitalInputs[NUM_ZONES][NUM_DIGITAL_INPUTS_PER_ZONE] = {
  {I0_0, I0_1, I0_2, I0_3, I0_4, I0_5, I0_6},
#define ANALOG_INPUTS_THRESHOLD 5 // Filtering threshold

const int analogInputs[NUM_ZONES][NUM_ANALOG_INPUTS_PER_ZONE] = {
  {I0_7, I0_8, I0_9, I0_10, I0_11, I0_12},
byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xAE };
IPAddress broker(10, 0, 3, 21);
unsigned port = 1883;
// Initialize client
EthernetClient client;
PubSubClient mqtt(client);

void setup(){ 
  mqtt.setServer(broker, port);
  // Init variables
  for (int i = 0; i < NUM_ZONES; ++i) {
    for (int j = 0; j < NUM_DIGITAL_INPUTS_PER_ZONE; ++j) {
      digitalInputsValues[i][j] = digitalRead(digitalInputs[i][j]);
    for (int j = 0; j < NUM_ANALOG_INPUTS_PER_ZONE; ++j) {
      analogInputsValues[i][j] = analogRead(analogInputs[i][j]);

void loop() {
  if (!mqtt.connected()) {
  } else {

void updateInputs() {
  for (int i = 0; i < NUM_ZONES; ++i) {
    for (int j = 0; j < NUM_DIGITAL_INPUTS_PER_ZONE; ++j) {
      updateDigitalInput(i, j);
    for (int j = 0; j < NUM_ANALOG_INPUTS_PER_ZONE; ++j) {
      updateAnalogInput(i, j);

void updateDigitalInput(int zone, int index) {
  int value = digitalRead(digitalInputs[zone][index]);
  if (value != digitalInputsValues[zone][index]) {
    digitalInputsValues[zone][index] = value;
    publishInput(zone, index + DIGITAL_INPUTS_OFFSET, value);

void updateAnalogInput(int zone, int index) {
  int value = analogRead(analogInputs[zone][index]);
  int minValue = value > ANALOG_INPUTS_THRESHOLD ? value - ANALOG_INPUTS_THRESHOLD : 0;
  int maxValue = value < 1023 - ANALOG_INPUTS_THRESHOLD ? value + ANALOG_INPUTS_THRESHOLD : 1023;
  if ((analogInputsValues[zone][index] < minValue) || (analogInputsValues[zone][index] > maxValue)) {
    analogInputsValues[zone][index] = value;
    publishInput(zone, index + ANALOG_INPUTS_OFFSET, value);

void setDigitalOutput(char *payload, unsigned int len) {
  DynamicJsonBuffer json(JSON_OBJECT_SIZE(3));
  JsonObject &root = json.parseObject(payload, len);
  if (root.success()) {
    int zone = root["zone"];
    if (zone >= NUM_ZONES) {
      // Invalid zone
    int index = root["index"];
    if (index >= NUM_DIGITAL_OUTPUTS_PER_ZONE) {
      // Invalid digital output
    int value = root["value"];
    digitalWrite(digitalOutputs[zone][index], value);

void setAnalogOutput(char *payload, unsigned int len) {
  DynamicJsonBuffer json(JSON_OBJECT_SIZE(3));
  JsonObject &root = json.parseObject(payload, len);
  if (root.success()) {
    int zone = root["zone"];
    if (zone >= NUM_ZONES) {
      // Invalid zone
    int index = root["index"];
    if (index >= NUM_ANALOG_OUTPUTS_PER_ZONE) {
      // Invalid analog output
    int value = root["value"];
    analogWrite(analogOutputs[zone][index], value);

void reconnect() {
  if (mqtt.connect(MQTT_ID)) {
  } else {
    // MQTT connect fail

void receiveMqttMessage(char* topic, byte* payload, unsigned int len) {
  if (strcmp(topic, "Q") == 0) {
    // Set digital output
    setDigitalOutput((char*) payload, len);
  } else if (strcmp(topic, "A") == 0) {
    // Set analog output
    setAnalogOutput((char*) payload, len);

void publishInput(int zone, int index, int value) {
  DynamicJsonBuffer json(JSON_OBJECT_SIZE(3));
  JsonObject &root = json.createObject();
  if (root.success()) {
    root["zone"] = zone;
    root["index"] = index;
    root["value"] = value;
    publish("I", root);

void publish(const char *topic, JsonObject &root) {
  unsigned len = root.measureLength();
  if (len > 0) {
    char *payload = new char[len + 1];
    if (payload) {
      root.printTo(payload, len + 1);
      publish(topic, payload);
      delete[] payload;

void publish(const char *topic, const char *payload) {
  if (mqtt.connected()) {
    mqtt.publish(topic, payload);

How to visualize inputs 

In the previous chapters we have seen how to install Node-RED in our computer and a useful Arduino code using Industrial Shields units.  This code will be related during the entire course and we will be interacting with it to debug our own programs. 

So, in  the chapter  #2 we will step forward and we will see how to visualize the input values of our M-Duino into a Dashboard. 

The first step is to install the stable version of Node-RED-Dashboards API. Remember that Node-RED-Dashboard requires Node-RED to be installed. Typing in the terminal we will go to our directory ~/.node-red using: 

cd /.node-red

Then we will type the command to install Node-RED-Dashboard:

npmi node-red-dashboard

If you want more information about Node-RED-Dashboard take a look on the following link:      Node-RED-Dashboard

Running Node-RED 

Once Node-RED-Dashboard is installed we can proceed to start out firs program. 

First of all, we will learn how to execute the node-red and how to change our programs. If you have installed Node-RED you can use the Node-RED  command: 

Running Node-RED 1 - Chapter 2 - Develop your SCADA Application based on NodeRED

After running the Node-RED command we are able to go to the localhost:1880/

Type localhost:1880/ in your browser. You will see the Node-RED user interface where we will be able to develop, debug and modify our programs

Node-RED user interface - Develop your SCADA Application

Now we are able to see the different Node-RED blocks at the right site. If you click on a module you will se that in the left site is showed some help documention that will be very useful to understand the block. 

Creating our first program

Finally  our first  steps  creating our program:

Take one MQTT input blog.

This module will be our MQTT input message from the MQTT broker. Make double click and change the topic for "I". This change will relate the input blog with all the messages that we receive through topic "I". Actually the block have subscribed to "I". 

Moreover we must change the server.  You will see that you don't have any server created. Create a new server, named and configured as follows. These will be the IP address and the port where the MQTT broker is placed. Take look on  the next picture. We have named the server "Localhost broker".

Creating our first program 1 - Chapter 2 - Develop your SCADA Application based on NodeRED

Our MQTT subscription is set properly. 

From this block we will receive a JSON string with the following structure:

                                    "{"zone" = 0, "index" = 0 , "value" = 0 }"

Work with string it's not practical. For this reason we have to convert this string to a JavaScript object. Node-RED has one blog dedicated to do this job. This block is named json and we can find it into the functions blocks. Double click to this block. Change the action to "Always convert to JavaScript Object". Now to the output of this message we will have the JavaScript object and will be very east to organised our program.

Odoo CMS - a big picture

After converting the message from the MQTT "I" topic to a JavaScript we are ready to analyze the object and divided to the different zones and indexes. In this course we just will see an example of M-Duino 21+. So we will have the following input structure.  

Zone 0

  • INDEX 0 = I0_0

  • INDEX 1 = I0_1

  • INDEX 2 = I0_2

  • INDEX 3 = I0_3

  • INDEX 4 = I0_4

  • INDEX 5 = I0_5

  • INDEX 6 = I0_6

  • INDEX 7 = I0_7

  • INDEX 8 = I0_8

  • INDEX 9 = I0_9

  • INDEX 10 = I0_10

  • INDEX 11 = I0_11

  • INDEX 12 = I0_12

Zone 1

(M-Duino 42+, M-Duino 38R, M-Duino 38AR+...)

Zone 2

(M-Duino 57R+, M-Duino 58+...)

Take a look in the M-Duino 21+ inputs, and you will see that from I0_7 to I0_12 are analog inputs. In fact the values will be representative in a different way, becouse one is digital and the other will be analog (from 0 to 1024). But we will see it later.

B Zone - Chapter 2 - Develop your SCADA Application based on NodeRED

The first split to the object will be the zone.

Node-RED have a block named switch that will be very useful to divide the information an direction it to where we want. So, to filter the zone we will add the switch and with double click we will change the configuration. Add two new conditions. And configured as the following picture. Adding we will indicate with part of the object the switch will have to look on in order to classify the message.  

Zone Switch - Edit switch node - Chapter 2 - Develop your SCADA Application based on NodeRED

After the first zone switch, we will proceed doing the same for the index. 

Index node - Edit switch node - Chapter 2 - Develop your SCADA Application based on NodeRED

Before placing the final blocks to display the values to the dashboard, we need to create some groups.

At the right site we have the three different tabs. One to see the debug messages, another for information and another one for the distribution of our dashboard.

In the Layout site, we have distributed the space in three groups, digital inputs and two for analog inputs. When we create the proper dashboard blocks, we will decide where to place these block on our dashboard. Apart from that there is other configurations in site and theme tabs that will give a customized look to our dashboard. 

So, after analyzed and divided the full message, now we just need to show in our dashboard the real and updated value. In fact, we just need to connect the switch block for digital inputs and the gauge block for the analog inputs, you may find this blocks in the dashboard group on the left site.

Node-RED also have the options like a chart for Analog signals.

Take a look at the following pictures to have a better understanding.

Inputs - Chapter 2 - Develop your SCADA Application based on NodeRED

Edit switch node 1 - Chapter 2 - Develop your SCADA Application based on NodeRED

Edit gauge node - Chapter 2 - Develop your SCADA Application based on NodeRED

You will have realized that in the last block picture we have placed the msg block. This blog is the debug block. The debug block is very useful to debug our program and follow up every function in order to see how the message flows in our workflow. 

Finally, we have our logic programmed and we just need to customize our dashboard. Configure the Layout, Site and Theme to give your desired look to your dashboard. As example take a look on the following pictures. 

Layout Dashboard - Chapter 2 - Develop your SCADA Application based on NodeRED

Site Dashboard - Chapter 2 - Develop your SCADA Application based on NodeRED

Theme Dashboard - Chapter 2 - Develop your SCADA Application based on NodeRED

Finally, the work is done. With the porpoise to test our new program, we will have to the Mosquitto MQTT broker in our computer and connect the M-Duino to the same network. Next is showed a picture of how the dashboard will be displayed.

Dashboard Display - Chapter 2 - Develop your SCADA Application based on NodeRED

Besides, you have a video example of how you will see the dashboard in real time while the inputs values are changing. 


Please, answer this  Survey   and receive the next lesson!

How to interact with Outputs

Coming soon...

How to configure your Industrial Shields PLC through MQTT

Coming soon...

Communications: How to read variables from a Slave device

Coming soon...

Install NodeRed on Raspberry Pi or Industrial Panel PC based on Raspberry(Linux)

Coming soon...

Alarms Manager

Coming soon...

Data Base Creation

Coming soon...

Build a Graphic of saved Values and how to download a file

Coming soon...


Coming soon...