Raspberry Pi XBee Point-to-Point Mesh Network Experiment (openHAB,Node-RED,B4R)

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

Raspberry Pi XBee Point-to-Point Mesh Network Experiment (openHAB,Node-RED,B4R)

Postby rwblinn » 31 Jan 2018, 14:11

openHAB2 Raspberry Pi XBee Point-to-Point Mesh Network Experiment using Node-RED.
Version 20180131

Objectives
To build a XBee Point-to-Point (AT mode) Mesh Network (using Raspberry Pi and an Arduino) to control, via openHAB & Node-RED, the Arduino with two LED's connected.
Two way communication is tested by sending data from the openHAB Raspberry Pi server, to the Arduino to act upon, and the Arduino to send data back to the openHAB server to act accordingly.

Concept
In openHAB, textual configuration (items, sitemap, services) is used without any logic (i.e. command definitions and rules).
Node-RED to perform all the control logic (functioning as a Rules Engine, no rules in openHAB) & communication.
Node-RED sends binary data to the Arduino to switch an LED and the Arduino response to Node-RED is a JSON string which is used to update the LED status information.

This experiment is a proof-of-concept for my Home Automation Solution to enable , via openHAB, controlling sensors & reading sensor data in a dedicated XBee Point-to-Point Mesh Network.
NOTE: It is a further development of a similar experiment using B4J to manage the coordination between openHAB and the Arduino. The advantage of this solution is the use of Node-RED as an alternative openHAB rules engine. Node-RED is part of the openHABian distribution, so the solution is not dependent on third party software other then the Arduino program.
For the Home Automation solution, this concept will be used.

Image

Hardware
  • 1x Raspberry Pi 3 Model B v1.2
  • 1x Arduino MEGA
  • 2x XBee XB24-ZB Modules (S2)
  • 1x XBee Explorer USB - to configure the XBee Modules and run as XBee Coordinator (AT mode) connected to the Raspberry Pi.
  • 1x XBee Shield Module (SainSmart xBee V1.1) - to act as the XBee Router (AT mode) connected to the Arduino.
  • 1x LED RED - connected to pin 11 of the Arduino.
  • 1x LED GREEN - connected to pin 12 of the Arduino.

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 and Node-RED add-on Dashboard UI 2.7.0.
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 openHAB configuration files and Node-RED flow.
More information.

XBee Configuration
There are two XBee's in the network. These are configured in AT mode via the XTCU Tool (from Digi International Inc.). Used a Windows 10 Device and the XBee Explorer USB to configure the XBees via the Serial Port.
Please note, that AT mode is limited to point-to-point communication between two XBees (for point-to-multipoint, the API mode is required).
XBee Configuration
  • XBee Coordinator: Product Family: XB24-ZB, Function Set: ZigBee Coordinator AT, Firmware: 20A7, Connected to the USB port of Raspberry Pi openHAB server.
  • XBee Router: Product Family: XB24-ZB, Function Set: ZigBee Router AT, Firmware: 20A7, Connected to the Arduino XBee shield.
  • The XBee default configuration is used (no changes made).

Data Flows
There are two data flows openHAB to Arduino and Arduino to openHAB.
In simple terms:
openHAB to Arduino
  • openHAB switch item sends "ON"|"OFF" to Node-RED
  • Node-RED converts to byte array LEDNr 1|2, State 0|1
  • Node-RED sends binary data to Arduino B4R program
  • Arduino B4R program switches state of the selected LED
Arduino to openHAB
  • B4R program sends LED info JSON string as byte array
  • Node-RED converts byte array to JSON object
  • Node-RED sends status update to openHAB text item.

openHAB
For this experiment, textual configuration is used to define the items and the sitemap. The sitemap is accessed via browser (Basic UI) or Android openHAB App.
The configuration files are located on the Raspberry Pi in sub folders of /etc/openhab2/.
The files are owned by user openhab. When editing and logged in as user pi, add parameter -u openhab when editing with f.e. nano (example sudo -u openhab nano /etc/openhab2/items/xbeeledswitch.items).

Items
There are 3 items defined; two switches setting the Arduino connected LED ON / OFF and a string to display the status of a LED supplied by the Arduino.

File:
/etc/openhab2/items/xbeeledswitch.items

Content:

Code: Select all

Switch aXBeeLED1Switch "LED 1 (Red)"
Switch aXBeeLED2Switch "LED 2 (Green)"
String sXBeeLEDStatus "Status [%s]"


Editing using command:

Code: Select all

sudo -u openhab nano /etc/openhab2/items/xbeeledswitch.items


Sitemap
Simple UI with the two switches and the status string.

File:
/etc/openhab2/sitemaps/xbeeledswitch.sitemap

Content:

Code: Select all

sitemap xbeeledswitch label="Experiment XBee LED Switch"
{
   Frame label="LED's" {
      Switch   item=aXBeeLED1Switch
      Switch   item=aXBeeLED2Switch
      Text   item=sXBeeLEDStatus
   }
}


Editing using command:

Code: Select all

sudo -u openhab nano /etc/openhab2/sitemaps/xbeeledswitch.sitemap


Access the sitemap from the openHAB Basic UI:
http://192.168.N.NN:8080/basicui/app?si ... eledswitch

Item Name Change
When changing an item name, ensure to update the sitemap and the Node-RED nodes using the item name (see below).

Logging
Open a terminal and run command:

Code: Select all

tail -f /var/log/openhab2/openhab.log -f /var/log/openhab2/events.log

Logging examples:

Code: Select all

2018-01-31 11:12:10.330 [vent.ItemStateChangedEvent] - aXBeeLED2Switch changed from OFF to ON
2018-01-31 11:12:10.500 [vent.ItemStateChangedEvent] - sXBeeLEDStatus changed from lednr 1=ok to lednr 2=ok


Alternative KARAF can be used for logging:
Open a terminal and run ssh -p 8101 openhab@localhost with password habopen:

openHAB Basic-UI Refresh
If the openHAB Basic-UI is not refreshing after making changes to the textual configuration or Node-RED flow, then restart openHAB:

Code: Select all

sudo /bin/systemctl restart openhab2.service


Node-RED
Node-RED add-on node-red-contrib-openhab2 is required.
The nodes are installed in /home/pi/.node-red/node_modules/node-red-contrib-openhab2.

The flow
Image


FLOW DATA TO ARDUINO

openhab2-controller Node "OHController"
The controller is used by the openhab2-in and openhab2-out nodes.
Protocol: http, Host:localhost, Port:8080
No username and password required.

openhab2-in Node "LED1 Switch"
Listen to the state change of the item switching LED 1 (Red).
Controller: OHController.
Item: xBeeLED1Switch.
Message:
{"_msgid":"9102a288.019fc","payload":"ON","item":"aXBeeLED1Switch","event":"StateEvent"}
{"_msgid":"8e133f5f.ca2c2","payload":"OFF","item":"aXBeeLED1Switch","event":"StateEvent"}
Node Output to:
Function Node "Build Serial Buffer Payload"

openhab2-in Node "LED2 Switch"
Listen to the state change of the item switching LED 2 (Green).
Controller: OHController.
Item: xBeeLED2Switch.
Message:
{"_msgid":"9102a288.019fc","payload":"ON","item":"aXBeeLED2Switch","event":"StateEvent"}
{"_msgid":"8e133f5f.ca2c2","payload":"OFF","item":"aXBeeLED2Switch","event":"StateEvent"}
Node Output to:
Function Node "Build Serial Buffer Payload"

Function Node "Build Serial Buffer Payload"
Create from the openHAB message, the serial buffer payload which is send to the Arduino.
The message payload is a byte array with a 2 bytes buffer. This is used by the Arduino serial asynchronous stream (no prefix!).
byte 0 = led number 1 | 2
byte 1 = led state 0 | 1
State 0 = LED OFF, 1 = LED ON

Code: Select all

// 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);

// Select the LED to switch depending message item
// NOTE: When changing item in the textual configuration, ensure to update here!
var LedNr = 0;
if (msg.item == "aXBeeLED1Switch"){
    LedNr = 1;
}
if (msg.item == "aXBeeLED2Switch"){
    LedNr = 2;
}

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

// Set the state LedNr and its 0=OFF,1=ON
// The message payload is a byte array with a 2 bytes buffer. This is used by the Arduino serial asynchronous stream (no prefix!).
// byte 0 = led number 1 | 2
// byte 1 = led state 0 | 1
msg.payload = Buffer.from([LedNr, LedState]);

// Return the message
return msg;

Node Output to:
Serial Out Node "Serial OUT to Arduino"

Serial Port Node
This node is used by the serial out node.
Settings
Serial Port: /dev/ttyUSB0
Baud Rate: 9600 - IMPORTANT: The Baud Rate must be same as set for the XBee's (via the XCTU Tool)
Data Bits: 8
Parity: None
Stop Bits: 1
Input: Split input on character \n and delivery Binary Buffers
Output: Do NOT check the option "add split character to output messages"

Serial Out Node "Serial OUT to Arduino"
Sent the binary data to the Arduino via the XBee Mesh network.
Serial Port: /dev/ttyUSB0:9600-8N1 (as defined in the previous node)
Node Output to:
No output.

FLOW DATA FROM ARDUINO

Serial Port Node
This node is used by the serial in node.
Settings
Serial Port: /dev/ttyUSB0
Baud Rate: 9600 - IMPORTANT: The Baud Rate must be same as set for the XBee's (via the XCTU Tool)
Data Bits: 8
Parity: None
Stop Bits: 1
Input: Split input on character \n and delivery ascii strings.
Output: Do NOT check the option "add split character to output messages"

Not to forget, that the incoming Arduino JSON string must be delimited by a CRLF character (see B4R code).

Serial In Node "Serial IN from Arduino"
Receive the ascii data from the Arduino via the XBee Mesh network.
Serial Port: /dev/ttyUSB0:9600-8N1 - IMPORTANT: The Baud Rate must be same as set for the XBee's (via the XCTU Tool)
Node Output to:
Function Node "Build JSON Object"

Function Node "Build JSON Object"

Code: Select all

// The Arduino sends a JSON string back after setting an LED state.
// The JSON string is parsed and a msg.payload is created and send to the openHAB item sXBeeLEDStatus.
// The JSON string example:
// {"lednr":1,"state":1,"status":"lednr N=ok"}

// Get the msg payload, send by the Arduino, which is a byte array as binary buffer.
const buf = Buffer.from(msg.payload);

// Parse the binary buffer into json string.
const json = JSON.parse(buf.toString('utf8'));

// Return the msg holding the json status string
msg.topic = "expxbee/led" + json.lednr;
msg.payload = json.status;
node.status({fill:"green",shape:"dot",text:json.status});
// node.warn(json.status);

// Example: "lednr 1=ok"
return msg;

Node Output to:
openHAB2-out Node "LEDStatus Update"

openHAB2-out Node "LEDStatus Update"
Update the item sXBeeLEDStatus which is refreshed on the sitemap. Example string "lednr 1=ok".
Controller: OHController
Item: sXBeeLEDStatus
Topic: ItemUpdate
Payload: Leave empty to use the default payload as provided by the Function Node "Build JSON Object".
The payload contains the key status from the Arduino JSON string {"lednr":1,"state":1,"status":"lednr N=ok"}.
Node Output to:
No output but updating the item as mentioned.

XBee Mesh Network
The XBee Network has 2 XBee Modules:
XBee Coordinator connected to the Raspberry Pi openHAB Server via an XBee Explorer USB.
Configuration: XBee XB24-Z7WIT-004 Serie ZB Coordinator AT 9600/8/N/1/N-AT

XBee Router connected to an Arduino with XBee Shield Module.
Configuration: XBee XB24-Z7WIT-004 Serie ZB Router AT 9600/8/N/1/N-AT

Arduino Program
The Arduino program is written in B4R.
Steps to flash the B4R program to the Arduino:
  • Disconnect the Arduino from the PC port.
  • Remove the two XBEE/USB jumpers from the XBee Shield Module.
  • Connect the Arduino to the PC port.
  • Compile and flash the program.
  • Disconnect the Arduino from the PC port.
  • Set the two XBEE/USB jumpers to XBee (towards the inside of the Arduino).
  • Connect the Arduino to the PC port - to provide power to the Arduino.

The B4R code:

Code: Select all

#Region Project Attributes
   #AutoFlushLogs: True
   #StackBufferSize: 600
#End Region

Sub Process_Globals
   Public Serial1 As Serial               'Serial Communication
   Private AStream As AsyncStreams            'Data from Node-RED flow to switch the LED
   Private LED1Pin As Pin                  'Pin used for LED 1 (RED)
   Private LED1PinNumber As Byte = 0x0B      'LED1 connected to pin 11 0x0B
   Private LED2Pin As Pin                  'Pin used for LED 2 (GREEN)
   Private LED2PinNumber As Byte = 0x0C      'LED2 connected to pin 12 0x0C
   Private LedNr As Byte
   Private LedState As Byte
End Sub

Private Sub AppStart
   'Init the serial line - ensure to use the same baud rate as for the XBee.
   Serial1.Initialize(9600)
   'Init the LED pins
   LED1Pin.Initialize(LED1PinNumber, LED1Pin.MODE_OUTPUT)
   LED2Pin.Initialize(LED2PinNumber, LED2Pin.MODE_OUTPUT)
   'Init the asyncstream which receives the data from the Node-RED flow
   AStream.Initialize(Serial1.Stream, "AStream_NewData", "AStream_Error")
End Sub

'AStream: Handle the incoming data via the serial line from Node-RED
'Expects 2 bytes: byte 0 = led number, byte 1 = led state (0=OFF=LOW,1=ON=HIGH)
'Log("Buffer Length:", Buffer.Length, ", 0=", Buffer(0), ", 2=",Buffer(1))
Sub AStream_NewData (Buffer() As Byte)
   LedNr = Buffer(0)
   LedState = Buffer(1)
   'Set LED Pin state to HIGH = True when state = 1 or LOW = False when state = 0
   Select LedNr
      Case 1
         LED1Pin.DigitalWrite(LedState = 1)
      Case 2
         LED2Pin.DigitalWrite(LedState = 1)
   End Select
   'Response a JSON String {"lednr":lednr,"state":ledstate}
   'Ensure not to use log for other messages
   'JSON string = {"lednr":1, "state":1, "status":"lednr 1=ok"}
   AStream_Write("{")
   AStream_Write("""lednr"":")
   AStream_Write(LedNr)
   AStream_Write(",")
   AStream_Write("""state"":")
   AStream_Write(LedState)
   AStream_Write(",")
   AStream_Write("""status"":")
   AStream_Write("""")
   AStream_Write("lednr ")
   AStream_Write(LedNr)
   AStream_Write("=ok")
   AStream_Write("""")
   AStream_Write("}")
   AStream_Write(CRLF)
End Sub

'AStream: Handle any errors
Sub AStream_Error
   AStream_Write("{")
   AStream_Write("""status"":")
   AStream_Write("""")
   AStream_Write("lednr ")
   AStream_Write(LedNr)
   AStream_Write("=error")
   AStream_Write("""")
   AStream_Write("}")
   AStream_Write(CRLF)
End Sub

'Write data as array of bytes to the serial stream
Sub AStream_Write(s As String)
   AStream.Write(s.GetBytes)
End Sub


ToDo
  • Experiment completed.
  • For the Home Automation solution, include direct MQTT messaging (see example below).

Version
  • 20180131

Node-RED Example adding MQTT Messaging
Switch the LED's via subscribing an MQTT message.
Obtain the LED switch status via publishing to a MQTT message.
Image
In a nutshell:
Switch the LED's via subscribing an MQTT message.
  • mqtt-in Nodes "expxbee/ledN/set" use the mosquitto broker with URL localhost:1883. Subscribing to topic expxbee/ledN/set with payload 0 or 1 i.e. Led OFF, ON. Ni is the Led number 1 or 2.
  • Function Node "Build from MQTT Serial Buffer Payload" builds the 2 byte array (Led Nr Byte 0 = 1 | 2, Led State Byte 1 = 0 | 1) to be send to the Arduino via the Serial Out Node "Build from MQTT Serial Buffer Payload" (explained previous)
Obtain the LED switch status via publishing an MQTT message.
  • Serial In Node "Serial IN from Arduino" listens for data from the Arduino.
  • Function Node "Build JSON Object to MQTT Publish" get the message payload holding a byte array, which is parsed into a JSON string
  • mqtt-out Node "MQTT Publish LED Status" use the mosquitto broker with URL localhost:1883. The message topic is expxbee/led with payload the full JSON string as send by the Arduino. Example JSON String {"lednr":1, "state":1, "status":"lednr 1=ok"}.

Return to “Experiments”



Who is online