This blog post describes an issue I am having with the XBee 2.2.3 Python package where the callbacks that are supposed to happen when new packets are received suddenly stop. I managed to find the reason for this as well as an at least temporary solution.
A bit of background
I just tried to add a second node to my small ZigBee network (now consisting of a coordinator and two routers) and ran into a bit of trouble. The new node has a new version of the XBee radio, namely XB24CZ7PIT-004. This has replaced the previous product XB24-ZB from Digi and it has a new firmware which simultaneously supports coordinator/router/end point. So one does not have to upload a firmware specific to the role the radio is playing in the network. Maybe it has other subtle differences as well. I do not know if the new radio version is relevant to the problems I am having, but I thought I’d better mention it.
I use a callback function to receive the data from the XBee, but the problem is that when I added the new XBee (as a router), I just got one or a few packets back from the coordinator (which is the one I talk to using Python) before callbacks stopped. I discovered that a new error callback feature had been added in 2.2.2, so I made use of this to try to troubleshoot:
# Callback function that runs when XBee errors are detected def xbee_error(e): print "XBee error!" print e xbee = ZigBee(ser, callback = receive_data, error_callback = xbee_error)
This gave me the following printout before receive_data callbacks ceased:
XBee error! 'Unrecognized response packet with id byte \xa1'
So apparently a “new” kind of packet with frame type A1 has started to show up for some reason unknown to me. This turns out to be a “Route Record Indicator”. I have not looked into why this happens, but since the A1 frame type is not defined in the api_responses dictionary in zigbee.py and there is a new except-clause with a break in the definition of run() in base.py, I think the thread that receives data from the XBee and calls the callback function thereby terminates when such an unrecognized frame id is received.
I do not think this is appropriate behavior in this case. The thread should not die just because an A1 frame ID appears. I solved it quickly and in an ugly manner by commenting out the troublesome break in base.py:
def run(self): """ run: None -> None This method overrides threading.Thread.run() and is automatically called when an instance is created with threading enabled. """ while True: try: self._callback(self.wait_read_frame()) except ThreadQuitException: # Expected termintation of thread due to self.halt() break except Exception as e: # Unexpected thread quit. if self._error_callback: self._error_callback(e) <b>#break # Commented out by Per M 2016-01-06</b>
There are probably better ways to solve this. Maybe the A1 and other possible frame IDs (see the API frame specifications section in the XBee User Guide) should be added to api_responses in zigbee.py.