In this tutorial, we will look at how to send data to the Kaa platform using Node-RED, which is a flow-based development tool for visual programming. You will learn how to create a digital twin of your Node-RED device, connect the device to Kaa, submit some telemetry and view it in the Kaa web interface.
We will be using Node-RED installed on a Raspberry Pi. However, in your case Node-RED can be installed anywhere - on a local machine, on some other device instead of Raspberry Pi, in the cloud, etc. Our device will represent an endpoint in the Kaa platform and report temperature, humidity, and air pressure. Also, we will interact with the Kaa UI to create a digital twin of the Raspberry Pi and view telemetry data.
Go to the “Device Management” dashboard in your account.
Then add a new device specifying a token that we will use later to identify the Raspberry Pi in the Kaa Cloud.
Also, go to the added device page from the “Device Management” dashboard and copy the application version name.
We will need both the application version and the token to connect the Raspberry Pi to the Kaa Cloud.
Now that we have a digital twin of our device created in Kaa together with its token and application version, let’s work with the Raspberry Pi.
Connect a BME280 sensor to the Raspberry Pi by referring to the following table:
MODULE PCB | DESC | GPIO HEADER PINS |
---|---|---|
VCC | 3.3V | P1-01 |
GND | Ground | P1-06 |
SCL | I2C SCL | P1-05 |
SDA | I2C SDA | P1-03 |
Here’s the diagram the breadboard setup diagram.
If you don’t have a BME280 sensor, then skip the above step and move on.
You may use an Ethernet cable or connect the Raspberry Pi to Wi-Fi using command line or graphical desktop user interface.
Once the Raspberry Pi is connected to the network, install Node-RED:
NOTE: Node-RED is pre-installed in the “Raspberry Pi OS (32-bit) with desktop and recommended software”, so you may skip installation step if you have this OS distribution.
$ sudo apt install nodejs
$ sudo apt install npm
$ sudo npm install -g --unsafe-perm node-red
After the installation is complete, start Node-RED:
$ node-red
When Node-RED reports in a console that it is running, open a browser on the Raspberry Pi and go to 127.0.0.1:1880
or, if you are using the browser on another computer, you will need to use the Raspberry Pi IP address from your network: your_raspberry_ip_address:1880
.
Install a BME280 node, for that click on a menu button in the right top corner and open Manage palette:
Then, click on Install tab and search for bme280.
Install node-red-contrib-bme280
node.
OK, now let’s import the Kaa Node-RED client flow description into Node-RED.
Click menu -> Import:
If you have BME280, use this flow description:
[
{
"id": "7eddf7e8.3a94e8",
"type": "tab",
"label": "kaa_client",
"disabled": false,
"info": ""
},
{
"id": "d80332d4.79c1b",
"type": "inject",
"z": "7eddf7e8.3a94e8",
"name": "Metadata Update",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "1.0",
"x": 150,
"y": 180,
"wires": [
[
"9b07caac.e1fce8"
]
]
},
{
"id": "288fc079.cc7d4",
"type": "mqtt out",
"z": "7eddf7e8.3a94e8",
"name": "Kaa KPC",
"topic": "",
"qos": "0",
"retain": "",
"broker": "ccf67e66.fe83c",
"x": 700,
"y": 260,
"wires": []
},
{
"id": "e5b6ee2a.8f12a",
"type": "debug",
"z": "7eddf7e8.3a94e8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"x": 710,
"y": 340,
"wires": []
},
{
"id": "9b07caac.e1fce8",
"type": "function",
"z": "7eddf7e8.3a94e8",
"name": "Metadata",
"func": "var deviceToken = global.get('DeviceToken');\nvar appVersion = global.get('AppVersion');\n\nmsg.topic = 'kp1/' + appVersion + '/epmx/' + deviceToken + '/update/keys';\n\nmsg.payload = {\n \"model\": \"Node Red\",\n \"works\": true,\n \"model\": \"BME/BMP 280\",\n \"fwVersion\": \"v0.0.1\",\n \"latitude\": 40.71427,\n \"longitude\": -74.00597,\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 360,
"y": 180,
"wires": [
[
"288fc079.cc7d4",
"bab967a5.742038"
]
]
},
{
"id": "ac51a783.266c18",
"type": "inject",
"z": "7eddf7e8.3a94e8",
"name": "Send Telemetry",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "2",
"crontab": "",
"once": true,
"onceDelay": "1.5",
"x": 150,
"y": 340,
"wires": [
[
"1bd2fecf.dd9661"
]
]
},
{
"id": "339bb634.0c571a",
"type": "comment",
"z": "7eddf7e8.3a94e8",
"name": "Sending Metadata to Kaa",
"info": "Example of sending metadata to kaa",
"x": 150,
"y": 140,
"wires": []
},
{
"id": "10fe191f.579067",
"type": "comment",
"z": "7eddf7e8.3a94e8",
"name": "Sending Telemetry to Kaa",
"info": "Example of sending telemtry data to kaa",
"x": 150,
"y": 300,
"wires": []
},
{
"id": "9d35257d.040298",
"type": "inject",
"z": "7eddf7e8.3a94e8",
"name": "Init",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "0",
"x": 110,
"y": 80,
"wires": [
[
"dd84eaa0.c19b18"
]
]
},
{
"id": "dd84eaa0.c19b18",
"type": "function",
"z": "7eddf7e8.3a94e8",
"name": "Init Global",
"func": "global.set('DeviceToken', 'yourToken');\nglobal.set('AppVersion', 'yourAppVersion');\n\nconsole.log('kaa_client')\nconsole.log('DeviceToken:', global.get('DeviceToken'))\nconsole.log('AppVersion:', global.get('AppVersion'))\n\nvar deviceToken = global.get('DeviceToken');\nvar appVersion = global.get('AppVersion');\n\nmsg.payload = 'DeviceToken: ' + deviceToken + '; AppVersion: ' + appVersion;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 360,
"y": 80,
"wires": [
[
"b5aad5ea.80c9d8"
]
]
},
{
"id": "b5aad5ea.80c9d8",
"type": "debug",
"z": "7eddf7e8.3a94e8",
"name": "Initial Variables",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"x": 720,
"y": 80,
"wires": []
},
{
"id": "bab967a5.742038",
"type": "debug",
"z": "7eddf7e8.3a94e8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"x": 710,
"y": 180,
"wires": []
},
{
"id": "cacc758b.f4b448",
"type": "comment",
"z": "7eddf7e8.3a94e8",
"name": "Initialization",
"info": "",
"x": 110,
"y": 40,
"wires": []
},
{
"id": "b662018c.77f55",
"type": "function",
"z": "7eddf7e8.3a94e8",
"name": "Telemetry Data",
"func": "var deviceToken = global.get('DeviceToken');\nvar appVersion = global.get('AppVersion');\n\nmsg.topic = 'kp1/' + appVersion + '/dcx/' + deviceToken + '/json/1';\n\nmsg.payload.timestamp = new Date().getTime()\ndelete msg.payload.model;\nmsg.payload = [msg.payload];\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 480,
"y": 340,
"wires": [
[
"e5b6ee2a.8f12a",
"288fc079.cc7d4"
]
]
},
{
"id": "1bd2fecf.dd9661",
"type": "Bme280",
"z": "7eddf7e8.3a94e8",
"name": "",
"bus": "1",
"address": "0x76",
"topic": "",
"extra": false,
"x": 320,
"y": 340,
"wires": [
[
"b662018c.77f55"
]
]
},
{
"id": "ccf67e66.fe83c",
"type": "mqtt-broker",
"z": "",
"name": "mqtt.cloud.kaaiot.com",
"broker": "mqtt.cloud.kaaiot.com",
"port": "1883",
"clientid": "",
"usetls": false,
"compatmode": true,
"keepalive": "60",
"cleansession": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"closeTopic": "",
"closeQos": "0",
"closePayload": "",
"willTopic": "",
"willQos": "0",
"willPayload": ""
}
]
If not, use this flow description:
[
{
"id": "a120f4f.e30b208",
"type": "tab",
"label": "kaa_client",
"disabled": false,
"info": ""
},
{
"id": "a12578ee.d4bef8",
"type": "inject",
"z": "a120f4f.e30b208",
"name": "Metadata Update",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "1.0",
"x": 150,
"y": 180,
"wires": [
[
"690e0efd.93f15"
]
]
},
{
"id": "a54dbdb1.24dcc",
"type": "mqtt out",
"z": "a120f4f.e30b208",
"name": "Kaa KPC",
"topic": "",
"qos": "0",
"retain": "",
"broker": "dc0deea1.ea5b2",
"x": 700,
"y": 260,
"wires": []
},
{
"id": "b23dc76c.f7c288",
"type": "debug",
"z": "a120f4f.e30b208",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"x": 710,
"y": 340,
"wires": []
},
{
"id": "690e0efd.93f15",
"type": "function",
"z": "a120f4f.e30b208",
"name": "Metadata",
"func": "var deviceToken = global.get('DeviceToken');\nvar appVersion = global.get('AppVersion');\n\nmsg.topic = 'kp1/' + appVersion + '/epmx/' + deviceToken + '/update/keys';\n\nmsg.payload = {\n \"model\": \"Node Red\",\n \"works\": true,\n \"model\": \"BME/BMP 280\",\n \"fwVersion\": \"v0.0.1\",\n \"latitude\": 40.71427,\n \"longitude\": -74.00597,\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 360,
"y": 180,
"wires": [
[
"a54dbdb1.24dcc",
"8c84e0d7.92ae3"
]
]
},
{
"id": "88765ea7.037f",
"type": "inject",
"z": "a120f4f.e30b208",
"name": "Send Telemetry",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "2",
"crontab": "",
"once": true,
"onceDelay": "1.5",
"x": 150,
"y": 340,
"wires": [
[
"a2dab299.37ae3"
]
]
},
{
"id": "66c1df10.0d3db",
"type": "comment",
"z": "a120f4f.e30b208",
"name": "Sending Metadata to Kaa",
"info": "Example of sending metadata to kaa",
"x": 150,
"y": 140,
"wires": []
},
{
"id": "a2dab299.37ae3",
"type": "function",
"z": "a120f4f.e30b208",
"name": "Telemetry Data",
"func": "var deviceToken = global.get('DeviceToken');\nvar appVersion = global.get('AppVersion');\n\nmsg.topic = 'kp1/' + appVersion + '/dcx/' + deviceToken + '/json';\n\nmsg.payload = [{\n temperature_C: Math.random() * (25 - 16) + 16,\n humidity: Math.random() * (95 - 80) + 80,\n pressure_hPa: Math.random() * (1000 - 990) + 990,\n timestamp: new Date().getTime()\n}];\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 380,
"y": 340,
"wires": [
[
"a54dbdb1.24dcc",
"b23dc76c.f7c288"
]
]
},
{
"id": "bbea8f00.2718",
"type": "comment",
"z": "a120f4f.e30b208",
"name": "Sending Telemetry to Kaa",
"info": "Example of sending telemtry data to kaa",
"x": 150,
"y": 300,
"wires": []
},
{
"id": "3a42d047.ab7e5",
"type": "inject",
"z": "a120f4f.e30b208",
"name": "Init",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "0",
"x": 110,
"y": 80,
"wires": [
[
"2a00fd58.27c562"
]
]
},
{
"id": "2a00fd58.27c562",
"type": "function",
"z": "a120f4f.e30b208",
"name": "Init Global",
"func": "global.set('DeviceToken', 'yourToken');\nglobal.set('AppVersion', 'yourAppVersion');\n\nconsole.log('kaa_client')\nconsole.log('DeviceToken:', global.get('DeviceToken'))\nconsole.log('AppVersion:', global.get('AppVersion'))\n\nvar deviceToken = global.get('DeviceToken');\nvar appVersion = global.get('AppVersion');\n\nmsg.payload = 'DeviceToken: ' + deviceToken + '; AppVersion: ' + appVersion;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 360,
"y": 80,
"wires": [
[
"cd0bf7ba.c69908"
]
]
},
{
"id": "cd0bf7ba.c69908",
"type": "debug",
"z": "a120f4f.e30b208",
"name": "Initial Variables",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"x": 720,
"y": 80,
"wires": []
},
{
"id": "8c84e0d7.92ae3",
"type": "debug",
"z": "a120f4f.e30b208",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"x": 710,
"y": 180,
"wires": []
},
{
"id": "a3cb4cfe.034f7",
"type": "comment",
"z": "a120f4f.e30b208",
"name": "Initialization",
"info": "",
"x": 110,
"y": 40,
"wires": []
},
{
"id": "dc0deea1.ea5b2",
"type": "mqtt-broker",
"z": "",
"name": "mqtt.cloud.kaaiot.com",
"broker": "mqtt.cloud.kaaiot.com",
"port": "1883",
"clientid": "",
"usetls": false,
"compatmode": true,
"keepalive": "60",
"cleansession": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"closeTopic": "",
"closeQos": "0",
"closePayload": "",
"willTopic": "",
"willQos": "0",
"willPayload": ""
}
]
Copy the corresponding code, then paste it into the red field and click Import.
Open the Init Global
node and change the token and the app version:
At this point, the nodes only exist in the editor and must be deployed to the server. Click Deploy. Node-Red will start executing the flow on the server (Raspberry Pi), pushing collected data from BME280 into the Kaa platform.
Edit the application configuration so that Kaa automatically creates a time series for each numeric field that it encounters at the root of data samples submitted by your endpoints. You will then be able to view these time series in the Kaa UI, with no extra configuration required.
Go to application under use.
Click on “epts” and enable “Autoextract”.
Go to the device details page of the recently created endpoint (by clicking on the corresponding row in the device table on the “Devices” dashboard). See the data from your Raspberry Pi on the “Device telemetry” widget.
Congratulations, you have successfully sent data from your Raspberry Pi with Node-RED and visualized it in the Kaa UI!
All tutorial resources are located on GitHub.