Home » Electronics » Configuration Utilities for XBee Radios

Configuration Utilities for XBee Radios

My ultimate aim is to wirelessly network several Arduino based platforms with a centralized Raspberry Pi controller. There is much for me to learn to get this operational, not the least of which is the radio device I plan to use, the Xbee.  To get up to speed on the Xbee, I found the tutorials at AdafruitSparkfun, and Parallax helpful.   More detailed references are listed at the end of this post, but the very first challenge is to configure the XBee radios for operation.  This post provides insight on how this can be done, and my main mission, create a few simple utilities that make that job easy.

Xbee Radios

I purchased two XBee Series 1 Module (Freescale 802.15.4 firmware) from Adafruit.  These are manufactured by Digi and are low-power module with wire antenna  (XB24-AWI-001).  They have a 250 kbps RF data rates and operate at 2.4 GHz.  These radios use the IEEE 802.15.4 networking protocol and can perform point-to-multi-point or peer-to-peer networking , but as configured here, they do not mesh.  The Digi models that handle meshing are Digimesh, ZNet2.5 and Zigbee (ZB).  Digimesh is a version of firmware that runs on Series 1 hardware. So, if you choose to, you can upgrade these modules to Digimesh firmware to get meshing.

Xbee Adapter Board

Along with the XBee radios, I purchased adapter boards designed to make it easier to work with the radios. The adopter provides on-board 3.3V regulator power from a 5 volt source, voltage level shifting circuitry so you can connect  5V circuitry to the XBee, commonly used pins are brought out along the edge (making it easy to breadboard), and engineered to be interface via FTDI cable to a computer via USB.  The image and the text below describe the pin-out for the Adafruit  XBee Adapter:

Adafruit Xbee Adapter Pinout

    1. 3V pin – This is either an input power pin (if 5V is not provided) or an output from the 250mA regulator if 5V is provided
    2. DTR – “Data terminal ready”  is a flow control pin used to tell the XBee that the microcontroller or computer host is ready to communicate.
    3. RST – “Reset”  pin can be used to reset the XBee.  By default it is pulled high by the 10K resistor under the module. To reset, pull this pin low.’
    4. Ground – common ground for power and signal
    5. CTS – “Clear to Send” this is a flow control pin that can be used to determine if there is data in the XBee input buffer ready to be read
    6. 5V – This is the power input pin into the 3.3V regulator. Provide up to 6V that will be linearly converted into 3.3V
    7. RX – “Receive Data” is the XBee’s serial recieve pin. Serial data is sent on this pin into the XBee to be transmitted wirelessly
    8. TX – “Transmit Data” is the XBee’s serial transmit pin. Serial data is sent on this pin out of the XBee, after it has been transmitted wirelessly from another module
    9. RTS – “Ready to Send” is a flow control pin that can be used to tell the XBee to signal that the computer or microcontroller needs a break from reading serial data.
    10. see pin #1

The DTR, RTS, RST and RX pins (going into the XBee) pass through a level converter chip that brings the levels to 3.3V. Adafruit claims you can use pretty much anywhere between 2.7 to 5.5V data to communicate with the XBee. The breakout pins on the bottom of the board are not level shifted and you should try to keep data going directly into the XBee pin under 3.3V

Xbee radio installed in a XBee Adapter with the USB FTDI TTL-232 Cable attached

XBee Initial Configuration and Testing

You need a way to communicate withe the Xbee, via it adapter,  to set it up.  This can be done via Adafruit’s  USB FTDI TTL-232 Cable, and the Digi X-CTU serial terminal program.  By the way, the X-CTU user guide describes the many more things it can do beyond the configuration shown here.

    1. Plug in the USB FTDI TTL-232 Cable into a PC USB port.  If drivers are not installed automatically (it didn’t for me), follow the steps at the FTDI site.
    2. Download the X-CTU, double click on the executable file, and follow the instructions to install the program.
    3. Now connect the USB FTDI TTL-232 Cable to the Xbee Adapter as shown in the picture to the right and insert the USB end of the cable to you PC.  Start the X-CTU.
    4. To connect, configure and upgrading the Xbee, follow the Adafruit instructions for the Xbee Adapter board. Note that if you follow the instructions (I didn’t – I kept it at 9600 baud), the modem’s serial interface is now set to 19,200 baud, not the default 9600 used by X-CTU.  Remember this next time you use X-CTU with this Xbee.
    5. If your instructed by X-CTU to reset the Xbee, you can do this by shorting the reset pin, RST pin,  to ground.

The configuration can be touchy, it can go badly, or not at all.  In my case, I seem to have one Xbee Adapter that can reliably perform a firmware upgrade but the other one took some time due to a lose fitting between the Adaptor and  Xbee.  If you run into configuration problems, check out these sites: Using XCTU to Invoke the BootloaderThe Unofficial XBee FAQ,  How to recover from a failed firmware upgrade.

Quickly Getting the Xbee’s Communicating

The next step for me was just do a basic test of getting two XBee device communicating with each other. This is just a sanity test to see evidence of communication between the devices. Basically, I just followed the instructions provided by Adafruit.
simple test

    1. Using the X-CTU, set the PAN ID to the same value on the two Xbee’s.
    2. Select an Ardunio that has been programmed to send repeated brief messages to its serial port.  I used the standard LED Blinking sketch but put in some write statements in the loop.
    3. Using an Arduino and breadboard, connect +5V and ground to provide power. Make sure the XBee’s LED is blinking.
    4. Connect the RX line (input) of the XBee to the TX line (output) of the Arduino. Connect the RX line (input) of the Arduino to the TX line (output) of the Xbee. Plug the Arduino into your PC’s serial port.
    5. Now take the second Xbee and connect the  USB FTDI TTL-232 Cable to the Xbee and the PC.  The cable is doing nothing but appling power to the Xbee.
    6. Now you should see the receive LED periodically light on the USB FTDI TTL-232 Cable tethered Xbee.
    7. You now got proof that the two Xbee’s are communicating.  The Arduino connected Xbee is sending data to its serial port and the USB FTDI TTL-232 Cable tethered Xbee is receiving it.

Above you’ll find a picture of the configuration, and below is the Arduino sketch I used.

/*
 *  Xbee Test via Blink LED
 *
 *Turns on an LED on for one second, then off for one second, repeatedly.
 *Also increase brigthness of analog LED.
 *
 *The circuit:
 * LED1 connected from digital pin 13 to ground.
 * LED2 connected from analog pin 9 to ground.
 * Note: On most Arduino boards, there is already an LED on the board
 * connected to pin 13, so you don't need any extra components for this example.

 *Created 1 June 2005
 *By David Cuartielles
 *http://arduino.cc/en/Tutorial/Blink
 *based on an orginal by H. Barragan for the Wiring i/o board
 *Modified by Jeff Irland in December 2012
 */

int ledPin1 =  13;    // LED connected to digital pin 13
int ledPin2 =  9;     // LED connected to analog pin 9
int brightness = 0;

// The setup() method runs once, when the sketch starts
void setup()   {
    Serial.begin(9600);
    pinMode(ledPin1, OUTPUT);     // initialize the digital pin as an output
    Serial.println("Arduino done with setup()");
}

// the loop() method runs over and over again,
// as long as the Arduino has power
void loop()
{
    digitalWrite(ledPin1, HIGH);   // set the LED on
    Serial.println("LED set HIGH.");
    delay(1000);                   // wait for a second

    digitalWrite(ledPin1, LOW);    // set the LED off
    Serial.println("LED set LOW.");
    delay(1000);                   // wait for a second

    brightness = brightness + 5;
    analogWrite(ledPin2, brightness);
    Serial.println("LED brightness increased.");
}

Installing XBee Python Tools for the RPi

While the MS Windows based Digi X-CTU tool is just fine, I want to use the RPi’s and Python to access the XBee serial communication API, and its advanced features, for one or more XBee devices.  I prefer simple utilities, that can be scripted within the Linux shell.  Call me a Linux snob if you wish, but I don’t care for MS Windows!

In my post “Selecting XBee Radios and Supporting Software Tools“, I referenced a Python package that could be used to create my utilitiesd, call python-xbee, and I will be using it here. It claims to provides a semi-complete implementation of the XBee binary API protocol and allows a developer to send and receive the information they desire without dealing with the raw communication details. It also claims the  library is compatible with both XBee 802.15.4 (Series 1) and XBee ZigBee (Series 2) modules, normal and PRO.

First, we need to load some additional required Python Packages, that being pySerial and Nose. pySerial extends python’s capabilities to include interacting with a serial port and Nose is a package providing a very easy way to build tests, based on the Python class unittest.  (Don’t let this all scare you away, these are necessary but your not going to use them directly).  To load these package:

sudo pip install pySerial
sudo pip install nose

Download the python-xbee tools from Google Code or Python Org and place them into the RPi’s $HOME/src.  The README file provides installation instructions.  It states that the following command automatically test and install the package for you:

sudo python setup.py install

There is a simple to use RPi platform tool that I have modified for my needs, that is a XBee serial command shell for interacting with XBee radios.  It performs the core functions of the official configuration tool, X-CTU, which only runs on Windows. (There happens to be a cross-platform version of X-CTU called moltosenso Network Manager but I don’t need all this horse power.)  I’ll use this X-CTU-alternative to configure the individual XBee radios.  With the X-CTU, you can update firmware, etc. but most of the time you need the program to do simple configuration tasks. You could use Linux’s minicom, but I prefer a simpler tool which can be scripted so I can configure several XBee radios identically.  I found much of what I wanted in an existing Python XBee tools for configuration.  I made some modification/improvements, I call it the XBeeTerm, and its listed below:


#!/usr/bin/env python

"""XBeeTerm.py is a XBee serial command shell for interacting with XBee radios

	This command interpretors establishes communications with XBee radios so that AT Commands can be sent to the XBee.
	The interpretors output is color coded to help distinguish user input, from XBee radio output, and from
	interpretors output. This command-line interpretor uses Python modual Cmd, and therefore, inherit bash-like history-list
	editing (e.g. Control-P or up-arrow scrolls back to the last command, Control-N or down-arrow forward to the next one,
	Control-F or right-arrow moves the cursor to the right non-destructively, Control-B or left-arrow moves the cursor
	to the left non-destructively, etc.).

	XBeeTerm is not a replacement for the Digi X-CTU program but a utility program for the Linux envirnment.  You can pipe
	scripts of XBee configration commands, making it easy to multiple radios.  Also, XBeeTerm wait for the arrival of a
	XBee data packet, print the XBee frame, and wait for the next packet, much like a packet sniffer.

	XBeeTerm Commands:
		baudrate <rate>		set the baud rate at which you will communicate with the XBee radio
		serial <device>		set the serial device that the XBee radio is attached
		watch				wait for the arrival of a XBee data packet, print it, wait for the next
		shell or !			pause the interpreter and invoke command in Linux shell
		exit or EOF			exit the XBeeTerm
		help or ?			prints out short discription of the commands (similar to the above)

	Just like the Digi X-CTU program, the syntax for the AT commands are:
		AT+ASCII_Command+Space+Optional_Parameter+Carriage_Return
		Example: ATDL 1F<CR>

	Example Session:
		baudrate 9600			# (XBeeTerm command) set the baudrate used to comm. with the XBee
		serial /dev/ttyUSB0		# (XBeeTerm command) serial device which has the XBee radio
		+++ 					# (XBee command) enter AT command mode on the XBee
		ATRE					# (XBee command) restore XBee to factory settings
		ATAP 2					# (XBee command) enable API mode with escaped control characters
		ATCE 0					# (XBee command) make this XBee radio an end device
		ATMY AAA1				# (XBee command) set the address of this radio to eight byte hex
		ATID B000				# (XBee command) Set the PAN ID to eight byte hex
		ATCH 0E					# (XBee command) set the Channel ID to a four byte hex
		ATPL 0					# (XBee command) power level at which the RF module transmits
		ATWR					# (XBee command) write all the changes to the XBee non-volatile memory
		ATFR					# (XBee command) reboot XBee radio
		exit					# (XBeeTerm command) exit python shell

	Referance Materials:
		XBee 802.15.4 (Series 1) Module Product Manual (section 3: RF Module Configuration)
			ftp://ftp1.digi.com/support/documentation/90000982_A.pdf
		python-xbee Documentation: Release 2.0.0, Paul Malmsten, December 29, 2010
			http://python-xbee.googlecode.com/files/XBee-2.0.0-Documentation.pdf
		cmd - Support for line-oriented command interpreters
			http://docs.python.org/2/library/cmd.html
		cmd - Create line-oriented command processors
			http://bip.weizmann.ac.il/course/python/PyMOTW/PyMOTW/docs/cmd/index.html
		Easy command-line applications with cmd and cmd2
			http://pyvideo.org/video/306/pycon-2010--easy-command-line-applications-with-c

	Orginally Created By:
		Amit Snyderman (amit@amitsnyderman.com), on/about August 2012, and taken from
		https://github.com/sensestage/xbee-tools

	Modified By:
		Jeff Irland (jeff.irland@gmail.com) in January 2013
"""

# imported modules
import os						# portable way of using operating system dependent functionality
import sys						# provides access to some variables used or maintained by the interpreter
import time						# provides various time-related functions
import cmd						# provides a simple framework for writing line-oriented command interpreters
import serial					# encapsulates the access for the serial port
import argparse					# provides easy to write and user-friendly command-line interfaces
from xbee import XBee			# implementation of the XBee serial communication API
from pretty import switchColor	# colored text in Python using ANSI Escape Sequences

# authorship information
__author__ = "Jeff Irland"
__copyright__ =	"Copyright 2013"
__credits__ = "Amit Snyderman, Marije Baalman, Paul Malmsten"
__license__ = "GNU General Public License"
__version__ = "0.1"
__maintainer__ = "Jeff Irland"
__email__ = "jeff.irland@gmail.com"
__status__ = "Development"
__python__ = "Version 2.7.3"

# text colors to be used during terminal sessions
CMD_INPUT_TEXT = 'normal'
CMD_OUTPUT_TEXT = 'bright yellow'
XBEE_OUTPUT_TEXT = 'bright red'
SHELL_OUTPUT_TEXT = 'bright cyan'
WATCH_OUTPUT_TEXT = 'bright green'

class ArgsParser():
	"""Within this object class you should load all the command-line switches, parameters, and arguments to operate this utility"""
	def __init__(self):
		self.parser = argparse.ArgumentParser(description="This command interpretors establishes communications with XBee radios so that AT Commands can be sent to the XBee.  It can be used to configure or query the XBee radio", epilog="This utility is primarily intended to change the AT Command parameter values, but could be used to query for the parameter values.")
		self.optSwitches()
		self.reqSwitches()
		self.optParameters()
		self.reqParameters()
		self.optArguments()
		self.reqArguments()
	def optSwitches(self):
		"""optonal switches for the command-line"""
		self.parser.add_argument("--version", action="version", version=__version__, help="print version number on stdout and exit")
		self.parser.add_argument("-v", "--verbose", action="count", help="produce verbose output for debugging")
	def reqSwitches(self):
		"""required switches for the command-line"""
		pass
	def optParameters(self):
		"""optonal parameters for the command-line"""
		pass
	def reqParameters(self):
		"""required parameters for the command-line"""
		pass
	def optArguments(self):
		"""optonal arguments for the command-line"""
		self.parser.add_argument(nargs="*", action="store", dest="inputs", default=None, help="XBeeTerm script file with AT Commands to be executed")
	def reqArguments(self):
		"""required arguments for the command-line"""
		pass
	def args(self):
		"""return a object containing the command-line switches, parameters, and arguments"""
		return self.parser.parse_args()

class XBeeShell(cmd.Cmd):
	def __init__(self, inputFile=None):
		"""Called when the objects instance is created"""
		cmd.Cmd.__init__(self)
		self.serial = serial.Serial()
		if inputFile is None:
			self.intro = "Command-Line Interpreter for Configuring XBee Radios"
			self.prompt = "xbee% "
		else:
			self.intro = "Configuring XBee Radios via command file"
			self.prompt = ""			# Do not show a prompt after each command read
			sys.stdin = inputFile

	def default(self, p):
		"""Command is assumed to be an AT Commands for the XBee radio"""
		if not self.serial.isOpen():
			print "You must set a serial port first."
		else:
			if p == '+++':
				self.serial.write('+++')
				time.sleep(2)
			else:
				self.serial.write('%s\r' % p)
				time.sleep(0.5)

			output = ''
			while self.serial.inWaiting():
				output += self.serial.read()
			if output == '' :
				print 'XBee timed out, so reissue "+++". (Or maybe XBee doesn\'t understand "%s".)' % p
			else:
				switchColor(XBEE_OUTPUT_TEXT)
				print output.replace('\r', '\n').rstrip()

	def emptyline(self):
		"""method called when an empty line is entered in response to the prompt"""
		return None		# do not repeat the last nonempty command entered

	def precmd(self, p):
		"""executed just before the command line line is interpreted"""
		switchColor(CMD_OUTPUT_TEXT)
		return cmd.Cmd.precmd(self, p)

	def postcmd(self, stop, p):
		"""executed just after a command dispatch is finished"""
		switchColor(CMD_INPUT_TEXT)
		return cmd.Cmd.postcmd(self, stop, p)

	def do_baudrate(self, p):
		"""Set the baud rate used to communicate with the XBee"""
		self.serial.baudrate = p
		print 'baudrate set to %s' % self.serial.baudrate

	def do_serial(self, p):
		"""Linux serial device path to the XBee radio (e.g. /dev/ttyUSB0)"""
		try:
			self.serial.port = p
			self.serial.open()
			print 'Successfully opened serial port %s' % p
		except Exception, e:
			print 'Unable to open serial port %s' % p

	def do_shell(self, p):
		"""Pause the interpreter and invoke command in Linux shell"""
		print "running shell command: ", p
		switchColor(SHELL_OUTPUT_TEXT)
		print os.popen(p).read()

	def do_watch(self, p):
		"""Wait for the arrival of a XBee data packet, print it when it arrives, wait for the next"""
		if not self.serial.isOpen():
			print "You must set a serial port first."
		else:
			print "Entering watch mode..."
			switchColor(WATCH_OUTPUT_TEXT)
			while 1:
				packet = xbee.find_packet(self.serial)
				if packet:
					xb = xbee(packet)
					print xb

	def do_exit(self, p):
		"""Exits from the XBee serial terminal"""
		self.serial.close()
		print "Exiting", os.path.basename(__file__)
		return True

	def do_EOF(self, p):
		"""EOF (end-of-file) or Ctrl-D will return True and drops out of the interpreter"""
		self.serial.close()
		print "Exiting", os.path.basename(__file__)
		return True

	def help_help(self) :
		"""Print help messages for command arguments"""
		print 'help\t\t', self.help_help.__doc__
		print 'shell <cmd>\t', self.do_shell.__doc__
		print 'EOF or Ctrl-D\t', self.do_EOF.__doc__
		print 'exit\t\t', self.do_exit.__doc__
		print 'watch\t\t', self.do_watch.__doc__
		print 'serial <dev>\t', self.do_serial.__doc__
		print 'baudrate <rate>', self.do_baudrate.__doc__

# Enter into XBee command-line processor
if __name__ == '__main__':
	# parse the command-line for switches, parameters, and arguments
	parser = ArgsParser()							# create parser object for the command-line
	args = parser.args()							# get list of command line arguments, parameters, and switches

	if args.verbose > 0:							# print what is on the command-line
		print os.path.basename(__file__), "command-line arguments =", args.__dict__

	# process the command-line arguments (i.e. script file) and start the command shell
	if len(args.inputs) == 0:	# there is no script file
		shell= XBeeShell()
		shell.cmdloop()
	else:							# there is a script file on the command-line
		if len(args.inputs) > 1:
			print os.path.basename(__file__), "will process only the first command-line argument."
		if os.path.exists(args.inputs[0]) :
			inputFile = open(args.inputs[0], 'rt')
			shell = XBeeShell(inputFile)
			shell.cmdloop()
		else:
			print 'File "%s" doesn\'t exist. Program terminated.' % args.inputs[0]

The XBeeTerm.py module imports functions from the pretty.py package, specifically to colorize the output for xterm on the Raspberry Pi.  This package is provided here:

#!/usr/bin/env python

"""pretty.py will color text for Xterm/VT100 type terminals using ANSI Escape Sequences

	A library that provides a Python print, stdout, and string wrapper that makes colored terminal
	text easier to use(e.g. without having to mess around with ANSI escape sequences).

	Referance Materials:
		Colored text in Python using ANSI Escape Sequences
			http://nezzen.net/2008/06/23/colored-text-in-python-using-ansi-escape-sequences/

	Orginally Created By:
		Copyright (C) 2008 Brian Nez <thedude at bri1 dot com>

	Modified By:
		Jeff Irland (jeff.irland@gmail.com) in January 2013
"""

# imported modules
import sys

# authorship information
__author__ = "Jeff Irland"
__copyright__ =	"Copyright 2013"
__credits__ = "Brian Nez"
__license__ = "GNU General Public License"
__version__ = "1.0"
__maintainer__ = "Jeff Irland"
__email__ = "jeff.irland@gmail.com"
__status__ = "Production"

# Dictionary of ANSI escape sequences for coloring text
colorCodes = {
	'black':	'0;30',		'bright gray':	'0;37',
	'blue':		'0;34',		'white':		'1;37',
	'green':	'0;32',		'bright blue':	'1;34',
	'cyan':		'0;36',		'bright green':	'1;32',
	'red':		'0;31',		'bright cyan':	'1;36',
	'purple':	'0;35',		'bright red':	'1;31',
	'yellow':	'0;33',		'bright purple':'1;35',
	'dark gray':'1;30',		'bright yellow':'1;33',
	'normal':	'0'
}

def printc(text, color):
	"""Print in color"""
	print "\033["+colorCodes[color]+"m"+text+"\033[0m"

def writec(text, color):
	"""Write to stdout in color"""
	sys.stdout.write("\033["+colorCodes[color]+"m"+text+"\033[0m")

def switchColor(color):
	"""Switch terminal color"""
	sys.stdout.write("\033["+colorCodes[color]+"m")

def stringc(text, color):
	"""Return a string with ANSI escape sequences to color text"""
	return "\033["+colorCodes[color]+"m"+text+"\033[0m"

# Simple test routine to validate thing are working correctly
if __name__ == '__main__':
	printc("Welcome to the pretty.py test routine!", 'white')

	printc("I will now try to print a line of text in each color using \"writec()\"", 'white')
	for color in colorCodes.keys():
		writec("Hello, world!", color)
		print "\t", color

	printc("\n\nI will now try to print a line of text in each color using \"switchColor()\"", 'white')
	for color in colorCodes.keys():
		switchColor(color)
		print 'Hello World #2!'

	printc("\n\nI will now try to print a line of text in each color using \"printc()\"", 'white')
	for color in colorCodes.keys():
		printc('Hello World #3!', color)

	printc("\n\nI will now try to print a line of text in each color using \"stringc()\"", 'white')
	for color in colorCodes.keys():
		print stringc('Hello World #4!', color)

Identifying the RPi USB device used by the XBee

Since the python-xbee library wants to talk to the via a Linux serial devices, I’m using the USB FTDI TTL-232 Cable (FTDI is the USB chip manufacturer) used in the XBee configuration step done earlier.  I connected the cable to the RPi USB port  and then we need to find the serial tty the cable is associated with.  To do this, it takes a bit of detective work. Run the commands:

lsusb
dmesg | grep Manufacturer
dmesg | grep FTDI

A better command might be (but I’m not sure it will work every time):

dmesg | grep -i usb | grep -i tty

The interpretation of the output tells us the cable is attached to serial device /dev/ttyUSB0.  See the output below.

best use of dmesg

Another possibility is to use udevadm to gather information about specific devices but I never figured out exactly how to use it to answer my question.  Python also has a package called PyUSB that might provide some help, but also here you’ll still need the vendor and product identification information.

Chances are that when you plug the cable into the same USB port the next time, it will default to the same tty but there is no certainty.  To assign a permanent tty name to the device, and never do any of this again, check out Persistent names for usb-serial devices.

Configuring the XBee Radios for API Mode

The configuration and testing of the XBee’s done earlier was done in AT Command mode (Transparent Mode). In AT mode, everything sent to the RX line of the XBee radio will be sent out via the antenna, and all the incoming data from antenna will go to the XBee’s TX line.  This is why we could check the sanity of the XBee radios in the earlier section, XBee Initial Configuration and Testing using a simple Arduino sketch.  We sent junk to the XBee and it transmitted it!

Now we’ll configure two XBee radios (with a Coordinator and a single End Device) to form a network using API Mode.  In API Mode, XBee won’t send out anything until it received the correct form of commands from the serial interface.  The XBee AT Command Set (page 27), specifically the  ATAP 2 command, allows you to configure the XBee radio for API Mode.   So why API Mode, consider the following:

    • When sending a packet, the transmitting radio receives an ACK, indicating the packet was successfully delivered. The transmitting radio will resend the packet if it does not receive an ACK.
    • Receive packets (RX), contain the source address of transmitting radio
    • You can configure a remote radio with the Remote AT feature
    • Easily address multiple radios and send broadcast TX packets
    • Receive I/O data from 1 or more remote XBees
    • Obtain RSSI (signal strength) of an RX packet
    • Packets include a checksum for data integrity

The XBeeTerm utility will  easily configure the XBee radios for API mode and set the appropriate network parameters.  To get a deeper appreciation of configuring the XBee radios, see the References at the end.  For here, I’ll just run through the steps using the XBeeTerm.py tool and the configuration commands used, documented in file scripts.

Coordinator Configuration File: Config-Coordinator.txt

# To remove comments, white spaces, and blank lines, use the following:
#		sed '/^#/d; s/\([^$]\)#.*/\1/' Config-Coordinator.txt | sed 's/[ \t]*$//' > coord.txt
# Run this script to configure the XBee radio using the following:
#		python XBeeTerm.py coord.txt
#
baudrate 9600			# (XBeeTerm command) set the baudrate used to comm. with the XBee
serial /dev/ttyUSB0		# (XBeeTerm command) serial device which has the XBee radio
+++ 					# (XBee command) enter AT command mode on the XBee
ATRE					# (XBee command) restore XBee to factory settings
ATAP 2					# (XBee command) enable API mode with escaped control characters
ATCE 1					# (XBee command) make this XBee radio the network coordinator
ATMY AAA0				# (XBee command) set the address of this radio to eight byte hex (must be unique)
ATID B000				# (XBee command) Set the PAN ID to eight byte hex (all XBee's must have this same value)
ATCH 0E					# (XBee command) set the Channel ID to a four byte hex (all XBee's must have same value)
ATPL 0					# (XBee command) power level at which the RF module transmits (0 lowest / 4 highest)
ATWR					# (XBee command) write all the changes to the XBee non-volatile memory
ATFR					# (XBee command) reboot XBee radio
exit					# (XBeeTerm command) exit python shell

End Device Configuration File: Config-End-Device.txt

# To remove comments, white spaces, and blank lines, use the following:
#		sed '/^#/d; s/\([^$]\)#.*/\1/' Config-End-Device.txt | sed 's/[ \t]*$//' > endd.txt
# Run this script to configure the XBee radio using the following:
#		python XBeeTerm.py endd.txt
#
baudrate 9600			# (XBeeTerm command) set the baudrate used to comm. with the XBee
serial /dev/ttyUSB0		# (XBeeTerm command) serial device which has the XBee radio
+++ 					# (XBee command) enter AT command mode on the XBee
ATRE					# (XBee command) restore XBee to factory settings
ATAP 2					# (XBee command) enable API mode with escaped control characters
ATCE 0					# (XBee command) make this XBee radio an end device
ATMY AAA1				# (XBee command) set the address of this radio to eight byte hex (must be unique)
ATID B000				# (XBee command) Set the PAN ID to eight byte hex (all XBee's must have this same value)
ATCH 0E					# (XBee command) set the Channel ID to a four byte hex (all XBee's must have same value)
ATPL 0					# (XBee command) power level at which the RF module transmits (0 lowest / 4 highest)
ATWR					# (XBee command) write all the changes to the XBee non-volatile memory
ATFR					# (XBee command) reboot XBee radio
exit					# (XBeeTerm command) exit python shell

As they stand right now, these files could not be processed by XBeeTerm.py because of the comments (included to make the contents understandable).  To clean this up, the command sed '/^#/d; s/\([^$]\)#.*/\1/'will remove all shell type comments from a file and sed 's/[ \t]*$//'will remove unneeded white space.  Putting this all together and you can use this to prepare the above files for XBeeTerm.py:

sed '/^#/d; s/\([^$]\)#.*/\1/' Config-Coordinator.txt | sed 's/[ \t]*$//' > coord.txt
sed '/^#/d; s/\([^$]\)#.*/\1/' Config-End-Device.txt | sed 's/[ \t]*$//' > endd.txt

Now execute the following python XBeeTerm.py coord.txt and you get the output below:

XBeeTerm Script

The yellow text is responses back from the XBee serial terminal and the red text is from the XBee radio itself.  Since all the red text is “OK”, all the commands took and the XBee radio is now configured as a Coordinator.  Now repeat this for the End Device XBee radio.

In this example, I have one End Device but what if you have multiple devices, do you need a Config-End-Device.txt file for each end device?  The only change within the configuration file is the radio’s address, which is established via the ATMY command.  Here is a trick to avoid the need for multiple files.  First, configure all your End Devices using the configuration file.  Then, for each radio, modify the ATMY use the following:

echo -e "baudrate 9600\nserial /dev/ttyUSB0\n+++\nATMY AAA1\nATWR\nATFR\nexit" | python XBeeTerm.py

but for each End Device radio, increment the ATMY address by one (e.g. AAA2, AAA3, …).

Querying XBee for Configuration

Now that we believe the XBee radios are properly configured, lets verify that by query the radios.  You could use XBeeTerm to perform this function by including only the AT Command without the parameter but I wanted a more informative tool. For this, I have created another utility that can take a list of AT Commands as arguments and query the XBee radio for the AT’s parameter value.  This utility, call XBeeQuery.py, is listed below:


#! /usr/bin/python

"""
	This utility will query a XBee radio for some of it's AT Command parameters and print their values, as well as
	optional discriptive information.  It has a set of default AT Commands or the use can provide the desired set
	of AT Commands on the command-line.

	The dictionay of AT Command descriptive information is limited but can be easily expanded.  The descriptive
	information was taken from the first referance given below. Also note that if this utility appears to hang,
	it is almost certainly waiting on a response from the XBee. To continue processing the AT Command list, use Ctrl-C.

	Reference Materials:
		XBee/XBee-PRO OEM RF Modules: Product Manual v1.xCx - 802.15.4 Protocol
			ftp://ftp1.digi.com/support/documentation/90000982_A.pdf
		python-xbee Documentation: Release 2.0.0, Paul Malmsten, December 29, 2010
			http://python-xbee.googlecode.com/files/XBee-2.0.0-Documentation.pdf
		Parser for command-line options, arguments and sub-commands
			http://docs.python.org/2/library/argparse.html#module-argparse

"""

# imported modules
import os						# portable way of using operating system dependent functionality
import sys						# provides access to some variables used or maintained by the Python interpreter
import serial					# encapsulates the access for the serial port
import argparse					# provides easy to write and user-friendly command-line interfaces
from xbee import XBee			# implementation of the XBee serial communication API
from pretty import stringc		# provides colored text for xterm and VT100 type terminals using ANSI Escape Sequences

# authorship information
__author__ = "Jeff Irland"
__copyright__ =	"Copyright 2013"
__credits__ = "Paul Malmsten"
__license__ = "GNU General Public License"
__version__ = "0.1"
__maintainer__ = "Jeff Irland"
__email__ = "jeff.irland@gmail.com"
__status__ = "Development"
__python__ = "Version 2.7.3"

# text colors to be used during terminal sessions
NORMAL_TEXT = 'normal'
CMD_TEXT = 'bright red'
NAME_TEXT = 'bright yellow'
CAT_TEXT = 'bright yellow'
DESC_TEXT = 'normal'
RANGE_TEXT = 'bright cyan'
DEFAULT_TEXT = 'bright green'

class ArgsParser():
	"""Within this object class you should load all the command-line switches, parameters, and arguments to operate this utility"""
	def __init__(self):
		self.parser = argparse.ArgumentParser(description="This utility will query a XBee radio for some of it's AT Command parameters and print their values.  It has a set of default AT Commands or the use can provide the desired set of AT Commands on the command-line.", epilog="This utility is for query only and will not change the AT Command parameter values.")
		self.optSwitches()
		self.reqSwitches()
		self.optParameters()
		self.reqParameters()
		self.optArguments()
		self.reqArguments()
	def optSwitches(self):
		"""optonal switches for the command-line"""
		self.parser.add_argument("--version", action="version", version=__version__, help="print version number on stdout and exit")
		self.parser.add_argument("-v", "--verbose", action="count", help="produce verbose output for debugging")
		self.parser.add_argument("-n", "--name", required=False, action="store_true", help="print the name (i.e. short description) of the XBee AT Command")
		self.parser.add_argument("-d", "--description", required=False, action="store_true", help="print the full description of the XBee AT Command")
	def reqSwitches(self):
		"""required switches for the command-line"""
		pass
	def optParameters(self):
		"""optonal parameters for the command-line"""
		self.parser.add_argument("-b", "--baudrate", required=False, action="store", metavar="RATE", type=int, default=9600, help="baud rate used to communicate with the XBee radio")
		self.parser.add_argument("-p", "--device", required=False, action="store", metavar="DEV", type=str, default='/dev/ttyUSB0', help="open this serial port or device to communicate with the XBee radio")
	def reqParameters(self):
		"""required parameters for the command-line"""
		pass
	def optArguments(self):
		"""optonal arguments for the command-line"""
		self.parser.add_argument(nargs="*", action="store", dest="inputs", help="AT Commands to be queried")
	def reqArguments(self):
		"""required arguments for the command-line"""
		pass
	def args(self):
		"""return a object containing the command-line switches, parameters, and arguments"""
		return self.parser.parse_args()

class ATDict():
	"""Within this object class you should load a dictionary of { "AT Command" : [ "Name", "Category", "Description", "Parameter Range", "Default Value" ] }"""
	# Networking & Security, RF Interfacing, Sleep Modes (NonBeacon), Serial Interfacing, I/O Settings, Diagnostics, AT Command Options
	def __init__(self):
		self.commands = {
		"CH" : [ "Channel", "Networking", "Set/Read the channel number used for transmitting and receiving data between RF modules.", "0x0B - 0x1A", "0x0C" ],
		"ID" : [ "PAN ID", "Networking", "Set/Read the PAN (Personal Area Network) ID. Use 0xFFFF to broadcast messages to all PANs.", "0 - 0xFFFF" , "0x3332" ],
		"DH" : [ "Destination Address High", "Networking", "Set/Read the upper 32 bits of the 64-bit destination address. When combined with DL, it defines the destination address used for transmission. To transmit using a 16-bit address, set DH parameter to zero and DL less than 0xFFFF. 0x000000000000FFFF is the broadcast address for the PAN.", "0 - 0xFFFFFFFF", "0" ],
		"DL" : [ "Destination Address Low", "Networking", "Set/Read the lower 32 bits of the 64-bit destination address. When combined with DH, DL defines the destination address used for transmission. To transmit using a 16-bit address, set DH parameter to zero and DL less than 0xFFFF. 0x000000000000FFFF is the broadcast address for the PAN.", "0 - 0xFFFFFFFF", "0" ],
		"MY" : [ "16-bit Source Address", "Networking", "Set/Read the RF module 16-bit source address. Set MY =0xFFFF to disable reception of packets with 16-bit addresses. 64-bit source address(serial number) and broadcast address (0x000000000000FFFF) is always enabled.", "0 - 0xFFFF", "0" ],
		"SH" : [ "Serial Number High", "Networking", "Read high 32 bits of the RF module's unique IEEE 64-bit address. 64-bit source address is always enabled.", "0 - 0xFFFFFFFF [read-only]", "Factory-set" ],
		"SL" : [ "Serial Number Low", "Networking", "Read low 32 bits of the RF module's unique IEEE 64-bit address. 64-bit source address is always enabled.", "0 - 0xFFFFFFFF [read-only]", "Factory-set" ],
		"RR" : [ "XBee Retries", "Networking", "Set/Read the maximum number of retries the module will execute in addition to the 3 retries provided by the 802.15.4 MAC. For each XBee retry, the 802.15.4 MAC can execute up to 3 retries.", "0 - 6", "0" ],
		"RN" : [ "Random Delay Slots", "Networking", "Set/Read the minimum value of the back-off exponent in the CSMA-CA algorithm that is used for collision avoidance. If RN = 0, collision avoidance is disabled during the first iteration of the algorithm (802.15.4 - macMinBE).", "0 - 3 [exponent]", "0" ],
		"MM" : [ "MAC Mode", "Networking", "Set/Read MAC Mode value. MAC Mode enables/disables the use of a Digi header in the 802.15.4 RF packet. When Modes 0 or 3 are enabled(MM=0,3), duplicate packet detection is enabled as well as certain AT commands.", "0 = Digi Mode, 1 = 802.15.4 (no ACKs), 2 = 802.15.4 (with ACKs), 3 = Digi Mode (no ACKs)", "0" ],
		"NI" : [ "Node Identifier", "Networking", "Stores a string identifier. The register only accepts printable ASCII data. A string can not start with a space. Carriage return ends command. Command will automatically end when maximum bytes for the string have been entered. This string is returned as part of the ND (Node Discover) command. This identifier is also used with the DN (Destination Node) command.", "20-character ASCII string", "-" ],
		"NT" : [ "Node Discover Time", "Networking", "Set/Read the amount of time a node will wait for responses from other nodes when using the ND (Node Discover) command.", "0x01 - 0xFC [x 100 ms]", "0x19" ],
		"CE" : [ "Coordinator Enable", "Networking", "Set/Read the coordinator setting. A value of 0 makes it an End Device but a value of 1 makes it a Coordinator.", "0 = End Device, 1 = Coordinator", "0" ],
		"SC" : [ "Scan Channels", "Networking", "Set/Read list of channels to scan for all Active and Energy Scans as a bitfield. This affects scans initiated in command mode (AS, ED) and during End Device Association and Coordinator startup", "0 - 0xFFFF [bitfield](bits 0, 14, 15 not allowed on the XBee-PRO)", "0x1FFE (all XBee-PRO Channels)" ],
		#"SD" : [ "Scan Duration", "Networking", "Set/Read the scan duration exponent.  For End Device - Duration of Active Scan during Association.  For Coordinator - If ‘ReassignPANID’ option is set on Coordinator [refer to A2 parameter],  SD determines the length of time the Coordinator will scan channels to locate existing PANs. If ‘ReassignChannel’ option is set, SD determines how long the Coordinator will perform an Energy Scan to determine which channel it will operate on.  ‘Scan Time’ is measured as (# of channels to scan] * (2 ^ SD) * 15.36ms). The number of channels to scan is set by the SC command. The XBee can scan up to 16 channels (SC = 0xFFFF).", "0-0x0F [exponent]", "4" ],
		"A1" : [ "End Device Association", "Networking", "Set/Read End Device association options. bit 0 - ReassignPanID (0 - Will only associate with Coordinator operating on PAN ID that matches module ID / 1 - May associate with Coordinator operating on any PAN ID), bit 1 - ReassignChannel(0 - Will only associate with Coordinator operating on matching CH Channel setting / 1 - May associate with Coordinator operating on any Channel), bit 2 - AutoAssociate (0 - Device will not attempt Association / 1 - Device attempts Association until success Note: This bit is used only for Non-Beacon systems. End Devices in Beacon-enabled system must always associate to a Coordinator), bit 3 - PollCoordOnPinWake (0 - Pin Wake will not poll the Coordinator for indirect (pending) data / 1 - Pin Wake will send Poll Request to Coordinator to extract any pending data), bits 4 - 7 are reserved.", "0 - 0x0F [bitfield]", "0" ],
		#"XX" : [ "", "", "", "", "" ],
		#"XX" : [ "", "", "", "", "" ],
		}
	def dictionary(self):
		"""return the whole dictionary of command"""
		return self.commands
	def command(self, cmd):
		"""return the colorized AT Command"""
		return stringc(cmd, CMD_TEXT)
	def name(self, cmd):
		"""return the colorized name of the AT Command"""
		return stringc(self.commands[cmd][0], NAME_TEXT)
	def category(self, cmd):
		"""return the colorized category of the AT Command"""
		return stringc(self.commands[cmd][1], CAT_TEXT)
	def description(self, cmd):
		"""return the colorized description of the AT Command"""
		return stringc(self.commands[cmd][2], DESC_TEXT)
	def range(self, cmd):
		"""return the colorized range of the AT Command"""
		return stringc(self.commands[cmd][3], RANGE_TEXT)

	def default(self, cmd):
		"""return the colorized devault value of the AT Command"""
		stringc(self.commands[cmd][3], DEFAULT_TEXT)

class FrameID():
	"""XBee frame IDs must be in the range 0x01 to 0xFF (0x00 is a special case).
	This object allows you to cycles through these numbers."""
	def __init__(self):
		self.frameID = 0
	def inc(self):
		if self.frameID == 255:
			self.frameID = 0
		self.frameID += 1
		return self.frameID

def byte2hex(byteStr):
	"""Convert a byte string to it's hex string representation"""
	hex = []
	for aChar in byteStr:
		hex.append("%02X " % ord(aChar))
	return ''.join(hex).strip()

if __name__ == '__main__':
	# parse the command-line for switches, parameters, and arguments
	parser = ArgsParser()							# create parser object for the command-line
	args = parser.args()							# get list of command line arguments, parameters, and switches
	if args.verbose > 0:							# print what is on the command-line
		print os.path.basename(__file__), "command-line arguments =", args.__dict__

	# create required objects
	frameID = FrameID()								# create a cycling frame ID sequence number to be used in XBee frames
	at = ATDict()									# create a dictionary of XBee AT Commands definitions
	ser = serial.Serial(args.device, args.baudrate)	# Open the serial port that has the XBee radio
	xbee = XBee(ser)								# Create XBee object to communicate with the XBee radio

	# if user provided desired AT Commands, use them for query, otherwise use the whole dictionary
	if len(args.inputs) == 0:
		args.inputs = at.dictionary()

	# for the command list provided, query the XBee radio AT Command's parameters
	for cmd in args.inputs:
		xbee.send('at', frame_id=chr(frameID.inc()), command=cmd)
		try:
			response = xbee.wait_read_frame()
			if args.name:
				print at.command(cmd) + " = " + byte2hex(response['parameter']) + "  " + at.name(cmd)
			else:
				print at.command(cmd) + " = " + byte2hex(response['parameter'])
			if args.description:
				print at.description(cmd) + "\n"
		except KeyboardInterrupt:
			print "*** AT Command \"" + at.command(cmd) + "\" interrupted. ***"
			if args.description:
				print " "

	ser.close()

Here is a sample output for the XBeeQuery utility:

XBeeQuery Script

References

Configuring the XBee Radios

General Documentation

Advertisements

10 Comments

  1. […] Configuration Utilities for XBee Radios January 30, 2013 […]

  2. dave says:

    Hey,
    Thanks for all the blog posts. Very informative for a newbie. I have some xbee S1’s and am trying to interface them with a Pi. I’m pretty sure they are correctly configured but am having a hell of a time getting them to communicate enough to turn on/off an led. Either via remoteAT or API mode. Hoping you have a few minutes to spare to help debug. I’m starting simple with an Xbee remote plugged into an LED and my other xbee connected to a pc with X-CTU. Settings seem to be inline with your posts and others.

  3. WebPyMan says:

    Great work, however I’m having issues with ‘from pretty import stringc’ not working. Which module do I need to support this ?

  4. gilbert says:

    hi, can i know how to capture packet data information, packet loss, and so on if im using xbee..?

  5. Luis Barbosa says:

    Is there any risk if I connect the Xbee-pro S1 in a raspberry pi? About burn the raspberry pi because a energy consume

  6. ML says:

    The AP Command is only supported when you use the API Firmware. Why is your response an OK in the example above? I’d like to send and receive API Packages, is this also possible with XBeeTerm.py

  7. supreme leader says:

    make a video and post a link here…..

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: