Switch xbee from receive to transmit?

I’m trying to roll my own here. I have an Asus WL520GU running openwrt and python. Basically I’m learning about the Tweetawatt and various sensors. All using xBee series 1 radios.

My python script basically loops through the 4 active xbees. Now I’d like to add a new xbee that I can send a signal to via the python script, for example, to turn on a light.

IOW, the reciever in the asus is, well, receiving. How do I change it to occasionally transmit?

See some sample code below…

Any leads and tips appreciated. TIA,
Chris.


from xbee import xbee
ser = serial.Serial(SERIALPORT, BAUDRATE)
ser.open()

while True:
    packet = xbee.find_packet(ser)
    xb = xbee(packet) 
    print xb

    # after calling a web service, I'd like to transmit a signal to an xbee that is connected to a relay/light.


The xbee.py lib:


# By Amit Snyderman 
# $Id: xbee.py,v 1.1 2009/01/20 18:23:01 cvs Exp $

import array

class xbee(object):
       
        START_IOPACKET   = '0x7e'
        SERIES1_IOPACKET = '0x83'
       
        def find_packet(serial):
                if hex(ord(serial.read())) == xbee.START_IOPACKET:
                        lengthMSB = ord(serial.read())
                        lengthLSB = ord(serial.read())
                        length = (lengthLSB + (lengthMSB << 8)) + 1
                        return serial.read(length)
                else:
                        return None
        find_packet = staticmethod(find_packet)
       
        def __init__(self, arg):
                self.digital_samples = []
                self.analog_samples = []
                self.init_with_packet(arg)
       
        def init_with_packet(self, p):
                p = [ord(c) for c in p]

                #print p
                #print len(p)
            
                self.app_id = hex(p[0])
               
                if self.app_id == xbee.SERIES1_IOPACKET:
                        addrMSB = p[1]
                        addrLSB = p[2]
                        self.address_16 = (addrMSB << 8) + addrLSB
                       
                        self.rssi = p[3]
                        self.address_broadcast = ((p[4] >> 1) & 0x01) == 1
                        self.pan_broadcast = ((p[4] >> 2) & 0x01) == 1
                       
                        self.total_samples = p[5]
                        self.channel_indicator_high = p[6]
                        self.channel_indicator_low = p[7]
                       
                        local_checksum = int(self.app_id, 16) + addrMSB + addrLSB + self.rssi + p[4] + self.total_samples + self.channel_indicator_high + self.channel_indicator_low
                       
                        for n in range(self.total_samples):
                                dataD = [-1] * 9
                                digital_channels = self.channel_indicator_low
                                digital = 0
                               
                                for i in range(len(dataD)):
                                        if (digital_channels & 1) == 1:
                                                dataD[i] = 0
                                                digital = 1
                                        digital_channels = digital_channels >> 1
                               
                                if (self.channel_indicator_high & 1) == 1:
                                        dataD[8] = 0
                                        digital = 1
                               
                                if digital:
                                        digMSB = p[8]
                                        digLSB = p[9]
                                        local_checksum += digMSB + digLSB
                                        dig = (digMSB << 8) + digLSB
                                        for i in range(len(dataD)):
                                                if dataD[i] == 0:
                                                        dataD[i] = dig & 1
                                                dig = dig >> 1
                               
                                self.digital_samples.append(dataD)
                               
                                analog_count = None
                                dataADC = [-1] * 6
                                analog_channels = self.channel_indicator_high >> 1
                                validanalog = 0
                                for i in range(len(dataADC)):
                                    if ((analog_channels>>i) & 1) == 1:
                                        validanalog += 1

                                for i in range(len(dataADC)):
                                        if (analog_channels & 1) == 1:
                                            analogchan = 0
                                            for j in range(i):
                                                if ((self.channel_indicator_high >> (j+1)) & 1) == 1:
                                                    analogchan += 1
                                            dataADCMSB = p[8 + validanalog * n * 2 + analogchan*2]
                                            dataADCLSB = p[8 + validanalog * n * 2 + analogchan*2 + 1]
                                            local_checksum += dataADCMSB + dataADCLSB
                                            dataADC[i] = ((dataADCMSB << 8) + dataADCLSB)# / 64
                                            #print "sample #"+str(n)+" for chan "+str(analogchan)+" = ["+str(dataADCMSB)+", "+str(dataADCLSB)+"] = "+str(dataADC[i])

                                            analog_count = i
                                        analog_channels = analog_channels >> 1
                               
                                self.analog_samples.append(dataADC)
                                #print dataADC
                               
                        #checksum = p[10 + analog_count * n]
                        #local_checksum = 0xff - local_checksum;
                       
                        # if (checksum - local_checksum != 0):
                        #       print "Checksum error! checksum: %s, local_checksum: %s" % (checksum, local_checksum)
       
        def __str__(self):
                return "" % (self.app_id, self.address_16, self.rssi, self.address_broadcast, self.pan_broadcast, self.total_samples, self.digital_samples, self.analog_samples)


Is this a crazy idea, or just not interesting?

Perhaps I did not explain it clearly? Simple version:

I have an xBee (embedded in an Asus router) receiving data from 4 xBee based sensors.

Every once in a while from the asus, I’d like to send a signal to a separate xBee that’s hooked up to a relay/lamp.

Does anyone have any leads of sample python code that might help.

Thanks,
Chris.

It’s not crazy, just people don’t like big vague puzzles with code.

The ideal solution is always to configure the remotes to auto-send data, never to poll. So you could become a single loop (not 4 in series) which says “Do I have a message? If so, use the MAC address to decide how to handle”.

Then your loop becomes easy:

  1. do I have data recveived? If so, handle based on MAC
  2. is there something queued to send? If so, send it. Assume any response hits the ‘other’ half of this loop as a receive.

How you queue to send could be as simple as managing a Python list of messages to send. If you are multi-threading, then using the Queue (or queue) module is helpful since it handles the multi-thread concurancy issues.

Thanks for the reply lynnl, “Friend of the Community”… (I like that)

I may have mis-described my setup . The transmitters are sending data. Here is how they are configured:

  • MY - incremented for each transmitter so I can tell them apart
  • SM - Sleep Mode to 4 (Cyclic sleep)
  • ST - Sleep Time to 3 (3 milliseconds after wakeup to go back to sleep)
  • SP - Sleep Period to C8 (0xC8 hexadecimal = 200 x 10 milliseconds = 2 seconds between transmits)
  • ADC 0 - D0 to 2 (analog/digital sensor enable pin AD0)
  • ADC 4 - D4 to 2 (analog/digital sensor enable pin AD4)
  • IT - Samples to TX to 13 (0x13 = 19 A/D samples per packet)
  • IR - Sample Rate IR to 1 (1 ms between A/D samples)

I left the PAN ID as default.

The receiver had no changes.

In the python script, it is basically “polling” the received transmissions in a while True: loop, perhaps because I don’t know how to set up an event mechanism, let alone do multi-threading as you suggest. :wink:

So I think my setup is more or less as you described:

  1. do I have data recveived? If so, handle based on MAC (I’m using the MY value)
  2. is there something queued to send? If so, send it. Assume any response hits the ‘other’ half of this loop as a receive.

Point 1) is where I’m at, and seems to be working OK.

Point 2) I can determine if I need to “send” something (part of my main loop), but with my python code I don’t see how to temporarily switch the configuration of the receiver xbee into transmit mode (specific to another xbee reciever), and then back (resumption of collecting transmitted data).

I hope I’m not getting too big and vague…

Thanks for your help,
Chris.

Friend of the Community (in this case) means I work for Digi :slight_smile: And if you are too stressed out by this Xbee advanture, take a look at http://www.mleiv.com/mt/locked_maze/, which is an amazingly odd web-comic by a talented lass. One of my hobbies is creating 3D rendered images & my efforts are dwarfed by others more talented.

But back to the subject - to successfully survive Xbee, look at this wiki page and try your best to understand the SELECt statement:
http://www.digi.com/wiki/developer/index.php/UDP_to_XBee_Network

This allows you to create a simple, single-minded loop that only deals with sending and reciving, with NO concern for application (or truth and justice!)

Then try to learn about threading (aka: multi-tasking) such as: http://docs.python.org/library/threading.html
http://docs.python.org/library/queue.html

You want to split your task into 2 parts. One thread that attempts to run your process-model, and another thread that attempts to manage the send/recieve which happens in opposition to your simple linear model of the process/application.

The iDigi/Dia framework does this (despite beign a huge “pill-to-swollow”). You cannot approach this problem as a simple liner I do A, then B, then C problem. Your remote devices send data when they wake, with no consieration for where you are in your program.

Thanks Lynn,

This is the kind of nudge I needed to get me looking in the right direction. I’ve a fair amount of programming, mostly in VFP and for the last 10 years in C#, but I’ve never needed to do any multi-threaded/multi-tasking. Now it seems it’s time.

As usual, what starts as a relatively simple project turns into a rabbit hole of new things to learn and I find myself reading a socially maladjusted ex-mormon’s comic titled The Locked Maze. She really is incredible.

The Locked Maze, indeed. I will peruse the links you sent but I’ll probably be back…

Thanks again,
Chris.

PS: would love to see some of your work also…