XBee Mesh Network Raspberry Pi (Coordinator) and Arduino's (Routers) (openHAB,Node-RED,C++)

Exploring openHAB & openHABian.
rwblinn
Site Admin
Posts: 224
Joined: 07 Oct 2017, 12:16

XBee Mesh Network Raspberry Pi (Coordinator) and Arduino's (Routers) (openHAB,Node-RED,C++)

Postby rwblinn » 21 Mar 2018, 15:26

openHAB2 Experiment XBee Point-to-Multipoint Mesh Network.
Version 20180321

Objectives
To build a XBee Point-to-Multipoint (API mode) Mesh Network, using a Raspberry Pi (as XBee Coordinator) and 2 Arduino's (as XBee Routers) controlled via openHAB & Node-RED.

Two way communication is tested by sending data from the openHAB Raspberry Pi server, to the Arduino’s to act upon, and the Arduino’s to send data back to the openHAB server to act accordingly.
  • Arduino 1 (XBee Router 1) has a BMP180 sensor connected and sends temperature & pressure data in regular intervals.
  • Arduino 2 (XBee Router 2) has a LED RED connected which is switched via openHAB2 Basic UI. A random number is send back in response.
  • Node-RED is used to switch the LED and to display the temperature, pressure & random number in dashboard UI gauges.
  • openHAB2 Basic-UI sitemap displays the temperature, pressure & random number and enables to switch the LED RED.

This experiment is a proof-of-concept for two way communication using ZigBee protocol with XBee devices.
Solutions based on this concept could be:
  • Weather Station sending data from Arduino to receiver (i.e. Home Automation)
  • Control a Robot
  • Home Automation Motion Detector
  • and many more

Image

Concept
Arduino1 acting as Router1:
The Arduino reads in regular intervals (1s) the BMP180 sensor data Temperature and Pressure. The BMP180 is connected to the Arduino by using I2C pins (SDA,SCL).
The Arduino converts the data into an 9 byte payload (byte[0]=ID as char "R" 1 byte, bytes[1-4]=Temperature as long 4 bytes, Bytes[5-8]=Pressure as long 4 bytes) which are send via an XBee.
The XBee (Series 2 XB24-ZB Module) is placed on an Arduino XBee Shield. The XBee is configured in API-Mode as a Router with AP=2.
The data is send to an XBee (Series 2 XB24-ZB Module) connected to a Raspberry Pi via an XBee Explorer USB. The XBee is configured in API-Mode as a Coordinator with AP=2.
Node-RED received the data and converts the 9 byte payload into 2 messages Temperature and Pressure which are used to update openHAB items.
The first byte holding the Arduino ID is just logged.
In openHAB, 2 items holding the Temperature and Pressure are textual configured. The items are displayed via a simple sitemap in a browser via the openHAB Basic-UI.

Arduino2 acting as Router2:
An openHAB switch Item LED sends ON | OFF to Node-RED flow node openhab-in which routes to a Function node.
The Function node builds the payload (1 byte array) for the xbee-tx node, which sends the data to the receiving XBee router (determined by its MAC address) connected to an Arduino.
The 1 byte payload contains the LED state (brightness 0 - 255) (byte 1). The xbee-tx node uses the XBee Coordinator connected to the Raspberry Pi.
The Arduino receives the 1 byte array via the serial line (96008N1) to which the XBee Router is connected. Depending the byte array content, the LED brightness is set (0=OFF,255=ON).
The Arduino response back to the XBee Coordinator. The response is a 9 byte array, containing Arduino ID number (byte 0), a Random Number bytes[1-4] and dummy data bytes[5-8].
Node-RED received the data and converts the 9 byte payload into 1 message Random Number which is used to update openHAB items.
The first byte holding the Arduino ID is just logged.
In openHAB, 2 item for the LED switch and the Random Number are textual configured. The items are displayed via a simple sitemap in a browser via the openHAB Basic-UI.

Hardware
  • XBee Coordinator
  • 1x Raspberry Pi 3 Model B v1.2
  • 1x XBee Explorer USB - to configure the XBee Modules and run as XBee Coordinator connected to the Raspberry Pi.
  • 1x XBee XB24-ZB Module (S2)
  • XBee Router 1
  • 1x Arduino MEGA
  • 1x XBee Shield Module (SainSmart xBee V1.1) connected to the Arduino MEGA.
  • 1x XBee XB24-ZB Module (S2)
  • 1x BMP180 - Arduino Pin 3.3v, GND, 20 SDA, 21 SCL
  • 1x LED GREEN + R220Ohm - Arduino Pin 12 - Status indicator (flashing when receiving or sending data via XBee)
  • 1x LED RED + R220Ohm - Arduino Pin 11 - Data indicator
  • XBee Router 2
  • 1x Arduino UNO
  • 1x XBee XB24C Module (S2)
  • 1x XBee wireless SD shield connected to the Arduino UNO.
  • 1x LED RED - Arduino Pin 13 (onboard, RED) - Error indicator
  • 1x LED RED + R220Ohm - Arduino Pin 12 - Data indicator

Software
  • Raspberry Pi Stretch Linux 4.9.59-v7+ ARM
  • openHAB 2.2.0.
  • Node-RED 0.17.5 with node.js 6.12.3
  • Node-RED add-on Dashboard UI 2.7.0.
  • Node-RED add-on node-red-contrib-xbee v1.0.0
  • Node-RED add-on openHAB Addon 1.1.3
  • Arduino IDE v1.8.4
Note:
This experiment uses a Raspberry Pi NOOBS installation with additional manual openHAB installation (to test setting up from scratch). Logged in as user Pi and for editing the user openhab is used. The Home Automation solution uses openHABian with user openhabian.

Download
Download Arduino sketches, openHAB configuration files and Node-RED flow.
More information.

Prepare
Raspberry Pi running openHAB (link, to lookup how to setup openHAB either manually or use openHABian) and Node-RED (link).

Additional libraries and addons required:
XBee-Arduino-Library by Andrew Rapp v0.6.0 (link)
Install via the Arduino IDE.

Raspberry Pi Node-RED Addons
node-red-contrib-xbee v1.0.0 (link)
Install: Open a terminal, login as user pi, $ cd ~/.node-red, $ sudo npm install node-red-contrib-xbee

openHAB Addon (link).
Install: Open a terminal, login as user pi, $ cd ~/.node-red, $ npm install node-red-contrib-openhab2

Hint: Must read details about the XBee API (link).

XBee Configuration
There are 3 XBee's in the Mesh Network.
The XBee Coordinator connected, via XBee Explorer USB, to the Raspberry Pi running openHAB and two XBee's attached to an Arduino XBee Shield.

XBee Coordinator
Product Family: XB24-ZB (Series 2 XBee), Function Set: ZigBee Coordinator API, Firmware: 21A7
MAC: 0013A20040DD2BB8, SH:13A200, SL:40DD2BB8, ID:0, MY:0, DH:0, DL:FFFF, AP:2, NI:Coordinator
Connected to the USB port (/dev/ttyUSB0) of the Raspberry Pi openHAB server.

XBee Router 1
Product Family: XB24-ZB (Series 2 XBee), Function Set: ZigBee Router API, Firmware: 23A7
MAC: 0013A20040DD2BCF, SH:13A200, SL:40DD2BCF, ID:0, MY:0, DH:0, DL:FFFF, AP:2, NI:Router1
Connected to the Arduino MEGA XBee shield.

XBee Router 2
Product Family: XB24C (Series 2 XBee), Function Set: ZIGBEE TH Reg, Firmware: 4060
MAC: 0013A2004155456D, SH:13A200, SL:4155456D, ID:0, MY:A407, DH:0, DL:0, AP:2, NI: Router2, MP:FFFE, CI:11, A0:0, MY
Connected to the Arduino UNO XBee shield.

IMPORTANT: Ensure ALL XBees have AP = 2 set!!!

openHAB
openHAB is configured by defining items and a sitemap in textual configuration files located on the Raspberry Pi in sub folder /etc/openhab2/...
Items Configuration
There are two groups for each of the Arduino's with XBee Shield.
Each Arduino has two LED which are switched by switch items. The status result of switching an LED is shown in a string item.
IMPORTANT: When changing an item name of a LED switch, ensure to update the Node-RED Function Nodes.
File:/etc/openhab2/items/xbeemultipointnetwork.items
Edit Command: sudo -u openhab nano /etc/openhab2/items/xbeemultipointnetwork.items
Content:

Code: Select all

Group gXBeeRouter1
Number nXBeeRouter1_Temperature "Temperature [%.1f C]" <temperature> (gXBeeRouter1)
Number nXBeeRouter1_Pressure "Pressure [%.0f pa]" <pressure> (gXBeeRouter1)

Group gXBeeRouter2
Number nXBeeRouter2_RandomNumber "Random Number [%.0f]" <number> (gXBeeRouter2)
Switch aXBeeRouter2_LEDSwitch "LED Switch"


Sitemap Configuration
The sitemap defines for each of the Arduino's a Frame.
File:/etc/openhab2/sitemaps/xbeemultipointnetwork.sidemap
sudo -u openhab nano /etc/openhab2/sitemaps/xbeemultipointnetwork.sitemap
Content:

Code: Select all

sitemap xbeemultipointnetwork label="Experiment XBee Multipoint Network“ {
   Frame label="Arduino1 XBee Router 1" {
      Text item=nXBeeRouter1_Temperature
      Text item=nXBeeRouter1_Pressure
   }
   Frame label="Arduino2 XBee Router 2" {
      Switch item=aXBeeRouter2_LEDSwitch
      Text item=nXBeeRouter2_RandomNumber
   }
}


Sitemap URL Access

Code: Select all

http://192.168.N.NN:8080/basicui/app?sitemap=xbeemultipointnetwork

Image

Arduino Sketches (C code)
Based on the example code (using Series 2 XBee) developed by Andrew Rapp (Thanks).
See download for the full sketches.

Node-RED Flow
Image
There are two flows defined:
  • Flow listening to incoming data, containing temperature & pressure from Arduino 1 and random number from Arduino 2.
  • Flow sending data to the Arduino 2 to switch an LED.

Flow listening to incoming data, containing LED state information from the Arduino's
Nodes flow: xbee-rx > function > openhab2-out
Node xbee-rx "XBee Coordinator RX"
Listen to incoming data from an XBee Router = Arduino.
Output to: Function Node

Node Function "Select Router"

Code: Select all

// Select the XBee Router and forward the payload accordingly.
// There are two routers in the XBee network:
// Router with ID=1 sending temperature & pressure from a BMP180 sensor
// Router with ID=2 sends a random number between 0 and 99

// Get the message payload containing 9 bytes:
// Arduino ID: Byte[0], i.e. 1 (for router1) or 2 (for router2) etc depending number of routers
// The depending the router:
// Temperature: Bytes[1-4], i.e. 108,7,0,0 = 1900
// Pressure: Bytes[5-8], i.e. 3,143,1,0 = 102147
// RandomNumber: Bytes[1-4], i.e. 108,7,0,0 = 1900

// Get the payload data and assing to a var which is used to send to the next function
var data = msg.payload.data;
// node.warn(data);
// If the data is undefined i.e. the payload byte array is not set, then do nothing
if (data===undefined){
    return
}

// Create a new Byte Array to hold the 9 bytes from the message payload
var buffull = new ArrayBuffer(9);
buffull = msg.payload.data;

// Get the Arduino ID i.e. ID=1, ID=2 etc.
var bufid = new ArrayBuffer(1);
bufid = buffull.slice(0,1);
var id = bufid[0];
// node.warn("ID=" + id);

// Select the id and send the message with the data
// Outputs 2 messages: router1, router2

// Router1 - put null for message router2
if (id==1){
var msgR1 = {};
msgR1.topic = "tandp";
msgR1.payload = data
return [msgR1,null];
}

// Router2 - put null for message router1
if (id==2){
var msgR2 = {};
msgR2.topic = "randomnumber";
msgR2.payload = data
return [null,msgR2];
}

Depending which Router is used the output is set.
Router 1 Output to: Delay Node
Router 2 Output to: Function Node

Node function "Build Temperature & Pressure"

Code: Select all

// Convert the message payload containing 9 bytes, i.e. [82, 108,7,0,0,3,143,1,0], into:
// Arduino ID: Byte[0], i.e. 82 = char "R"
// Temperature: Bytes[1-4], i.e. 108,7,0,0 = 1900
// Pressure: Bytes[5-8], i.e. 3,143,1,0 = 102147

// Note: Extend the various array buffers if the payload contains more data.

// node.warn(msg.payload.data); //[82,108,7,0,0,3,143,1,0]

// Create a new Byte Array to hold the 9 bytes from the message payload
var buffull = new ArrayBuffer(9);
buffull = msg.payload;

// Get the Temperature.
// Create a new byte array with 4 bytes. Slice the first 4 bytes from the full buffer.
var buftemp = new ArrayBuffer(4);
buftemp = buffull.slice(1,5);
// Get the temperature as long
var lvalt = new Int32Array(new Uint8Array([buftemp[0],buftemp[1],buftemp[2],buftemp[3]]).buffer)[0]
// node.warn("T=" + lvalt);    //T=1900
var msgT = {};
msgT.topic = "temperature";
msgT.payload = lvalt * 0.01;

// Get the Pressure - same approach as the Temperature
var buftemp = new ArrayBuffer(4);
buftemp = buffull.slice(5,9);
var lvalp = new Int32Array(new Uint8Array([buftemp[0],buftemp[1],buftemp[2],buftemp[3]]).buffer)[0]
// node.warn("P=" + lvalp);    //P=102147
var msgP = {};
msgP.topic = "pressure";
msgP.payload = lvalp * 0.01;

// Return the topics holding the Temperature & Pressure
return [msgT,msgP];

Output to: openhab2-out node, dashboard ui gauge node, debug node

Node function "Build Random Number"

Code: Select all

// Convert the message payload containing 9 bytes, i.e. [82, 108,7,0,0,3,143,1,0], into:
// Arduino ID: Byte[0], i.e. 82 = char "R"
// Temperature: Bytes[1-4], i.e. 108,7,0,0 = 1900
// Pressure: Bytes[5-8], i.e. 3,143,1,0 = 102147

// Note: Extend the various array buffers if the payload contains more data.

// node.warn(msg.payload); //[82,108,7,0,0,3,143,1,0]

// Create a new Byte Array to hold the 9 bytes from the message payload
var buffull = new ArrayBuffer(9);
buffull = msg.payload;

// Get the randomnumber.
// Create a new byte array with 4 bytes. Slice the first 4 bytes from the full buffer.
var buftemp = new ArrayBuffer(4);
bufrn = buffull.slice(1,5);
// Get the randomnumber as long
var lvalrn = new Int32Array(new Uint8Array([bufrn[0],bufrn[1],bufrn[2],bufrn[3]]).buffer)[0]
// node.warn("RN=" + lvalrn);

var msgRN = {};
msgRN.topic = "randomnumber";
msgRN.payload = lvalrn;
// Return the topics holding the RandomNumber & Null
return [msgRN];

Output to: openhab2-out node, dashboard ui gauge node, debug node

Flow sending data to the Arduino's to switch an LED
Nodes flow: openhab2-in > function > xbee-tx
Node openhab2-in "aXBeeRouter2_LEDSwitch"
Listen to the state change of a switch item and sends payload ON or OFF.
Output to: Function Node

Node function "Build XBeeRouter2 TX Payload"

Code: Select all

//Build the JSON string to send to the XBee

//Log the incoming openHAB message item and payload
//The msg.item holds the openHAB item as defined in the textual iems file.
//The msg.payload holds the openHAB item state, i.e. "ON" or "OFF"
node.warn(msg.item + "=" + msg.payload);

// Get and set the switch state OFF=0, ON=1
var LedState = 0;
if (msg.payload == "ON") {
    LedState = 255;
}

//Parse the payload, holding the LED number & brightness, to a byte
var LedStateByte = "0x" + pad(LedState.toString(16),2)

//Build the data frame for the receiving XBee.
//The data is a byte array with 1 byte:
//Byte 0 = LED State = Brightness between 0x00 - 0xFF
var myDataFrame = {
            type: 0x10,                         // ZigBee Transmit Request (ZNet, ZigBee)
            id: 0x01,                           // Optional, nextFrameId() is called per default
            destination64: "0013A2004155456D",
            destination16: "fffe",              // Optional, "fffe" is default
            broadcastRadius: 0x00,              // Optional, 0x00 is default
            options: 0x00,                      // Optional, 0x00 is default
            data: [LedStateByte]      // String or Byte Array
            };

//Assign the data frame to the payload
msg.payload = myDataFrame;
//Send to the XBee node
return msg;

function pad(number, length) {
    var str = '' + number;
    while (str.length < length) str = '0' + str;
    return str;
}

Output to: xbee-tx Node

Node xbee-tx "XBee Router1 TX"
Sends the data to the XBee Router.

Node xbee-config ""
This is the node used to communicate between the XBees.
The settings are:
"apiMode": "2",
"rawFrames": false,
"convertAdc": false,"vrefAdc": "1200",
"serialPort": "/dev/ttyUSBxbee",
"lock": false,
"baudRate": "9600","dataBits": "8","stopBits": "1","parity": "none","bufferSize": "65536",
"rtscts": false,
"xon": false,"xoff": false,"xany": false,
"vmin": "1","vtime": "0"

Return to “Experiments”



Who is online