Developing IoT Mashups with Docker, MQTT, Node-RED, InfluxDB, Grafana

From air
Jump to navigation Jump to search

Page for the tutorial " Developing IoT Mashups with Docker, MQTT, Node-RED, InfluxDB, Chronograf, Grafana " at Eclipse IoT Days Grenoble 2016

Sensors Mix

Introduction

presentation ...

The goal of this tutorial is building rapidly a minimal IoT stack from sensors to dataviz and realtime analytics.

The hardware compoments used in this stack are:

  • various (wireless) sensors,
  • USB radio modems plugged into embedded IoT gateways,
  • Raspberry Pi 1 and 2 playing the role of embedded IoT gateways,
  • Your PC/Mac playing the role of the IoT datacenter server,
  • A t2 micro AWS instance playing the role of the IoT datacenter server if a public IP address is required (case for Sigfox callback).


The software compoments used in this IoT stack are :

Those software compoments are preinstalled on the Raspian Jessie distribution of the Raspberry PI boards in order to speed the installation and prevent WiFi whims.

Tools are:

Security, Avaibility and Performance issues are not in the scope of this tutorial.

Radio communication technologies are : Wifi, BLE, LoRa, SigFox, NFC and Rfxcom 433 MHz.

Info: the username and password on the RPIs are pi and IoTTraining


Install Docker

MacOS and Debian

See Docker

Raspian

wget --no-check-certificate https://downloads.hypriot.com/docker-hypriot_1.10.2-1_armhf.deb
sudo dpkg -i docker-hypriot_1.10.2-1_armhf.deb
sudo service docker restart
sudo docker info

Install Node.js and NPM

http://nodered.org/docs/hardware/raspberrypi

On Raspian Jessie : Node.JS is already installed but NPM not

nodejs -v
sudo apt-get update
sudo apt-get install npm
npm -v


On Raspian Wheezy

sudo apt-get update
sudo apt-get install nodejs npm
nodejs -v
npm -v


On MacOS X

TODO

With Docker

docker pull node

See https://hub.docker.com/_/node/

Install Node-RED

http://nodered.org/docs/hardware/raspberrypi


On Raspian Jessie : Node-RED is already installed (but you can update it with sudo apt-get update ; sudo apt-get install nodered)

node-red-start
pgrep node-red

The default directory is : ~/.node-red

Use node-red-stop to stop Node-RED

Use node-red-start to start Node-RED again

Use sudo systemctl enable nodered.service to autostart Node-RED at every boot

Use sudo systemctl disable nodered.service to disable autostart on boot


Browse http://127.0.0.1:1880/

Now, you can write your own Node-RED flows and functions.


Install the admin cmdline tool

sudo npm install -g node-red-admin
node-red-admin help

# installed modules
node-red-admin list


# search modules
node-red-admin search serial
node-red-admin search rfxcom
node-red-admin search zwave
node-red-admin search ble
node-red-admin search bluetooth
node-red-admin search sensortag

node-red-admin search beaglebone
node-red-admin search gpio

node-red-admin search mongodb
node-red-admin search redis
node-red-admin search cassandra
node-red-admin search elastic
node-red-admin search influxdb
node-red-admin search kafka

Remark: node-red-admin install <module> does not work ! Use npm install -g module

cd ~/.node-red
sudo npm install -g node-red-node-redis
sudo npm install -g node-red-contrib-kafka-consumer
sudo npm install -g node-red-node-mongodb

Restart Node-Red

node-red-admin list

With Docker

docker pull nodered/node-red-docker

Install extra nodes for Node-RED

Extra nodes are provided with the Node-RED community. There are listed here.

Serial for Geiger Counter

Sparkfun's geiger counter

Install the serial node (node-red-node-serialport)

npm install node-red-node-serialport

or

sudo npm install -g npm@2.x
npm install node-red-node-serialport@0.0.5

if node.js prior to 4.x (ie v0.10.x and v0.12.x)

Restart Node-RED with node-red -v.

Check the module in the list

node-red-admin list | grep serial

Check available serial ports (/dev/tty.usbserial* on MacOS X, /dev/ttyUSB* ...) with ls /dev/tty.*.

Connect the Geiger counter to the host.

Check available serial ports (/dev/tty.usbserial* on MacOS X, ...) with ls /dev/tty.*.

Add a node serial "Geiger" with a Settings of 9600/8/N/1 and 'Split input into fixed lenghts of 1 chars'.

Add a node debug.

Connect "Geiger" to debug.

Deploy the flow.

The Geiger Counter sends a random sequence of 0 and 1.

Add a node function "Count Particles" with a flow-scoped variable (geiger/count):

 1var COUNT='geiger/count';
 2
 3// initialise the counter to 0 if it doesn't exist already
 4var count = flow.get(COUNT)||0;
 5count += 1;
 6// store the value back
 7flow.set(COUNT,count);
 8// make it part of the outgoing msg object
 9msg.count = count;
10msg.payload = {};
11msg.payload.device = "geiger";
12msg.payload.count = count;
13
14node.log("Received particles : " + count);
15
16return msg;

Connect node "Geiger" to node "Count Particles".

Deploy the new flow.

Edit the node "Count Particles" and add the 2 following statements in order to display the count into the node's status.

14...
15setTimeout(function() { node.status({}); }, 1000);
16// The shape property can be: ring or dot.
17// The fill property can be: red, green, yellow, blue or grey
18node.status({fill:"green",shape:"dot",text:"#"+count}); 
19return msg;

Deploy the new flow.

Add a node inject "One minute timer" with a repeat interval of 1 minute.

Add a node function "Reset Particles Count" with a flow-scoped variable (geiger/count):

 1var COUNT='geiger/count';
 2
 3// initialise the counter to 0 if it doesn't exist already
 4var count = flow.get(COUNT)||0;
 5
 6msg.count = count;
 7msg.payload = {};
 8msg.payload.device = "geiger";
 9msg.payload.ppm = count;
10
11node.log("Reset counter at " + count);
12
13// make it part of the outgoing msg object
14count = 0;
15// store the value back
16flow.set(COUNT,count);
17
18return msg;

Connect node "One minute timer" to node "Reset Particles Count" and node "Reset Particles Count" to node debug.

Deploy the new flow.

The result is:

Geiger Flow

RFXCom for Oregon Weather Sensors

Install the rfxcom node (node-red-contrib-rfxcom)

cd ~/.node-red
npm install -g node-red-contrib-rfxcom

Restart Node-RED with node-red -v.

Check the module in the list

node-red-admin list | grep rfx

Connect the RFXCom receiver to the host.

Check available serial ports (/dev/tty.usbserial* on MacOS X, ...) with ls /dev/tty.*.

Add a node rfxcom-sensors "RFXCom" with the correct serial port.

Add a node debug display the full message (not only msg.payload).

Connect "RFXCom" to debug.

Deploy the flow.

The flow loos like that:

RFXCom Flow


RFXCom Receiver Oregon Thermo Sensor Oregon Baro Sensor Oregon UV Sensor

Serial for Arduino + Weather Shield

Sparkfun Weather Shield

Plug the SparkFun Weather Shield into the Arduino Leonardo. Connect the Weather Meters to the shield sockets.

Install the Arduino IDE on your host (link)

Install 2 extra libraries (Menu Sketch > Include Library > Add ZIP Library)

Select the right board (Arduino Leonardo) with the menu Tool

Load and unzip the Weather_Shield sketch bundle https://codeload.github.com/sparkfun/Weather_Shield/zip/master

Load the sketch Weather_Shield/firmware/Weather_Shield/Weather_Shield.ino into the Arduino Leonardo

Check the output with the menu Tool > Serial Monitor

The output looks like this:

$,winddir=-1,windspeedmph=3.1,windgustmph=117.7,windgustdir=-1,windspdmph_avg2m=3.1,winddir_avg2m=0,windgustmph_10m=117.7,windgustdir_10m=-1,humidity=33.6,tempf=75.2,rainin=3.04,dailyrainin=3.04,pressure=98257.75,batt_lvl=4.28,light_lvl=0.28,#


Install the serial node (node-red-node-serialport)

npm install node-red-node-serialport

or

sudo npm install -g npm@2.x
npm install node-red-node-serialport@0.0.5

if node.js prior to 4.x (ie v0.10.x and v0.12.x)

Restart Node-RED with node-red -v.

Check the module in the list

node-red-admin list | grep serial

Check available serial ports (/dev/tty.usbserial* on MacOS X, /dev/ttyUSB* ...) with ls /dev/tty.*.

Start Node-RED

node-red -v


Add a node debug

Add a node function "Clean Data" with the following statements:

1var m=msg.payload;
2var i=m.indexOf(",")+1;
3msg.payload=m.substr(i,m.lastIndexOf(",")-i);
4setTimeout(function() { node.status({}); }, 500)
5node.status({fill:"green",shape:"dot",text:"updated"});
6return msg;

Add a node serial "Weather Station" with settings 9600/8/N/1 and split input on charracter /n

Connect them together like that

Weather-flow.png


The flow is :

[{"id":"40c61a94.428894","type":"serial-port","z":"65e2c142.626cf8","serialport":"/dev/tty.usbmodem1451","serialbaud":"9600","databits":"8","parity":"none","stopbits":"1","newline":"\\n","bin":"false","out":"char","addchar":false},{"id":"e0626709.612a1","type":"serial in","z":"65e2c142.626cf8","name":"Weather Station","serial":"40c61a94.428894","x":200.5,"y":486.5,"wires":[["576a5389.61c4e4"]]},{"id":"bf78bff1.63e8a","type":"debug","z":"65e2c142.626cf8","name":"","active":true,"console":"false","complete":"payload","x":802.5,"y":488,"wires":[]},{"id":"576a5389.61c4e4","type":"function","z":"65e2c142.626cf8","name":"Clean data","func":"var m=msg.payload;\nvar i=m.indexOf(\",\")+1;\nmsg.payload=m.substr(i,m.lastIndexOf(\",\")-i);\nsetTimeout(function() { node.status({}); }, 500)\nnode.status({fill:\"green\",shape:\"dot\",text:\"updated\"});\nreturn msg;","outputs":1,"noerr":0,"x":498.5,"y":486.5,"wires":[["bf78bff1.63e8a"]]}]

Serial for LoRa Libelium

Libelium Waspmote with LoRa modem
Libelium Waspmote with LoRa modem
Libelium Waspmote with LoRa modem
Libelium Waspmote USB Dongle with LoRa modem on RPI2

Install the Waspmote PRO IDE from Libelium on your host (link)


Load the sketch SX_02a_TX_LoRa on the LoRa Waspmote.

 1/*
 2 *  ------ [SX_02a] - TX LoRa -------- 
 3 *
 4 *  Explanation: This example shows how to configure the semtech 
 5 *  module in LoRa mode and then send packets with plain-text payloads
 6 */
 7// Include this library to transmit with sx1272
 8#include <WaspSX1272.h>
 9
10// define the destination address to send packets
11uint8_t rx_address = 8;
12
13// status variable
14int8_t e;
15
16void setup()
17{
18  // Init USB port
19  USB.ON();
20  USB.println(F("SX_02a example"));
21  USB.println(F("Semtech SX1272 module TX in LoRa"));
22
23  USB.println(F("----------------------------------------"));
24  USB.println(F("Setting configuration:")); 
25  USB.println(F("----------------------------------------"));
26
27  // Init sx1272 module
28  sx1272.ON();
29
30  // Select frequency channel
31  e = sx1272.setChannel(CH_10_868);
32  USB.print(F("Setting Channel CH_10_868.\t state ")); 
33  USB.println(e);
34
35  // Select implicit (off) or explicit (on) header mode
36  e = sx1272.setHeaderON();
37  USB.print(F("Setting Header ON.\t\t state "));  
38  USB.println(e); 
39
40  // Select mode: from 1 to 10
41  e = sx1272.setMode(1);  
42  USB.print(F("Setting Mode '1'.\t\t state "));
43  USB.println(e);  
44
45  // Select CRC on or off
46  e = sx1272.setCRC_ON();
47  USB.print(F("Setting CRC ON.\t\t\t state "));
48  USB.println(e);  
49
50  // Select output power (Max, High or Low)
51  e = sx1272.setPower('L');
52  USB.print(F("Setting Power to 'L'.\t\t state "));  
53  USB.println(e); 
54
55  // Select the node address value: from 2 to 255
56  e = sx1272.setNodeAddress(2);
57  USB.print(F("Setting Node Address to '2'.\t state "));
58  USB.println(e);
59  USB.println();
60  
61  delay(1000);  
62  
63  USB.println(F("----------------------------------------"));
64  USB.println(F("Sending:")); 
65  USB.println(F("----------------------------------------"));
66}
67
68void loop()
69{
70  // Sending packet before ending a timeout
71  e = sx1272.sendPacketTimeout( rx_address, "This_is_a_new_message");
72
73  // Check sending status
74  if( e == 0 ) 
75  {
76    USB.println(F("Packet sent OK"));     
77  }
78  else 
79  {
80    USB.println(F("Error sending the packet"));  
81    USB.print(F("state: "));
82    USB.println(e, DEC);
83  } 
84  delay(2500); 
85}

Check with the IDE Serial monitor the output of the Waspmote

Load the sketch SX_02b_RX_LoRa on the LoRa Dongle.

 1/*  
 2 *  ------ [SX_02b] - RX LoRa -------- 
 3 *  Explanation: This example shows how to configure the semtech 
 4 *  module in LoRa mode and then receive packets with plain-text payloads
 5 */
 6// Include this library for transmit with sx1272
 7#include <WaspSX1272.h>
 8
 9// status variable
10int8_t e;
11
12void setup() 
13{
14  // Init USB port
15  USB.ON();
16  USB.println(F("SX_02b example"));
17  USB.println(F("Semtech SX1272 module RX in LoRa"));
18
19  USB.println(F("----------------------------------------"));
20  USB.println(F("Setting configuration:")); 
21  USB.println(F("----------------------------------------"));
22
23  // Init sx1272 module
24  sx1272.ON();
25
26  // Select frequency channel
27  e = sx1272.setChannel(CH_10_868);  
28  USB.print(F("Setting Channel CH_10_868.\t state ")); 
29  USB.println(e);
30
31  // Select implicit (off) or explicit (on) header mode
32  e = sx1272.setHeaderON();
33  USB.print(F("Setting Header ON.\t\t state ")); 
34  USB.println(e);
35
36  // Select mode: from 1 to 10
37  e = sx1272.setMode(1);
38  USB.print(F("Setting Mode '1'.\t\t state "));
39  USB.println(e);  
40
41  // Select CRC on or off
42  e = sx1272.setCRC_ON();
43  USB.print(F("Setting CRC ON.\t\t\t state ")); 
44  USB.println(e);  
45
46  // Select output power (Max, High or Low)
47  e = sx1272.setPower('L');
48  USB.print(F("Setting Power to 'L'.\t\t state ")); 
49  USB.println(e);  
50
51  // Select the node address value: from 2 to 255
52  e = sx1272.setNodeAddress(8);
53  USB.print(F("Setting Node Address to '8'.\t state "));
54  USB.println(e); 
55
56  delay(1000);  
57
58  USB.println(F("----------------------------------------"));
59  USB.println(F("Receiving:")); 
60  USB.println(F("----------------------------------------"));
61}
62
63void loop()
64{
65  // receive packet
66  e = sx1272.receivePacketTimeout(10000);
67
68  // check rx status
69  if( e == 0 )
70  {
71    USB.println(F("\nShow packet received: "));
72
73    // show packet received
74    sx1272.showReceivedPacket();
75  }
76  else
77  {
78    USB.print(F("\nReceiving packet TIMEOUT, state "));
79    USB.println(e, DEC);  
80  }
81}

Check with the IDE Serial monitor the output of the USB Dongle


Install the serial node (node-red-node-serialport)

npm install node-red-node-serialport

or

sudo npm install -g npm@2.x
npm install node-red-node-serialport@0.0.5

if node.js prior to 4.x (ie v0.10.x and v0.12.x)

Restart Node-RED with node-red -v.

Check the module in the list

node-red-admin list | grep serial

Check available serial ports (/dev/tty.usbserial* on MacOS X, /dev/ttyUSB*, /dev/ttyAMA*, /dev/ttyACM* ...) with ls /dev/tty.*.


The RX boards receive LoRa frames and output the following lines on the console when the TX boards are powered :

...
SX_02b example
Semtech SX1272 module RX in LoRa
----------------------------------------
Setting configuration:
----------------------------------------
Setting Channel CH_10_868.	 state 0
Setting Header ON.		 state 0
Setting Mode '1'.		 state 0
Setting CRC ON.			 state 0
Setting Power to 'L'.		 state 0
Setting Node Address to '8'.	 state 0
----------------------------------------
Receiving:
----------------------------------------

Show packet received: 
==============================
dest: 8
src: 2
packnum: 171
length: 26
retry: 0
payload (HEX): 546869735F69735F615F6E65775F6D657373616765
payload (string): This_is_a_new_message
==============================
...

Create a new flow or start Node-RED

Add a node debug

Add a node function "Extract RX Data" with the following statements

 1var prefix="payload (HEX): ";
 2var m=msg.payload;
 3var i=m.indexOf(prefix);
 4if(i===0) {
 5    msg.payload=new Buffer(m.substr(prefix.length),"HEX");
 6    setTimeout(function() { node.status({}); }, 500)
 7    node.status({fill:"green",shape:"dot",text:"updated"});
 8    return msg;
 9} else {
10    return null;
11}

Add a node serial "LoRa RX Modem" with settings 115200/8/N/1 and split input on character /n. On RPI, the port is /dev/ttyUSB0.

Connect them together like that

Waspmotelora-flow.png


The flow is :

[{"id":"3124f278.d5cc86","type":"serial-port","z":"3cf8afc1.fe41a","serialport":"/dev/ttyUSB2","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","newline":"\\n","bin":"false","out":"char","addchar":false},{"id":"8ea9bd5f.7ffac8","type":"serial in","z":"3cf8afc1.fe41a","name":"","serial":"3124f278.d5cc86","x":123.5,"y":137.5,"wires":[["a9a605c3.664548"]]},{"id":"32a2d4e0.54214c","type":"debug","z":"3cf8afc1.fe41a","name":"","active":true,"console":"false","complete":"false","x":495.5,"y":145,"wires":[]},{"id":"a9a605c3.664548","type":"function","z":"3cf8afc1.fe41a","name":"Extract RX Data","func":"var prefix=\"payload (HEX): \";\nvar m=msg.payload;\nvar i=m.indexOf(prefix);\nif(i===0) {\n    msg.payload=new Buffer(m.substr(prefix.length),\"HEX\");\n    setTimeout(function() { node.status({}); }, 500)\n    node.status({fill:\"green\",shape:\"dot\",text:\"updated\"});\n    return msg;\n} else {\n    return null;\n}","outputs":1,"noerr":0,"x":320.5,"y":247.5,"wires":[["32a2d4e0.54214c"]]}]


Serial for LoRaWAN Libelium

Libelium Waspmote with LoRaWAN modem

Install the Waspmote PRO IDE from Libelium on your host (link)

Load the sketch LoRaWAN_02_join_abp_send_unconfirmed (from Examples > 03. Communications > LoRaWAN) on the LoRaWAN Waspmote. (API documentation)

Add the following flow into the Node-RED server embedded in the Multitech gateway. This flow adapts the [Shttps://github.com/Lora-net/packet_forwarder/blob/master/PROTOCOL.TXT emtech packer forwarder protocol] to MQTT. TBC

Multitech Packet Forwarder Flow

The flow is :

[{"id":"5bf2579.78cd328","type":"mqtt-broker","broker":"192.168.0.101","port":"1883","clientid":""},{"id":"b1939dd4.d3375","type":"debug","name":"","active":true,"console":"false","complete":"false","x":852,"y":951,"z":"bcbfaccb.6b341","wires":[]},{"id":"23420539.4f4012","type":"udp in","name":"","iface":"","port":"1680","ipv":"udp4","multicast":"false","group":"","datatype":"buffer","x":254,"y":847,"z":"bcbfaccb.6b341","wires":[["7c343386.1d5f5c"]]},{"id":"7c343386.1d5f5c","type":"function","name":"Parse PUSH_DATA packet","func":"// See https://github.com/Lora-net/packet_forwarder/blob/master/PROTOCOL.TXT\n\n/*\n### 3.2. PUSH_DATA packet ###\n\nThat packet type is used by the gateway mainly to forward the RF packets \nreceived, and associated metadata, to the server.\n\n Bytes  | Function\n:------:|---------------------------------------------------------------------\n 0      | protocol version = 2\n 1-2    | random token\n 3      | PUSH_DATA identifier 0x00\n 4-11   | Gateway unique identifier (MAC address)\n 12-end | JSON object, starting with {, ending with }, see section 4\n*/\n\n\n\nvar from=msg[\"from\"];\nvar ip=msg[\"ip\"];\nvar fromip=msg[\"fromip\"];\n\nvar b = msg.payload;\n\nif(b.length < 12) return undefined;\n\nvar payload = {};\n\npayload[\"protocol\"] = b.readUInt8(0);\npayload[\"token\"] = b.readUInt16BE(1);\npayload[\"push_data_id\"] = b.readUInt8(3);\npayload[\"gateway_eui\"] = b.slice(4,12).toString(\"hex\");\nvar json = b.slice(12);\nif(json !== undefined && json.length > 0) {\n    payload[\"json\"] = JSON.parse(json);\n}\n    \n\nmsg.payload = payload;\nreturn msg;","outputs":1,"noerr":0,"x":540,"y":846,"z":"bcbfaccb.6b341","wires":[["b1939dd4.d3375","fadd4563.822ee8","36d9eb5c.4250d4"]]},{"id":"b38c07a5.0ae658","type":"udp out","name":"","addr":"127.0.0.1","iface":"","port":"1681","ipv":"udp4","outport":"","base64":false,"multicast":"false","x":854,"y":1044,"z":"bcbfaccb.6b341","wires":[]},{"id":"fadd4563.822ee8","type":"function","name":"Build PUSH_ACK packet","func":"// See https://github.com/Lora-net/packet_forwarder/blob/master/PROTOCOL.TXT\n\n/*\n### 3.3. PUSH_ACK packet ###\n\nThat packet type is used by the server to acknowledge immediately all the \nPUSH_DATA packets received.\n\n Bytes  | Function\n:------:|---------------------------------------------------------------------\n 0      | protocol version = 2\n 1-2    | same token as the PUSH_DATA packet to acknowledge\n 3      | PUSH_ACK identifier 0x01\n*/\n\nvar payload = new Buffer(4);\n\npayload[0] = msg.payload.protocol;\npayload.writeUInt16BE(msg.payload.token,1);\npayload[3] = 0x01;\n\nmsg.payload = payload;\n\nreturn msg;","outputs":1,"noerr":0,"x":546,"y":956,"z":"bcbfaccb.6b341","wires":[["b38c07a5.0ae658"]]},{"id":"36d9eb5c.4250d4","type":"mqtt out","name":"MQTT Uplink","topic":"gateway/up/008000000000aaaa","qos":"","retain":"","broker":"5bf2579.78cd328","x":855,"y":847,"z":"bcbfaccb.6b341","wires":[]},{"id":"e6274e97.c4455","type":"mqtt in","name":"MQTT Downlink","topic":"gateway/dn/008000000000aaaa","broker":"5bf2579.78cd328","x":247,"y":1123,"z":"bcbfaccb.6b341","wires":[["84741d8f.12f3c8","b1939dd4.d3375"]]},{"id":"84741d8f.12f3c8","type":"function","name":"Build TX_ACK packet","func":"// See https://github.com/Lora-net/packet_forwarder/blob/master/PROTOCOL.TXT\n\n/*\n### 5.5. TX_ACK packet ###\n\nThat packet type is used by the gateway to send a feedback to the server\nto inform if a downlink request has been accepted or rejected by the gateway.\nThe datagram may optionnaly contain a JSON string to give more details on\nacknoledge. If no JSON is present (empty string), this means than no error\noccured.\n\n Bytes  | Function\n:------:|---------------------------------------------------------------------\n 0      | protocol version = 2\n 1-2    | same token as the PULL_RESP packet to acknowledge\n 3      | TX_ACK identifier 0x05\n 4-end  | [optional] JSON object, starting with {, ending with }, see section 6*/\n\nvar payload = new Buffer(4+msg.payload.length);\n\npayload[0] = 2;\n\nmsg.payload.protocol;\n//payload.writeUInt16BE(msg.payload.token,1);\npayload[3] = 0x05;\nmsg.payload.copy(payload,4);\n\nmsg.payload = payload;\n\nreturn msg;","outputs":1,"noerr":0,"x":509,"y":1122,"z":"bcbfaccb.6b341","wires":[["b38c07a5.0ae658"]]}]


Test with mosquitto_sub -t "gateway/up/#" -d

Serial for LoRa Nucleo

STM32 Nucleo F411 + Semtech SX1276 Eval Kit

Install the serial node (node-red-node-serialport)

npm install node-red-node-serialport

or

sudo npm install -g npm@2.x
npm install node-red-node-serialport@0.0.5

if node.js prior to 4.x (ie v0.10.x and v0.12.x)

Restart Node-RED with node-red -v.

Check the module in the list

node-red-admin list | grep serial

Check available serial ports (/dev/tty.usbserial* on MacOS X, /dev/ttyUSB*, /dev/ttyAMA*, /dev/ttyACM* ...) with ls /dev/tty.*.

Compile and load the SX1276Receiver program https://developer.mbed.org/users/donsez/code/SX1276Receiver/ on the Nucleo board.

For the receiver, set line 16 to #define RX_MODE 1

For the transmitter, set line 16 to #define RX_MODE 0

Remark: select the right board (F411 or L152 for instance).

The RX boards receive LoRa frames and output the following lines on the console when the TX boards are powered :

...
>INFO RX modem=1 size=17 rssi=-41 snr=31 freq=868100000 bw=0 sf=12 cr=1 buffer=544553540004411d616263646566676869
RX;1;17;-41;31;868100000;0;12;1;544553540004411d616263646566676869
...

Create a new flow or start Node-RED

Add a node debug

Add a node function "Extract RX Data" with the following statements

 1var prefix="RX;";
 2var m=msg.payload;
 3var i=m.indexOf(prefix);
 4if(i===0) {
 5    msg.payload=m.substr(prefix.length);
 6    setTimeout(function() { node.status({}); }, 500)
 7    node.status({fill:"green",shape:"dot",text:"updated"});
 8    return msg;
 9} else {
10    return null;
11}

Add a node serial "LoRa RX Modem" with settings 115200/8/N/1 and split input on character /n. On RPI, the port is /dev/ttyACM0.

Connect them together like that

Nucleolora-flow.png


The flow is :


TODO

UDP for LoRaWAN

Add a node 'udp in' listening the port 8123.

Add a node 'function' "toString" with the following statement:

msg.payload=msg.payload.toString();
return msg;

Add a node 'debug'.

Connect them together.

Deploy the new flow.

Test the flow with the shell command

echo -n -e '{"device"="123456","temperature"=37.2}' > /dev/udp/127.0.0.1/8123

The flow looks like that:

UDP Flow

Add a node 'json' into the flow.

Now you can filter and send the output of a process to the flow througth an 'udp in' node.

TO BE CONTINUED

UDP for ESP8266 + PowerSensor

ESP8266 Module 12
ESP8266 Module 12 Arduino


Install the Arduino IDE on your host (link)

Add the "ESP8266 Modules" support with the Tools menu > Board Manager.

Select "NodeMCU 0.9 (ESP8266-12 Module)" in the Tools menu.

Load the following sketch on the ESP8266.

 1/*
 2From http://www.iotfrog.com/en/articles/article/227
 3*/
 4
 5#include <ESP8266WiFi.h>
 6#include <WiFiUDP.h>
 7
 8const char* ssid     = "iotdays";
 9const char* password = "eclipse2016";
10
11//IPAddress ipBroadCast(192,168,1,255);
12IPAddress ipBroadCast;
13
14unsigned int udpRemotePort = 8123;
15unsigned int udplocalPort = 8124;
16const int UDP_PACKET_SIZE = 48;
17
18char udpBuffer[ UDP_PACKET_SIZE];
19WiFiUDP udp;
20
21// Setup the Wifi connection
22void connectWifi() {
23  Serial.print("Connecting to ");
24  Serial.println(ssid);
25
26  //  Try to connect to wifi access point
27  WiFi.begin(ssid, password);
28  while (WiFi.status() != WL_CONNECTED) {
29    delay(500);
30    Serial.print(".");
31  }
32  Serial.println("");
33  Serial.println("WiFi connected");
34  Serial.print("IP address: ");
35  Serial.println(WiFi.localIP());
36
37  ipBroadCast = ~WiFi.subnetMask() | WiFi.gatewayIP();
38}
39
40// Send udp message
41void udpSend()
42{
43  // TODO read the current value of an analog pin
44  
45  strcpy(udpBuffer, "{\"device\"=\"12348266\",\"load\"=10.2}");
46  udp.beginPacket(ipBroadCast, udpRemotePort);
47  udp.write(udpBuffer, sizeof(udpBuffer));
48  udp.endPacket();
49  Serial.print("Broadcast: ");
50  Serial.println(udpBuffer);
51}
52
53// Setup hardware, serial port, and connect to wifi.
54void setup() {
55  Serial.begin(115200);
56  delay(10);
57  // We start by connecting to a WiFi network
58  connectWifi();
59  
60  Serial.println("Starting UDP");
61  // set udp port for listen
62  udp.begin(udplocalPort);
63  Serial.print("Local port: ");
64  Serial.println(udp.localPort());
65}
66
67// LOOP MAIN
68// Send udp packet each 10 secconds
69void loop() {
70  udpSend();
71  delay (10000);
72}

Add a node 'udp in' listening the port 8123 with a Buffer output.

Add a node 'function' "toStr" with the following statement:

1msg.payload=msg.payload.toString();
2return msg;

Add a node 'debug'.

Connect them together.

Deploy the new flow.

The flow looks like that:

UDP Flow

Remark: you can test the flow with this shell command

echo -n -e '{"device"="12348266","load"=10}' > /dev/udp/127.0.0.1/8123

The flow is:

[{"id":"b32d523b.fd02d8","type":"udp in","z":"a994a424.14415","name":"","iface":"","port":"8123","ipv":"udp4","multicast":"false","group":"","datatype":"utf8","x":147,"y":94,"wires":[["1658af1a.ebfd11"]]},{"id":"f732d1c6.93623","type":"debug","z":"a994a424.14415","name":"","active":true,"console":"false","complete":"payload","x":535,"y":94.5,"wires":[]},{"id":"1658af1a.ebfd11","type":"function","z":"a994a424.14415","name":"toStr","func":"setTimeout(function() { node.status({}); }, 1000);\n// The shape property can be: ring or dot.\n// The fill property can be: red, green, yellow, blue or grey\nnode.status({fill:\"green\",shape:\"dot\",text:\"receiving\"}); \nmsg.payload=msg.payload.toString();\nreturn msg;","outputs":1,"noerr":0,"x":336,"y":94,"wires":[["f732d1c6.93623"]]}]


Second part:

Plug the SCT-013 Current Clamp power shield into the ESP8266 Arduino board.

Compile and load the following sketch on the ESP8266 Arduino board.

 1#include <ESP8266WiFi.h>          //https://github.com/esp8266/Arduino
 2
 3//needed for library
 4#include <DNSServer.h>
 5#include <ESP8266WebServer.h>
 6#include <stdlib.h>
 7#include "EmonLib.h"             // Include Emon Library
 8
 9EnergyMonitor emon1;             // Create an instance
10const int ANALOG_PIN = A0; // The only analog pin on the Thing
11
12const char host[] = "52.50.55.74";
13const int port = 80;
14const char nodename[] = "sct013";
15const char apiKey[] = "&apikey=7af3b1772fa1b624ef73925ba117d562";
16
17
18const char* ssid     = "iotdays";
19const char* password = "eclipse2016";
20
21// Use WiFiClient class to create TCP connections
22WiFiClient client;
23
24
25void setup()
26{
27  Serial.begin(115200);
28  delay(10);
29  
30
31  // We start by connecting to a WiFi network
32
33  Serial.println();
34  Serial.println();
35  Serial.print("Connecting to ");
36  Serial.println(ssid);
37  WiFi.begin(ssid, password);
38
39  while (WiFi.status() != WL_CONNECTED) {
40    delay(500);
41    Serial.print(".");
42  }
43
44  Serial.println("");
45  Serial.println("WiFi connected");
46  Serial.println("IP address: ");
47  Serial.println(WiFi.localIP());
48  emon1.current(A0, 29.1);       // Current: input pin, calibration.
49}
50
51void loop()
52{
53  Serial.print("waiting a delay\n");
54  delay(5000);
55
56  Serial.print("connecting to ");
57  Serial.println(host);
58
59  double Irms = emon1.calcIrms(1480);  // Calculate Irms only
60  Serial.println("begin loop");
61
62  const int httpPort = 80;
63  if (!client.connect(host, httpPort)) {
64    Serial.println("connection failed");
65    return;
66  }
67
68  // This will send the request to the server
69  const String url =  "/input/post.json?node=" + String(nodename) + "&json={power:" + String(Irms * 1.414 * 235 / 10) + "}" + String(apiKey);
70  client.print("GET " + url + " HTTP/1.1\r\n" +
71               "Host:" + host + "\r\n" +
72               "Connection: close\r\n\r\n");
73  Serial.print("Requesting URL: ");
74  Serial.println(url);
75
76  delay(10);
77
78  // Read all the lines of the reply from server and print them to Serial
79  while (client.available()) {
80    String line = client.readStringUntil('\r');
81    Serial.print(line);
82  }
83
84  Serial.println();
85  Serial.println("closing connection");
86}

Change the Node-RED to display the received data.

Third part: Change the shetch in order to use MQTT for the message transport : see https://github.com/tuanpmt/esp_mqtt

ACR122U NFC Reader

Plug the ACR122U NFC reader in the host and check it with lsusb

Install LibNFC (on Debian)

sudo apt-get install libnfc-dev libnfc-bin libnfc-examples
sudo nfc-list

Launch nfc-poll and put a NFC card/tag on the reader

sudo nfc-poll -v

The ID of the NFC card/tag is prefixed by the string UID (NFCID1):.

Execute the following script sudo ./nfcevent.sh:

#!/bin/sh
while true 
do
    nfc-poll | grep "UID (NFCID1):" > /tmp/nfc.log
done

Into the Node-RED dashboard, create a new flow.

Add a node tail for reading the tail of the log file containing the card/tags identifiers.

Add a node debug.

Connect the node tail to the node debug.

Deploy the new flow.

Add a node function "Build message" with the following statements:

 1var m=msg.payload;
 2var i=m.indexOf(":");
 3if(i>=0) {
 4    var tid = m.substr(i+1).replace(/\s+/g, '');
 5    msg.payload={}
 6    msg.payload.device="acr122u";
 7    msg.payload.nfc=tid;
 8    return msg;
 9}
10return null;

Connect the node tail to the node "Build message" and the node "Build message" to the node debug.

Deploy the new flow.


Edit the node "Build message" and add the 2 following statements in order to display the last tid into the node's status during one second.

 7    ...
 8    setTimeout(function() { node.status({}); }, 1000);
 9    // The shape property can be: ring or dot.
10    // The fill property can be: red, green, yellow, blue or grey
11    node.status({fill:"green",shape:"dot",text:"#"+tid}); 
12    return msg;
13}
14return null;

Deploy the new flow.


Sigfox Weather Station : Sigfox Areku Board + DHT11

Connect the DHT11 pins into the Areku board pins (or the Akene shield with an Arduino or STM32 Nucleo boards).

  • + --> 5V
  • - --> GND
  • OUT --> D2

Install the libraries Areku and DHT11 libraries into the Arduino IDE.

Compile and load the following sketch into the Areku board. The board type of the Areku board is "Uno".

 1#include <SoftwareSerial.h>
 2#define RX_PIN 5
 3#define TX_PIN 4
 4
 5#include "DHT.h"
 6
 7#define DHTPIN 2     // what pin we're connected to
 8
 9// Uncomment whatever type you're using!
10#define DHTTYPE DHT11   // DHT 11 
11//#define DHTTYPE DHT22   // DHT 22  (AM2302)
12//#define DHTTYPE DHT21   // DHT 21 (AM2301)
13
14// Connect pin 1 (on the left) of the sensor to +5V
15// Connect pin 2 of the sensor to whatever your DHTPIN is
16// Connect pin 4 (on the right) of the sensor to GROUND
17// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor
18
19DHT dht(DHTPIN, DHTTYPE);
20
21SoftwareSerial sigfox(RX_PIN,TX_PIN);
22
23// Sigfox message size is 12 bytes max.
24#define BUFFERSIZE 256
25char downlinkbuffer[BUFFERSIZE];
26
27// Send message every 11 minutes (max 140 messages per day)
28#define PERIOD 660000
29
30void getDownlinkLine(char * buffer)
31{
32  uint8_t idx = 0;
33  char c;
34  do
35  {
36    while (sigfox.available() == 0) ; // wait for a char this causes the blocking
37    c = sigfox.read();
38    buffer[idx++] = c;
39  }
40  while (c != '\n' && c != '\r' && idx >= BUFFERSIZE);
41  buffer[idx] = 0;
42}
43
44void setup(){
45  Serial.begin(9600);
46  sigfox.begin(9600);
47  dht.begin();
48}
49
50void loop(){
51  // Reading temperature or humidity takes about 250 milliseconds!
52  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
53  float fh = dht.readHumidity();
54  float ft = dht.readTemperature();
55
56  // check if returns are valid, if they are NaN (not a number) then something went wrong!
57  if (isnan(ft) || isnan(fh)) {
58    Serial.println("Failed to read from DHT");
59  } else {
60    Serial.print("Temperature: "); 
61    Serial.print(ft);
62    Serial.println(" *C");
63    Serial.print("Humidity: "); 
64    Serial.print(fh);
65    Serial.println(" %\t");
66    
67    Serial.print("Send message\n");
68    sigfox.write("AT$SF=");
69    
70    sigfox.print((byte)ft, HEX);
71    sigfox.write(" ");
72    sigfox.print((byte)fh, HEX);
73    
74    sigfox.write("\n");
75    
76    getDownlinkLine(downlinkbuffer);
77    Serial.print(downlinkbuffer);
78    Serial.print("\n");
79  
80    Serial.print("Wait ");
81    Serial.print(PERIOD/1000);
82    Serial.print(" second before next uplink\n");
83  
84  }
85  delay(PERIOD);
86 }

Check with the IDE Serial monitor the USB output of the board.

Install and run the following Node.js script:

 1var PORT = 3000;
 2var PATH = '/sigfox';
 3
 4//var BROKER_URL = "mqtt://localhost";
 5var BROKER_URL = "mqtt://test.mosquitto.org";
 6var TOPIC = "iotdays/sensors/sigfox";
 7
 8var express = require('express');
 9var app = express();
10
11var mqtt    = require('mqtt');
12var client  = mqtt.connect(BROKER_URL);
13var mqttConnected = false;
14 
15client.on('connect', function () {
16  mqttConnected = true;
17  console.log('Sigfox callback server : MQTT connected to ',BROKER_URL);
18});
19
20client.on('reconnect', function () {
21  mqttConnected = true;
22  console.log('Sigfox callback server : MQTT reconnected to ',BROKER_URL);
23});
24
25client.on('offline', function () {
26  mqttConnected = false;
27  console.log('Sigfox callback server : MQTT offline ');
28});
29
30client.on('close', function () {
31  mqttConnected = false;
32  console.log('Sigfox callback server : MQTT closed');
33});
34
35client.on('error', function (error) {
36  mqttConnected = false;
37  console.log('Sigfox callback server : MQTT Error ',error);
38});
39
40
41app.get(PATH, function (req, res) {
42  console.log("Received ", JSON.stringify(req.query));
43  if(mqttConnected) {
44	client.publish(TOPIC, JSON.stringify(req.query));
45	res.send('Callback received');  
46  } else {
47  	res.status(500).send('Could not delivered callback');
48  }
49});
50
51app.listen(PORT, function () {
52  console.log('Sigfox callback server listening on port ', PORT);
53});
npm init
npm install express --save
sudo npm install mqtt --save
cat package.json
node server.js

Configure the callback http://52.50.55.74:3000/sigfox?data={data}&id={device}&time={time}&snr={snr}&station={station}&avgSnr={avgSnr}&rssi={rssi}&lat={lat}&lng={lng}&seqNumber={seqNumber}&duplicate={duplicate} for the device into the Sigfox backend. (account is required)

Create a flow with a MQTT in node and a debug node.

Parse and display the values sent by the Sigfox backend : device, time, duplicate, snr, station, data, avgSnr, lat, lng, rssi, seqNumber

TBC

Remarks:

  • The Sigfox modem can not send more than 144 messages due to the ETSI regulation.
  • A Sigfox message contains up to 12 bytes (authenticated but not encrypted)

Sigfox Patrol Man : Sigfox Areku Board + Sparkfun's Weather Station Shield

Sparkfun Weather Shield

Plug the SparkFun Weather Shield into the Areku board. Plug the Weather Meters into the shield sockets.

Install the Arduino IDE on your host (link)

Install 2 extra libraries (Menu Sketch > Include Library > Add ZIP Library)

Select the right board (Arduino Uno) for the Akeru board with the menu Tool

Load and unzip the Weather_Shield sketch bundle https://codeload.github.com/sparkfun/Weather_Shield/zip/master

Load the sketch Weather_Shield/firmware/Weather_Shield/Weather_Shield.ino into the Arduino Leonardo

Check the output with the menu Tool > Serial Monitor

TODO

Sigfox Patrol Man : Sigfox Areku Board + Adafruit NFC Shield

Install the libraries Areku and Adafruit_PN532 (https://github.com/PM2M-2016-NFCSigfox/pm2m/tree/master/arduino/libraries) into the Arduino IDE.

Compile and load the sketch into the Areku board. (https://github.com/PM2M-2016-NFCSigfox/pm2m/blob/master/arduino/rondesNfc/rondesNfc.ino). The board type of the Areku board is "Uno".

 1#define DELAY_BETWEEN_MESSAGES 10000
 2#include <Akeru.h>
 3
 4#include <Adafruit_PN532.h>
 5#include <SPI.h>
 6#include <SoftwareSerial.h>
 7
 8#define PN532_CS 10 // La pin CS peut être connectée à la sortie D9 ou D10.
 9Adafruit_PN532 nfc(PN532_CS);
10#define NFC_DEMO_DEBUG 1
11
12void setup()
13{
14#ifdef NFC_DEMO_DEBUG
15    Serial.begin(9600); // Vérification liaison série.
16    // Init modem
17    Akeru.begin();
18    Serial.println("Bonjour!");
19#endif
20    nfc.begin(); // Démarrage puce PN532.
21
22    uint32_t versiondata = nfc.getFirmwareVersion();
23
24    if (!versiondata) {
25#ifdef NFC_DEMO_DEBUG // Vérification PN532.
26        Serial.print("Puce PN532 absente");
27#endif
28        while (1)
29            ;
30    }
31#ifdef NFC_DEMO_DEBUG // Vérification paramétrage de la puce.
32    Serial.print("Puce detectee, PN5");
33    Serial.println((versiondata >> 24) & 0xFF, HEX);
34    Serial.print("Firmware version: ");
35    Serial.print((versiondata >> 16) & 0xFF, DEC);
36    Serial.print('.');
37    Serial.println((versiondata >> 8) & 0xFF, DEC);
38    Serial.print("Supports ");
39    Serial.println(versiondata & 0xFF, HEX);
40
41#endif
42    nfc.SAMConfig(); // Configuration de la carte pour lire des tags et cartes RFID.
43}
44
45void loop()
46{
47
48    // Attente de disponiblité (envoi d'un messages toutes les 11 minutes : 140 messages par jour max)
49    while (!Akeru.isReady()) {
50        Serial.println("Modem en mode attente.");
51        delay(2500);
52    }
53
54    Serial.println("Modem OK");
55
56    uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer pour stocker l'UID NFC
57    uint8_t uidLength; // Taille de l'UID (4 or 7 octets)
58
59    bool success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
60
61    if (success) {
62        Serial.print("UID Length: ");
63        Serial.print(uidLength, DEC);
64        Serial.println(" bytes");
65
66        Serial.print("UID Value: ");
67
68        for (uint8_t i = 0; i < uidLength; i++) {
69            Serial.print(" 0x");
70            Serial.print((byte)uid[i], HEX);
71        }
72        Serial.println("");
73
74        // Envoyer les données
75        if (Akeru.send(uid, uidLength)) {
76            Serial.println("Send OK");
77        }
78        else {
79            Serial.println("Send NOK");
80        }
81        Serial.print("Mode attente pendant ");
82        Serial.print(DELAY_BETWEEN_MESSAGES);
83        Serial.println("ms.");
84        delay(DELAY_BETWEEN_MESSAGES);
85    }
86    else {
87        Serial.println("Timed out waiting for a card");
88    }
89}


Check with the IDE Serial monitor the USB output of the board and put a NFC tag on the PCB antenna of the Adafruit NFC Shield.

Install and run the following Node.js script:

 1var PORT = 3000;
 2var PATH = '/sigfox';
 3
 4//var BROKER_URL = "mqtt://localhost";
 5var BROKER_URL = "mqtt://test.mosquitto.org";
 6var TOPIC = "iotdays/sensors/sigfox";
 7
 8var express = require('express');
 9var app = express();
10
11var mqtt    = require('mqtt');
12var client  = mqtt.connect(BROKER_URL);
13var mqttConnected = false;
14 
15client.on('connect', function () {
16  mqttConnected = true;
17  console.log('Sigfox callback server : MQTT connected to ',BROKER_URL);
18});
19
20client.on('reconnect', function () {
21  mqttConnected = true;
22  console.log('Sigfox callback server : MQTT reconnected to ',BROKER_URL);
23});
24
25client.on('offline', function () {
26  mqttConnected = false;
27  console.log('Sigfox callback server : MQTT offline ');
28});
29
30client.on('close', function () {
31  mqttConnected = false;
32  console.log('Sigfox callback server : MQTT closed');
33});
34
35client.on('error', function (error) {
36  mqttConnected = false;
37  console.log('Sigfox callback server : MQTT Error ',error);
38});
39
40
41app.get(PATH, function (req, res) {
42  console.log("Received ", JSON.stringify(req.query));
43  if(mqttConnected) {
44	client.publish(TOPIC, JSON.stringify(req.query));
45	res.send('Callback received');  
46  } else {
47  	res.status(500).send('Could not delivered callback');
48  }
49});
50
51app.listen(PORT, function () {
52  console.log('Sigfox callback server listening on port ', PORT);
53});
npm init
npm install express --save
sudo npm install mqtt --save
cat package.json
node server.js

Configure the callback http://52.50.55.74:3000/sigfox?data={data}&id={device}&time={time}&snr={snr}&station={station}&avgSnr={avgSnr}&rssi={rssi}&lat={lat}&lng={lng}&seqNumber={seqNumber}&duplicate={duplicate} for the device into the Sigfox backend. (account is required)

Create a flow with a MQTT in node and a debug node.

Parse and display the values sent by the Sigfox backend : device, time, duplicate, snr, station, data, avgSnr, lat, lng, rssi, seqNumber

TBC

Remarks:

  • The Sigfox modem can not send more than 144 messages due to the ETSI regulation.
  • A Sigfox message contains up to 12 bytes (authenticated but not encrypted)

LoRa Patrol Man : STM32 Nucleo + NFC Shield

See https://github.com/PM2M2016-STM32NUCLEO/M2M

Arduino 101 BLE

TODO


Intel Quark D2000

TODO

SensorTag2 BLE

TODO

Follow the instructions here : https://github.com/uwefassnacht/ti-sensor-tag-demo


STEVAL-WESU1

TODO

K8055 Experiment IO Board

TODO


Johnny-Five

TODO

https://github.com/monteslu/node-red-contrib-gpio

Pycom IoT Boards

LoPy (LoRa)
SiPy (Sigfox)
File:Fipy.png
FiPy (the full monty)
  1. Pycom LoPy
  2. Pycom SiPy
  3. Pycom FiPy

TODO

Plot geolocated devices on a Leaflet map

Install [1], a Node-RED node to provide a web page of a world map for plotting things on.

npm install node-red-contrib-web-worldmap 
# restart Node-RED
My Lab
[
    {
        "id": "3511f624.ade2aa",
        "type": "worldmap",
        "z": "ffdc6633.be43c8",
        "name": "Test Map",
        "lat": "45",
        "lon": "5",
        "zoom": "",
        "layer": "Esri Satellite",
        "cluster": "",
        "maxage": "",
        "usermenu": "show",
        "layers": "show",
        "panit": "true",
        "x": 1020,
        "y": 1780,
        "wires": []
    },
    {
        "id": "88d26ee5.8ca6b8",
        "type": "inject",
        "z": "ffdc6633.be43c8",
        "name": "",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "repeat": "",
        "crontab": "",
        "once": false,
        "x": 620,
        "y": 1780,
        "wires": [
            [
                "66ba0382.730ce4"
            ]
        ]
    },
    {
        "id": "66ba0382.730ce4",
        "type": "function",
        "z": "ffdc6633.be43c8",
        "name": "Inject pos",
        "func": "\n\n    msg.payload = {\n        name:\"My Lab\", \n        lat:45.19053, lon:5.76691\n        \n    };\n\n  return msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 840,
        "y": 1780,
        "wires": [
            [
                "3511f624.ade2aa"
            ]
        ]
    },
    {
        "id": "c55666e6.f84c7",
        "type": "worldmap in",
        "z": "ffdc6633.be43c8",
        "name": "",
        "x": 980,
        "y": 1880,
        "wires": [
            [
                "ed61e82.61e0518"
            ]
        ]
    },
    {
        "id": "ed61e82.61e0518",
        "type": "debug",
        "z": "ffdc6633.be43c8",
        "name": "",
        "active": true,
        "console": "false",
        "complete": "payload",
        "x": 1170,
        "y": 1880,
        "wires": []
    }
]

Browse http://localhost:1880/worldmap/

NodeRED World Map

Display sensors data into a Freeboard dashboard

http://noderedguide.com/lecture-7-dashboards-and-ui-techniques-for-node-red/

Display sensors data into a Cayenne dashboard

TODO


Publish and subscribe with ROS Robots

TODO

Install node-red-contrib-ros

npm install node-red-contrib-ros

Install ROS on your favorite robotic platform (RobAIR, ...) with Docker

TODO

Install Mosquitto

On MacOS X

brew install mosquitto
ln -sfv /usr/local/opt/mosquitto/*.plist ~/Library/LaunchAgents
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mosquitto.plist

echo Test connectivity
BROKER=localhost
mosquitto_sub -h $BROKER -t '$SYS/#'


On Debian

sudo apt-get install mosquitto
sudo service mosquitto status
sudo apt-get install mosquitto-clients
echo Test connectivity
BROKER=localhost
mosquitto_sub -h $BROKER -t '$SYS/#'

With Docker

docker pull eclipse-mosquitto
docker run -it -p 1883:1883 -p 9001:9001 -v mosquitto.conf:/mosquitto/config/mosquitto.conf -v /mosquitto/data -v /mosquitto/log eclipse-mosquitto

https://hub.docker.com/_/eclipse-mosquitto/


Test local Mosquitto broker

BROKER=localhost
mosquitto_sub -d -h $BROKER -t 'iotdays/sensors/#' &
mosquitto_pub -d -h $BROKER -t 'iotdays/sensors/gw0001' -m '{"device"="123456","temperature"=37.2}'
mosquitto_pub -d -h $BROKER -t 'iotdays/sensors/gw0001' -m '{"device"="345678","temperature"=23.2,"humidity"=50}'
mosquitto_pub -d -h $BROKER -t 'iotdays/sensors/gw0002' -m '{"device"="acr122u","nfc"="04ddf0f9232580"}'
sleep 1
pkill mosquitto_sub


Test public Mosquitto broker

BROKER=test.mosquitto.org
mosquitto_sub -d -h $BROKER -t 'iotdays/sensors/#' &
mosquitto_pub -d -h $BROKER -t 'iotdays/sensors/gw0001' -m '{"device"="123456","temperature"=37.2}'
mosquitto_pub -d -h $BROKER -t 'iotdays/sensors/gw0001' -m '{"device"="345678","temperature"=23.2,"humidity"=50}'
mosquitto_pub -d -h $BROKER -t 'iotdays/sensors/gw0002' -m '{"device"="acr122u","nfc"="04ddf0f9232580"}'
pkill mosquitto_sub


More:

Using MQTT for collecting sensors data

In the flows defined above, add a node mqtt out with a new MQTT broker localhost:1883 and a topic iotdays/sensors/gwXXXX where gwXXXX is the name of the host.

Check the publishing with mosquitto_sub

BROKER=localhost
mosquitto_sub -d -h $BROKER -t 'iotdays/sensors/#' &

Create a new flow for subscribing messages from the Mosquitto MQTT broker.

Add a node debug for displaying the full message.

Add a node mqtt in with with a new MQTT broker localhost:1883 and a topic iotdays/sensors#

Connect the node mqtt in to the node debug.

Deploy the new flow.

Install InfluxDB

OS X (via Homebrew)

brew update
brew install influxdb

Ubuntu & Debian (64-bit)

wget http://dl.influxdata.com/influxdb/releases/influxdb_0.12.2-1_amd64.deb
sudo dpkg -i influxdb_0.12.2-1_amd64.deb

Ubuntu & Debian (ARM)

wget  --no-check-certificate http://dl.influxdata.com/influxdb/releases/influxdb_0.12.2-1_armhf.deb
sudo dpkg -i influxdb_0.12.2-1_armhf.deb

Docker

docker pull influxdb
docker run -p 8083:8083 -p 8086:8086 \
      -v influxdb:/var/lib/influxdb \
      influxdb

https://hub.docker.com/_/influxdb/

Populate InfluxDB from Node-RED

Launch the InfluxDB shell

influx

Enter the following InfluxDB statements

1create database iotdb
2show retention policies on iotdb
3create retention policy three_hours_iot_training on iotdb duration 3h replication 1 default
4show retention policies on iotdb
5exit

In the Node-RED dashboard, create a new flow to collect sensors data from the MQTT server.

Install the Node-RED InfluxDB node.

Restart Node-RED.

Add a node mqtt in "MQTT Broker" for subscribing to the MQTT server (broker is test.mosquitto.org or localhost topic is iotdays/sensors/#)

Add a node function "Tranform into time series" to format the JSON messages into time series messages.

Add a node influxdb out "IoT Database" with the InfluxDB server.

Connect the node "MQTT Broker" to node "Tranform into time series" and to the node "Tranform into time series" to node "IoT Database".

The flow looks like than:

MQTT to InfluxDB flow


Launch the InfluxDB shell

influx

Enter the following InfluxDB statements

 1use iotdb
 2show measurements
 3show series
 4
 5select * from temperature
 6select * from humidity
 7select * from nfc
 8select * from ppm
 9select * from current
10select * from sigfox
11select * from lora
12select * from weather

Extra for Arduino and Weather Shield

Add a node influxdb out

Add a node function with the following statements:

1var result = {};
2msg.payload.split(',').forEach(function(x){
3    var arr = x.split('=');
4    arr[1] && (result[arr[0]] = parseFloat(arr[1]));
5});
6msg.payload=result;
7return msg;

Connect the 2 additionnal nodes like that:

Weather-influxdb.png

The flow is:

[{"id":"57400c2a.74f84c","type":"influxdb","z":"65e2c142.626cf8","hostname":"localhost","port":"8086","database":"iotdb","name":""},{"id":"40c61a94.428894","type":"serial-port","z":"65e2c142.626cf8","serialport":"/dev/tty.usbmodem1451","serialbaud":"9600","databits":"8","parity":"none","stopbits":"1","newline":"\\n","bin":"false","out":"char","addchar":false},{"id":"e0626709.612a1","type":"serial in","z":"65e2c142.626cf8","name":"Weather Station","serial":"40c61a94.428894","x":200.5,"y":486.5,"wires":[["576a5389.61c4e4"]]},{"id":"bf78bff1.63e8a","type":"debug","z":"65e2c142.626cf8","name":"","active":true,"console":"false","complete":"payload","x":802.5,"y":488,"wires":[]},{"id":"576a5389.61c4e4","type":"function","z":"65e2c142.626cf8","name":"Clean data","func":"var m=msg.payload;\nvar i=m.indexOf(\",\")+1;\nmsg.payload=m.substr(i,m.lastIndexOf(\",\")-i);\nsetTimeout(function() { node.status({}); }, 500)\nnode.status({fill:\"green\",shape:\"dot\",text:\"updated\"});\nreturn msg;","outputs":1,"noerr":0,"x":498.5,"y":486.5,"wires":[["86b78cd4.e2d548","bf78bff1.63e8a"]]},{"id":"86b78cd4.e2d548","type":"function","z":"65e2c142.626cf8","name":"Format as InfluxDB line","func":"var result = {};\nmsg.payload.split(',').forEach(function(x){\n    var arr = x.split('=');\n    arr[1] && (result[arr[0]] = parseFloat(arr[1]));\n});\nmsg.payload=result;\nreturn msg;","outputs":1,"noerr":0,"x":667.5,"y":610,"wires":[["1a959fff.cd4668","bf78bff1.63e8a"]]},{"id":"1a959fff.cd4668","type":"influxdb out","z":"65e2c142.626cf8","influxdb":"57400c2a.74f84c","name":"","measurement":"weather","x":908.5,"y":704,"wires":[]}]

Start the InfluxDB shell:

influx

Create the database with the foolowing statements:

1create database iotdb
2show retention policies on iotdb
3create retention policy three_hours_iot_training on iotdb duration 3h replication 1 default
4show retention policies on iotdb
5
6use iotdb
7show measurements
8select * from weather

Install Chronograf

https://influxdata.com/downloads/#chronograf

OS X (via Homebrew)

brew update
brew install homebrew/binary/chronograf

Ubuntu & Debian

wget https://s3.amazonaws.com/get.influxdb.org/chronograf/chronograf_0.12.0_amd64.deb
sudo dpkg -i chronograf_0.12.0_amd64.deb

Remark: Chronograf configuration directory is ~/chronograf.db

Docker

https://hub.docker.com/_/chronograf/

Visualize sensors data into the Chronograf dashboard

TODO

Browse https://localhost:10000/

Configure the InfluxDB datasource

Definition of a chart into Chronograf GUI Chronograf Dashboard

Install Grafana (2.6)

On Debian

wget https://grafanarel.s3.amazonaws.com/builds/grafana_2.6.0_amd64.deb
sudo dpkg -i xzvf grafana_2.6.0_amd64.deb
sudo service grafana-server start

Docker

docker pull grafana/grafana

https://hub.docker.com/r/grafana/grafana/

On Raspian Jessie

See https://github.com/heziegl/rpi-grafana

Visualize sensors data into the Grafana dashboard

Browse http://localhost:3000

Login with username:password admin:admin

Change your admin password (optional)

Create a new dashboard

Add a data source (InfluxDB 0.9) iotdb (http://localhost:8086 direct root:root)

Save the data source

Enable dashboard edition.

Add a row.

Add a graph in the row.

Edit the graph.

Edit the query for the graph for the data source.

Save the dashboard.

Duplicate the graph and change the measurement in the query

Duplicate the graph and aggregate (mean) all measurements of the same type (temperature, humidity).

Set the timeline and the refresh time.

Save the dashboard.

Move and resize the graphs into the dashboard.

Save the dashboard.

See Grafana

The result should look like that

Grafana for IoT Dashboard

Install Apache Spark

See Spark

Process a realtime stream of sensors data with Apache Spark

TODO

 1import org.eclipse.paho.client.mqttv3._
 2import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence
 3
 4import org.apache.spark.storage.StorageLevel
 5import org.apache.spark.streaming.{Seconds, StreamingContext}
 6import org.apache.spark.streaming.mqtt._
 7import org.apache.spark.SparkConf
 8
 9val brokerUrl = "tcp://localhost:1883"
10val topic = "iotdays/sensors/#"
11val ssc = new StreamingContext(sc, Seconds(60))
12val sensordatas = MQTTUtils.createStream(ssc, brokerUrl, topic, StorageLevel.MEMORY_ONLY_SER_2)
13
14TODO
15
16ssc.start()
17ssc.awaitTermination()

See

Annexes

Raspian Jessie commands

TODO

IBM IoT Watson

TODO

OVH IoT PaaS

With OpenTSDB and Grafana.