Monthly Archives: July 2015

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.

 

Solution to Very Slow Keyboard Response in IPython

I am starting to use Python (on Windows) and am running IPython as well as pylab and matplotlib. I had a problem though, keyboard input in IPython was very slow (maybe half a second delay for each character). This was extra noticeable when pasting e.g. a path. After some googling around, I found this discussion:

https://groups.google.com/a/continuum.io/forum/#!topic/anaconda/kvWVtW40aDI

There, they say that starting IPython using the following command could help:

ipython console --pylab

I adapted this to Windows by right-clicking the on the IPython icon in the start menu and added

console --pylab

to the string in the target field so that it reads:

C:\Anaconda\python.exe "C:\Anaconda\Scripts/ipython-script.py" console --pylab

When I now start IPython through this shortcut, the delay is almost completely gone! When I paste in a string, it might take a tenth of a second or so for 20 characters to be pasted, which is not really fast, but still well below the limit for being annoying and a vast improvement over the previous situation.