Node-RED is a fun tool from IBM Research to "wire up the IoT". We show how the JsonServer application allows you to interface Node-RED to your SmartMesh IP network without writing a line of code!

This recipe updates the previously published "SmartMesh IP and Node-RED" recipe. In this recipe, we use the JsonServer SmartMesh SDK application; it's now even simpler to interface with Node-RED!


Overview of Node-RED

Node-RED is a fun tool from IBM Research to "wire up the IoT". It's a program you launch on your computer, which allowing you to link inputs (sensors, etc.) to outputs (actuators, files, Twitter feeds, etc.) through a web-based graphical interface.

SmartMesh IP and Node-RED are a perfect match. I'll show you a couple of examples in this recipe. You will be using the brand new JsonServer application from the SmartMesh SDK; you won't even have to write a line of code!

To complete this tutorial, you need to have:

We assume the motes are running the default firmware, in master mode.

We assume that the manager is connected to your computer over USB, that all the motes are switched on, and that all motes have joined the network.

We assume you have downloaded the SmartMesh SDK, and are comfortable enough with it that you can launch different applications.

Setup

Installing Node-RED

The first step is to install Node-RED.

Running the JsonServer application

This application is part of the SmartMesh SDK. To start it, double-click on JsonServer.py.

Starting your network

We assume that you have a SmartMesh IP manager connected to the computer which runs the JsonServer application, and a couple of motes already in the network.

Interact with your SmartMesh IP nodes using Node-RED!

In this section, we will create a number of Node-RED flows to interact with your SmartMesh IP network directly from Node-RED!

Retrieve the status of the JsonServer

Use Node-RED to issue the following HTTP request:

methodGET
URIhttp://127.0.0.1:8080/api/v1/status
bodynone

To do so, in Node-RED, create a flow called "status" with the following contents:

[{"id":"3eb439e9.a16146","type":"inject","z":"8c6d627b.da73c","name":"click to get status","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":146.5908966064453,"y":65.63638305664062,"wires":[["97cbb847.431838"]]},{"id":"97cbb847.431838","type":"http request","z":"8c6d627b.da73c","name":"","method":"GET","ret":"txt","url":"http://127.0.0.1:8080/api/v1/status","tls":"","x":271.59088134765625,"y":161.8182144165039,"wires":[["a459d098.1a269"]]},{"id":"a459d098.1a269","type":"debug","z":"8c6d627b.da73c","name":"","active":true,"console":"false","complete":"false","x":366.5908660888672,"y":261.72728729248047,"wires":[]}]

List the available serial ports

Use Node-RED to issue the following HTTP request:

methodGET
URIhttp://127.0.0.1:8080/api/v1/helpers/serialports
bodynone

To do so, in Node-RED, create a flow called "serialports" with the following contents:

[{"id":"83b5eea0.77e04","type":"inject","z":"1815fc03.041354","name":"click to get serialports","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":249,"y":123,"wires":[["802c15cd.802598"]]},{"id":"802c15cd.802598","type":"http request","z":"1815fc03.041354","name":"","method":"GET","ret":"txt","url":"http://127.0.0.1:8080/api/v1/helpers/serialports","tls":"","x":353.99998474121094,"y":219.18183135986328,"wires":[["e13a0a2c.06ff08"]]},{"id":"e13a0a2c.06ff08","type":"debug","z":"1815fc03.041354","name":"","active":true,"console":"false","complete":"false","x":448.9999694824219,"y":319.09090423583984,"wires":[]}]

Connect to your SmartMesh IP Manager

Use Node-RED to issue the following HTTP request:

methodPUT
URIhttp://127.0.0.1:8080/api/v1/config/managers
body
{
    "managers": ["COM10"]
}

To do so, in Node-RED, create a flow called "managers" with the following contents:

[{"id":"352ac77f.320e08","type":"inject","z":"4b63067f.9288b8","name":"click to add manager","topic":"","payload":"{\"managers\": [\"COM10\"]}","payloadType":"json","repeat":"","crontab":"","once":false,"x":138.27272033691406,"y":65.2727279663086,"wires":[["43b23a3b.2c0014"]]},{"id":"43b23a3b.2c0014","type":"http request","z":"4b63067f.9288b8","name":"","method":"PUT","ret":"txt","url":"http://127.0.0.1:8080/api/v1/config/managers","tls":"","x":253.272705078125,"y":161.45455932617188,"wires":[["8632b0e3.e632c"]]},{"id":"8632b0e3.e632c","type":"debug","z":"4b63067f.9288b8","name":"","active":true,"console":"false","complete":"false","x":348.27268981933594,"y":261.36363220214844,"wires":[]}]

List operational motes

Use Node-RED to issue the following HTTP request:

methodGET
URIhttp://127.0.0.1:8080/api/v1/helpers/motes
body

none

To do so, in Node-RED, create a flow called "motes" with the following contents:

[{"id":"6ab6af4f.8f30d","type":"inject","z":"4a64780f.dc05f8","name":"click to list motes","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":117.272705078125,"y":50.272727966308594,"wires":[["5aee536b.ed093c"]]},{"id":"5aee536b.ed093c","type":"http request","z":"4a64780f.dc05f8","name":"","method":"GET","ret":"txt","url":"http://127.0.0.1:8080/api/v1/helpers/motes","tls":"","x":254.272705078125,"y":138.4545669555664,"wires":[["c57e64d9.733608"]]},{"id":"c57e64d9.733608","type":"debug","z":"4a64780f.dc05f8","name":"","active":true,"console":"false","complete":"false","x":338.2726593017578,"y":246.36363983154297,"wires":[]}]

Blink LEDs on motes

Use Node-RED to issue the following HTTP request:

methodPUT
URIhttp://127.0.0.1:8080/api/v1/oap/00-17-0d-00-00-38-06-45/digital_out/INDICATOR_0
body
{     "value":   1 }


To do so, in Node-RED, create a flow called "LED" with the following contents:

[{"id":"88f5a22c.e5996","type":"inject","z":"a1220086.57409","name":"LED on","topic":"","payload":"{     \"value\":   1 }","payloadType":"json","repeat":"","crontab":"","once":false,"x":97.27272033691406,"y":70.2727279663086,"wires":[["b4734888.410a58"]]},{"id":"b4734888.410a58","type":"http request","z":"a1220086.57409","name":"","method":"PUT","ret":"txt","url":"http://127.0.0.1:8080/api/v1/oap/00-17-0d-00-00-38-06-45/digital_out/INDICATOR_0","tls":"","x":266.27268981933594,"y":103.4545669555664,"wires":[["622cfc89.bccb74"]]},{"id":"622cfc89.bccb74","type":"debug","z":"a1220086.57409","name":"","active":true,"console":"false","complete":"false","x":389.2726593017578,"y":179.3636703491211,"wires":[]},{"id":"22d76ea2.ebe1b2","type":"inject","z":"a1220086.57409","name":"LED off","topic":"","payload":"{     \"value\":    0 }","payloadType":"json","repeat":"","crontab":"","once":false,"x":93.27272033691406,"y":150.27274322509766,"wires":[["b4734888.410a58"]]}]

Display temperature readings

Use Node-RED to receive the following HTTP requests:

methodPOST
URI/oap

The JsonServer application continuously receives notifications from the SmartMesh IP manager over its serial port. This includes data notifications.

Its default behavior is to issue an HTTP POST request to url http://localhost:1880/<notification_type>. When it receives a valid OAP notification, ithe full URL is http://localhost:1880/oap.

Port 1880 is precisely the port Node-RED runs on by default. This means that, by simply listening for HTTP requests on URI /oap, Node-RED receives the notifications sent by the JsonServer application.

Add a function so the debug console prints only the temperature values received, in C.

[{"id":"3ed8596b.547296","type":"http in","z":"a94e61b2.59c9f","name":"","url":"/oap","method":"post","swaggerDoc":"","x":75.59091186523438,"y":178.00005340576172,"wires":[["d98c9170.75e3f","8c49b10f.e5449"]]},{"id":"593ab632.17cff8","type":"debug","z":"a94e61b2.59c9f","name":"","active":true,"console":"false","complete":"payload","x":358.5908660888672,"y":204.7273178100586,"wires":[]},{"id":"d98c9170.75e3f","type":"http response","z":"a94e61b2.59c9f","name":"","x":192.5908966064453,"y":267.2727737426758,"wires":[]},{"id":"8c49b10f.e5449","type":"function","z":"a94e61b2.59c9f","name":"","func":"if (msg.payload.name==\"oap\" && msg.payload.fields.channel_str==\"temperature\") {\n    return {\n        payload: msg.payload.fields.samples[0]/100.0\n    };\n}","outputs":1,"noerr":0,"x":239.59088134765625,"y":151.2727813720703,"wires":[["593ab632.17cff8"]]}]

A little control loop!

You can install the following very simple control loop: set the LED of one mote if the temperature measured by the other mote is larger than 20C

[{"id":"4be45ab5.008614","type":"http in","z":"f37f1253.7cbce","name":"","url":"/oap","method":"post","swaggerDoc":"","x":86.27272033691406,"y":177.27275848388672,"wires":[["5300f7fb.2b2618","750a3d82.d1d3f4"]]},{"id":"5300f7fb.2b2618","type":"http response","z":"f37f1253.7cbce","name":"","x":194.272705078125,"y":265.5454788208008,"wires":[]},{"id":"750a3d82.d1d3f4","type":"function","z":"f37f1253.7cbce","name":"get temp","func":"if (msg.payload.name==\"oap\" && msg.payload.fields.channel_str==\"temperature\") {\n    return {\n        payload: msg.payload.fields.samples[0]/100.0\n    };\n}","outputs":1,"noerr":0,"x":228.27267456054688,"y":129.54547882080078,"wires":[["8ec13b2c.38b8b8"]]},{"id":"8ec13b2c.38b8b8","type":"switch","z":"f37f1253.7cbce","name":"","property":"payload","propertyType":"msg","rules":[{"t":"gt","v":"20","vt":"num"},{"t":"else"}],"checkall":"true","outputs":2,"x":372.59092712402344,"y":121.54546356201172,"wires":[["a9b1b0ae.6d48b"],["9524e4f7.a34af8"]]},{"id":"a9b1b0ae.6d48b","type":"function","z":"f37f1253.7cbce","name":"LED on","func":"return {\n    payload: {\n        value: 1,\n    }\n};","outputs":1,"noerr":0,"x":519.5908966064453,"y":88.0909194946289,"wires":[["c46fce89.b1fff"]]},{"id":"9524e4f7.a34af8","type":"function","z":"f37f1253.7cbce","name":"LED off","func":"return {\n    payload: {\n        value: 0,\n    }\n};","outputs":1,"noerr":0,"x":519.2726898193359,"y":162.27277374267578,"wires":[["c46fce89.b1fff"]]},{"id":"c46fce89.b1fff","type":"http request","z":"f37f1253.7cbce","name":"","method":"PUT","ret":"txt","url":"http://127.0.0.1:8080/api/v1/oap/00-17-0d-00-00-38-06-45/digital_out/INDICATOR_0","tls":"","x":697.2726898193359,"y":115.2727279663086,"wires":[["6e33ca8f.b4c504"]]},{"id":"6e33ca8f.b4c504","type":"debug","z":"f37f1253.7cbce","name":"","active":true,"console":"false","complete":"false","x":753.2726898193359,"y":215.18183135986328,"wires":[]}]

MQTT integration!

MQTT allows you to coordinate two independent flows, possibly running on different computers.

For that, create two flows:

The first flow publishes the temperature to the HiveMQ MQTT broker on topic DustAcademy/temperature:

[{"id":"4be45ab5.008614","type":"http in","z":"f37f1253.7cbce","name":"","url":"/oap","method":"post","swaggerDoc":"","x":86.27272033691406,"y":177.27275848388672,"wires":[["5300f7fb.2b2618","750a3d82.d1d3f4"]]},{"id":"5300f7fb.2b2618","type":"http response","z":"f37f1253.7cbce","name":"","x":194.272705078125,"y":265.5454788208008,"wires":[]},{"id":"750a3d82.d1d3f4","type":"function","z":"f37f1253.7cbce","name":"get temp","func":"if (msg.payload.name==\"oap\" && msg.payload.fields.channel_str==\"temperature\") {\n    return {\n        payload: msg.payload.fields.samples[0]/100.0\n    };\n}","outputs":1,"noerr":0,"x":228.27267456054688,"y":129.54547882080078,"wires":[["880dd1ce.39589","1d25b4cd.160dfb"]]},{"id":"880dd1ce.39589","type":"mqtt out","z":"f37f1253.7cbce","name":"","topic":"DustAcademy/temperature","qos":"","retain":"","broker":"a2abf4c8.553448","x":491.5908966064453,"y":149.63638305664062,"wires":[]},{"id":"1d25b4cd.160dfb","type":"debug","z":"f37f1253.7cbce","name":"","active":true,"console":"false","complete":"false","x":395.5908966064453,"y":83.54546356201172,"wires":[]},{"id":"a2abf4c8.553448","type":"mqtt-broker","z":"f37f1253.7cbce","broker":"broker.hivemq.com","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""}]

The second flow subscribes to this broker and topic, and switches the LED on/off depending on the temperature value:

[{"id":"6ec61e8a.7e5e4","type":"http request","z":"645a4adb.41c354","name":"","method":"PUT","ret":"txt","url":"http://127.0.0.1:8080/api/v1/oap/00-17-0d-00-00-38-06-45/digital_out/INDICATOR_0","tls":"","x":633.2726898193359,"y":218.27277374267578,"wires":[["ff6f5c0a.fe394"]]},{"id":"ff6f5c0a.fe394","type":"debug","z":"645a4adb.41c354","name":"","active":true,"console":"false","complete":"false","x":753.2726898193359,"y":314.1818313598633,"wires":[]},{"id":"bb7ef7a3.204e38","type":"function","z":"645a4adb.41c354","name":"LED on","func":"return {\n    payload: {\n        value: 1,\n    }\n};","outputs":1,"noerr":0,"x":430.272705078125,"y":182.27276611328125,"wires":[["6ec61e8a.7e5e4"]]},{"id":"22b77e36.fddbd2","type":"function","z":"645a4adb.41c354","name":"LED off","func":"return {\n    payload: {\n        value: 0,\n    }\n};","outputs":1,"noerr":0,"x":444.27268981933594,"y":297.2727737426758,"wires":[["6ec61e8a.7e5e4"]]},{"id":"82b2b938.4af6a8","type":"switch","z":"645a4adb.41c354","name":"","property":"payload","propertyType":"msg","rules":[{"t":"gt","v":"22","vt":"num"},{"t":"else"}],"checkall":"true","outputs":2,"x":298.27272033691406,"y":227.27275848388672,"wires":[["bb7ef7a3.204e38"],["22b77e36.fddbd2"]]},{"id":"f0944028.b9fb1","type":"mqtt in","z":"645a4adb.41c354","name":"","topic":"DustAcademy/temperature","qos":"2","broker":"d510485.da0c1b8","x":155.59091186523438,"y":147.4545669555664,"wires":[["82b2b938.4af6a8"]]},{"id":"d510485.da0c1b8","type":"mqtt-broker","z":"645a4adb.41c354","broker":"broker.hivemq.com","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""}]