Saturday, December 29, 2012

Make a note: how an XBee replies to 'IS' command

This may save you a couple of days of debugging. Read on and make a note so when you don't understand why 'IS' command doesn't return packet you expect, you remember this post.

OK, when you configure an XBee to send samples periodically, it will send you 0x92 API frame once in a while. So you would expect to get the same frame in either sampling mode - 'periodic', 'on change', and 'querie'. But the thing is that in 'querie' case a remote XBee replies not with 0x92, but with 0x97 with sample data used as a parameter.

This is not stated anywhere in manual, I had to read it many times and finally debug step by step with python and Excel (yes, I use that great programming tool for modelling and visualisation).

I think +XBee Digi guys shell revisit their manuals and explicitly explain this.

Again, I am using python-xbee and I filed a bug. Here's my workaround about this (not a great one, I'm sure, but it works). You should find base.py in python-xbee lib and change the following:

def _split_response(self, data):
....
...
 # If the data field has no length specified, store any
            #  leftover bytes and quit
            else:
                field_data = data[index:]
                
                # Were there any remaining bytes?
                if field_data:
                    # If so, store them
                    info[field['name']] = field_data
                    try:
                        if info['command'] == 'IS':
                            packet['parse_as_io_samples'] = 'parameter'
                    except:
                        pass
                    index += len(field_data)
                break


Friday, December 28, 2012

My first attempt to build a home monitoring/control system

I've been playing with XBees for a while now and about two weeks ago I hit the wall - transparent UART mode has stopped being enough for my hobby. Sensors, devices to control, clocks to sync all aroung house. I had to move on - API mode, explicit addressing, frames parsing...

I, however, also spent some time recently studying some courses (mostly programming) on edx.org (this eats a lot of my time by the way). So I couldn't just get away with simple functional programming approach. I created many classes, I subclassed subclasses and have a pretty sofisticated class structure now in about 10 different python modules. Trying to get through all of this makes my head ake. However if you just look from a 'Main' program stand point, the whole thing is relatively easy and natural. Here how a blinking led example looks like:

def main():

    ## Create a coordinator. This is an XBee, connected to PC via comport
    ## 'COM4' is a comport to where XBee is connected
    ## 57600 is the comport speed
    ## "\x00\x13\xA2\x00\x40\x78\xFD\x76" is 64-bit address of the coordinator module
    ## 'coord' is a human-readable name
    coordinator = XBee24ZBCoordinator('COM4', 57600,
        "\x00\x13\xA2\x00\x40\x78\xFD\x76", 'coord')


    ##print "Hi, I'm Coordinator, my is hw #", coordinator.get_hwuid(),
    ##print 'and name is', coordinator.getName()

    ## Create a remote module. This is an XBee, hanging out somewhere in my house
    ## "\x00\x13\xA2\x00\x40\x78\xFD\x76" is 64-bit address of the module
    ## 'spalnya' is a human-readable name
    remote = XBee24ZBRemote('\x00\x13\xA2\x00\x40\x79\xB2\x71', 'spalnya')


    ##print "Hi, I'm a remote, my is hw #", remote.get_hwuid(),
    ##print 'and name is', remote.getName(), 'and address is', remote.getLongAddress()

    ## Now we are building the network topology
    ## We tell remote to connect to coordinator
    ## This tells remote where to send information and this
    ## also registers this remote with coordinator
    remote.connectToCoordinator(coordinator)

    ## Create a led
    led = LED()
    ## Connect led to remote, tell to which pin and in which mode
    ## remote.getPin('DO4') <- this is a pin on remote with name 'DO4'
    ## 'DO' is pin operation mode. Can be DO (digital out), DI (digital in),
    ## 'ADC' - analog input
    led.connectTo(remote.getPin('DO4'), 'DO')

    ## Tell led to turn on. Notice, after network topology is set (remote
    ## is connected to coordinator and the led is connected to a specific
    ## pin of the remote, we do not have to care about connections any more
    ## we just tell our led to switch on
    led.on()

    ## Digital input sensor (sempling LOW/HIGH level on an XBee pin)
    ## 'test' is a human readable name
    io = DI('test')

    ## connect this sensor to an XBee pin
    io.connectTo(remote.getPin('DI3'), 'DI')
    
    while True:
        ## Read pin
        io.read()
        try:
            ## switch on led
            led.on()
            sleep(2)
            ## switch off led
            led.off()
            sleep(2)
        except KeyboardInterrupt:
            break

    ## Halt XBee and close comport
    coordinator.halt()

Note, that we have to define topology first (like connectTo(coordinator)), but than I simply don't care HOW my led is connected to main server - via XBee, WiFi, TCP/IP, UART or else. I don't have to. I just tell the led to shine and it magically goes on. That's what I wanted to get and it seems I'll get that.

What I have now is a working prototype. I wouldn't been able to do even this without this great XBee library: http://code.google.com/p/python-xbee/


Thursday, December 20, 2012

Fahrenheit is not for embedders


When Fahrenheit came up with his temperature scale back in 1724, he clearly didn' think about embedded applications. If he would, he'd wait till Celsius invents his scale in 1742.

The problem here, if you use Fahrenheit to tell the temperature and you want to make a thermometer with a microcontroller, you will find out what is voltage on a sensor, calculate Celsius from it, and then convert to Fahrenheit by *9/5+32, right? (right, right, unless you've got a Fahrenheit sensor - which you most probably don't)

So you end up spending more cycles and getting a huge error as a result. That's crazy, guys!