Interfacing to an XBee Module from Python

In a previous post, I described how to talk to an XBee ZigBee module from a FRDM development platform. In this post, I describe how to do it from Python on e.g. a Windows PC.

First, one obviously has to have a Python environment set up on the computer. I use Python 2.7 and the IPython interactive shell. I will not describe how to install that, but it should not be too hard to do using the instructions on the IPython website.

Then we need to install two modules to enable communication with the XBee. The first one is simply called xbee and can be found here. Download, unpack (using e.g. 7-zip), start a cmd window, cd to the folder with the downloaded files and install it by typing:

python setup.py install

The second is pyserial. Download it from here and install it in a similar manner as described above. This module mentions that it is intended for 32-bit windows, but it has worked fine for me on 64-bit Windows 7.

I use a SparkFun XBee Explorer USB board to interface to the XBee module. This provides an FTDI serial port for communication with the XBee. I soldered an LED with a series resistor between DIO1 and GND to provide easy verification that I was able to control the I/Os of the XBee. The XBee needs to be in API mode. If it is not, the XCTU program from Digi can be used to upload a proper firmware to the module.

Here is the program I wrote to test communication with the XBee:

#! /usr/bin/python

# Demo to talk to an XBee ZigBee device
# Per Magnusson, 2015-07-28
 
from xbee import ZigBee
import serial
import serial.tools.list_ports
import time
import sys

# Look for COM port that might have an XBee connected
portfound = False
ports = list(serial.tools.list_ports.comports())
for p in ports:
    # The SparkFun XBee Explorer USB board uses an FTDI chip as USB interface
    if "FTDIBUS" in p[2]:
        print "Found possible XBee on " + p[0]
        if not portfound:
            portfound = True
            portname = p[0]
            print "Using " + p[0] + " as XBee COM port."
        else:
            print "Ignoring this port, using the first one that was found."

if portfound:
    ser = serial.Serial(portname, 9600)
else:
    sys.exit("No serial port seems to have an XBee connected.")

# Flash the LED attached to DIO1 of the XBee
try:
    xbee = ZigBee(ser)
    print "XBee test"

    xbee.at(command='D1', parameter='\x05') # Pin 1 high
    resp = xbee.wait_read_frame()
    print resp

    time.sleep(1)
    xbee.at(command='D1', parameter='\x04') # Pin 1 low
    resp = xbee.wait_read_frame()
    print resp

    # Try another AT command
    xbee.at(command='ID')
    resp = xbee.wait_read_frame()
    print resp
    print "Done"
    ser.close()
except:
    print "Error!"
    ser.close()

raw_input("Press Enter to continue...")

The program has some bells and whistles. First it looks at all the serial ports it can find and selects the first one that could be the XBee (indicated by the text FTDIBUS in the description of the port). It then tries to set up a connection to the ZigBee and issues three local AT commands. The first turns the LED on (then it waits for 1 second), the second turns the LED off and then it issues the ATID command. The response from these commands are printed. At last the serial port is closed and the program waits for the user to press enter to exit the program.

The output may look like this:

In [3]: %run xbee_prog.py
Found possible XBee on COM3
Using COM3 as XBee COM port.
XBee test
{'status': '\x00', 'frame_id': '\x01', 'command': 'D1', 'id': 'at_response'}
{'status': '\x00', 'frame_id': '\x01', 'command': 'D1', 'id': 'at_response'}
{'status': '\x00', 'frame_id': '\x01', 'parameter': '\x00\x00\x00\x00\x00\x00\x0
0\x01', 'command': 'ID', 'id': 'at_response'}
Done
Press Enter to continue...

In [4]:

Stupid mistake

While writing this program I made a stupid mistake that prevented it from working. I happened to name the program xbee.py and this made the line

from xbee import ZigBee

import the program itself, instead of the installed module. The error message was: ImportError: cannot import name ZigBee. Renaming the program from xbee.py to xbee_prog.py solved this issue.

Now that I realize that Python imported the program itself instead of the module, it is obvious why it could not find ZigBee inside it, but it took a while before I figured that one out.

 

4 thoughts on “Interfacing to an XBee Module from Python

  1. Hey, thanks for the article I ran this code, but it only gave me this output:

    Found possible XBee on COM3
    Using COM3 as XBee COM port.
    Found possible XBee on COM4
    Ignoring this port, using the first one that was found.
    XBee test

    I have Xbees connected to both COM3 and 4, can you explain why it did continue testing the XBee?

  2. Hi Brendan,

    The code is written to work with a single XBee attached, since this is my current configuration. You have to modify it to work with multiple XBees.

    The reason I did not write the loop such that it terminated as soon as it found an FTDI serial port is that the heuristic of looking for the first FTDI serial port adapter to find the XBee port can fail and the user (me) should be informed if there are other FTDI ports that could be the correct XBee port to use. If this code is to be used on a system with more than one FTDI USB serial port, it has to be rewritten to make some other test to determine which one is the XBee port.

  3. How about rewriting it to work on a Raspberry pi? This is where a lot of the XBee and Zigbee devices usually wind up.

Leave a Reply to Brendan Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.