Saturday, April 19, 2014

Android, Samsung Phone, My very own app, and a Raspberry Pi Home Automation Server

I did it; I finally took the plunge and created an app for Android that runs on my phone and controls the house.  I didn't want to go through the learning curve necessary to conquer the Android Development Environment, so I just relied on the web interface for all this time.  The problem is that I got a new phone and it was too great a temptation for me.  I had to do it.

I lucked out and ran across Appdeveloper 2 from MIT (it was once owned by Google) and it looked pretty cool, so I started trying it out.  The very first tutorial was enough to get me wound up.  Over several days, I experimented and coaxed an app out of it and then went totally nuts.  It's still a work in progress like all my projects, but it is SO COOL!

Here's the screen you see when you first tap on it


The first three buttons: Power, Temp, and Clock open the SteelSeries gauges I've already created and put them up so I can watch them.  The clock is bound to the time at my house so I can see exactly what time it is there wherever I am.  The data is supplied by my Raspberry Pi in JSON format so there is very little traffic to load it down.  All the formatting and such is done exclusively on the phone saving my little Pi for doing the monitoring tasks.  Those buttons were a pain.  Do you know how hard it is to find cool buttons out there?  That is without having to spend days editing them to get them to look OK.  Here's what it looks like with the power gauge showing:


Yes, this is the exact same display code I use for the web interface.  Appinventor 2 has provisions for a little browser that can handle javascript code.  I can't do the fancy graphs yet, because they are Flash based.  I'll have to look into that in the future.  Just for fun, here's the display when I put up the temperature gauge:


I stack the various controls and gauges one on top of the other so I can scroll between them if needed.  For example, Here's the screen when I have both thermostats showing:


I color the buttons yellow to show inactive and green for active which means they should be showing on the screen.  You can see how the two A/C unit selectors are green and below the controls and status of each of them.  One of them is idle and the other is recirculating the air; that's what the green fan is showing.  Yes, the fan turns; figuring out how to make it rotate was painful since the tool doesn't support animated GIFs yet.  The black fan doesn't turn silly, it means it isn't running.  There's also red and blue fans to show heating or cooling.  The tool has a 'picker' screen built into it, so to change the mode from Off to something else I pop up this display to choose from:


There's something similar for the fan also.  I got fancier on the temperature and put up a slider and set buttons:


When you slide it towards the red, the temperature setting goes up and similarly the other direction, then touch set and you have a new temperature setting.  When you touch set, the temperature controls go away and it leaves you with just the thermostat readings displayed.  This gives me darn good control over the thermostats and a nice flashy display.  I put pictures on the lights to show their state:


Those lights were a total pain in the butt.  I had to construct them from pictures that were waaay too big and didn't match the off representation.  Took a few hours using paint.net to get them right.  To turn off the lights, just touch the icon itself:


Notice how I managed to find a nice clear bulb and use it for both states.  No, I can't dim the bulbs, nor do I want to.  The garage doors are still pretty primitive:


But, they get the job done.  I want to fancy that display up some over time.  Similarly, the pool controls are still in the beginning stages:


Lots of refinements are needed here.  All of it works though, I can turn on the pool light anywhere I have data service on the phone.  Of course, no rural place would be complete without knowing the state of the septic tank:


When septic gets too full, the OK icon goes red.  I do the same thing when the acid pump goes low.  I show this to people and they invariably click on the septic tank:


I love their reaction when they have to select "I'm a Dummy" from the picker.  There's a couple of Easter Egg messages like that in other places as well.  Hey, gotta have fun with it too ... right?

Needless to say, I spent a heck of a lot of time just playing with the controls and watching things turn on and off around the house.  I actually had the front lights cycling in a kind of rhythm for a while, much to the amusement of the neighbors.  I guess the new will wear off in a few weeks, but then I'll just make something else and hook it into the system.  I'll also be looking for cute icons to include in various places in the app; it would be nice to have a cartoon garage door to show when it is open.  I'm thinking about using my old cell phone as a house control.  Take the battery that expanded out <link> and hook it to power.  Since everything will work except the actual phone, I should be able to turn it into a house controller that sets by the bed, or maybe mount it on the wall.  It would give me great pleasure to repurpose that device so it would actually get some use ... finally.

I can't wait to show this off.  So, people, what's holding you up from building something like this as well?  No, I won't port this to the iPhone.

Sunday, April 13, 2014

Why I'll Never Buy Another Motorola Cell Phone

A couple of years ago I pre-ordered a Motorola Razr Max cell phone.  It came right on time, the day it was released, and was SO COOL!  It was running Android and had all the bells and whistles that modern technology could create.  I specifically waited for this phone because they put a battery in it large enough to last a full day of normal use and because the screen was big enough to actually use the device.

I was so stoked.  I played with it for days, customizing every little tiny feature.  I carried it with me everywhere. It became a companion.  Don't get me wrong, I don't spend all my time chatting on the phone, text messages are mostly unused, and email can wait until I have a real keyboard to use.  But I could turn my lights on using a web browser from the Burger King in town.  This is a techie's dream.

Then one day I was taking a picture in the back yard and the screen cracked.  Yep, it cracked vertically from top to bottom when I touched the little icon on the screen.  I couldn't believe it.  Here was a device that had a Kevlar case and Gorilla Glass screen and was advertised as being able to handle 'real life' that broke under my index finger.

I called the cell phone provider about the problem and met with the, "physical damage is not covered under warranty" line.  I argued for almost an hour that taking a picture wasn't damage, it was normal use, but they didn't give an inch.  I took it to one of the corporate stores and they did the same thing. I was totally annoyed and actually thought about a little mayhem as a possible route to some degree of satisfaction.  I even contacted the manufacturer about it.  The result was exactly the same.  Their logic is that a cracked screen is a result of damage, not bad design or manufacture.  They couldn't possibly be at fault.

Having exactly zero success trying to get someone to acknowledge that there was a problem that needed correcting, I used the insurance I bought along with the phone.  A hundred bucks later, I had a new phone just like the old one, but the magic was gone.  The device was too fragile to trust.  I equipped it with an otterbox, which make it boxy and ugly, but it might survive being used and nursed it along.

During this time I noticed a slight bulge on the back of the phone; the darn battery was swelling.  Yep, the state-of-the-art lithium-ion battery was puffing up and distorting the case.  So much for embedded batteries that you can't change; it was failing in one year nine months and bending the back cover.  Again on the phone with the provider and they say that it's out of warranty and there's nothing to be done, but I could use the insurance again (another 100 bucks) and get a replacement.  I decided not to send good money chasing after bad and continued to treat the phone like a new girl friend until the contract ended.

My thinking was that I'd get a different manufacturer's device and maybe have better luck.  And, as luck would have it, Samsung announced that their Galaxy 5 would come out in a couple of months; last Friday (the release date) my new phone was delivered to the house (again on the day of release).  I'm in love again.

However, I still have a bitter taste in my mouth about putting up with a piece of crap for two years because Motorola created a hunk-o-junk, but I'll get over it in time.  Here's a couple of pictures of the damage done by the expanding battery:


The bulge is really obvious, but take a look at the next photo.


The case has actually split at a seam and you can see inside the phone if you get a flashlight.  This is the damage that Motorola and Verizon won't warranty because too much time has passed.  Just like the crack down the screen they wouldn't cover because of 'physical damage'.  The swelling actually broke the speaker on the back, so I couldn't hear a ring; I had to rely on vibrate for the last month.

What a racket.

Yes, I know that one should get a case for a cell phone.  But doesn't that eliminate the need to make it slim, attractive and stylish?  Take a piece of high tech jewelry and hide it inside a poly carbonate case with a silicon protector around it and it looks like a plastic box, not a cell phone.  Yes, I know that screens can crack, but when you touch it to take a picture??  What the heck is up with that?  That generation of Gorilla Glass doesn't deserve the name.  The good thing is that I tested the heck out of the Otterbox case; I'm certain that the case was the only reason I didn't have to replace the phone a couple more times.

So ends an annoying chapter of my life.  I would change carriers to get away, but no other carrier works out here.

Now, I get to play with all the features of a new phone.  I get to customize every little thing and put pictures of my dog on it to annoy other people with.

Motorola used to be a great company.  Maybe Google will bring some of the life back to them since they took over the mobile phone part, but I'm keeping my distance.

Tuesday, April 8, 2014

Kissing Goodbye to DynDns

For a long time now I've been using Dyn's free service DynDns.  For those of you that don't understand what I'm talking about, most homes have DSL provided by one of the big names or cable modems provided by some of the same big names.  I happen to have CenturyLink (used to be Qwest).  With these services, your IP address changes periodically so it's hard to have a name linked to an IP address when it changes every time the provider decides they want to.  At one time CenturyLink was changing my IP address a couple of times a day.

So there are a number of dynamic dns services out there that will update the various name servers on the internet when your IP address changes.  Doing something like this saves you the extra fee for a static IP and you can still get to your home machine by some name or other.  These services used to be free, but over time, they've started to charge for the service.  Dyn just did this.  Over the weekend I got an email telling me that my free account with them would be cancelled.

So, what to do?  I simply signed up with a different service and changed the bookmark in my browser.

Now, a lot of you folk can't do it that easily.  You may have distributed the name of your site or machine to friends and relatives and now you would have to let them know it changed.  Or, perhaps wait until they try it and give you a call to see what happened.

Don't misunderstand, I don't mind paying for value.  If they had said that they were going to charge $5 a year for this service I wouldn't have even thought about it, I would have just signed up and paid the five bucks.  They wanted $25 a year (discounted the first year), and frankly, that's too much for such a simple thing as sending an update to the name servers that your IP address has changed.  To be fair, they offer a number of other services and have a good reputation, but I don't need the other services.  Perhaps someday when I have a huge corporation to worry about, I might consider them again.  For now, my one little blog and one little computer will do just fine without them.

So, if you want to visit my home control and monitoring system, use this link <link>.  Strangly, it took me about six minutes to get it working and another ten to find the software to keep it updated through IP address changes.  That's about 1/10th the time it took me to set it up originally with DynDns.


Wednesday, March 5, 2014

I Want To Complain about 'Experts'

My refrigerator started giving me trouble.  No, it wasn't the Iris Smart Switch I installed in the power, it was that the darn thing started to get warm.  I opened the door and the little thermometer I have inside said it was 55 F inside.  It usually runs under 45, so something was up.  I checked all the obvious things, the compressor was going, the fan on the condenser coil was running; I couldn't see anything obvious.

Once again, a little bit about the refrigerator:  It's a refrigerator (only) that I've had for some years and it has given me trouble before; I even had to have the evaporator coil replaced.  I got this thing because I wanted it to be the last refrigerator I'd ever buy.  To meet that I got the very top of the line GE Monogram model ZIRS36 in stainless steel (ZIRS36NMRH).  It's a really, really old design that doesn't even have a frost free option.  That's because it has no freezer inside and just doesn't form frost.

Basically, the power comes in, goes to the temperature control, then to a temperature sensor on the evaporator coil (to prevent freezing up) and then to the compressor.  There's three fans: one on the top to cool the condenser and condenser coil, one inside to circulate air from the evaporator coil to the rest of the fridge, and one on the bottom to evaporate any water that drains out of the evaporator.  Then the lights are all that's left.  Not much to go bad, and not much to troubleshoot when it has problems.

However, I couldn't find anything wrong with any of those things, so I went to the web and found this discussion on one of those 'Ask an Expert' sites <link>; basically, the expert said the correct thing first, then corrected himself to the wrong thing.  This fridge is a middle level cooling system.  It doesn't cool below freezing anywhere inside except the actual surface of the evaporator coil.  It maintains a temperature of about 38 degrees and doesn't need a defrost timer or defrost heater at all.  The customer in the discussion tells the expert this, but that doesn't keep the expert from getting confused and messing it up.  I chuckled a little bit and then found this discussion <link>;  once again, the expert changes his mind midstream and messes it up.

The last link is especially interesting because a couple of other repairmen get into it and try to straighten things out.  By the very bottom of the discussion, the actual possible problems finally show up.

So, what was wrong with mine?  The door needed to be adjusted.  Yep, the door has sagged a little bit over the years and was far enough down that it didn't close a switch at the top that turns on the fan for the evaporator.  See, if the fan isn't on, the evaporator goes into freezing range and the temperature sensor I mentioned above, shuts off the compressor to prevent ice forming and breaking the evaporator coil.  I drug out the tools and modified the top hinge to be adjustable and reset the door.  Problem solved.

The reason I had to modify the hinge was because GE made provisions for raising and lowering the door, but not tilting it.  They even avoid the subject in their installation manual (yes, I read it) like a door will never, ever skew a little bit.  The experts out there will tell me that I should adjust the fridge to assure that it's square because that can cause the same problem; I did that first with a nice level, framing square, and all.  Nope, the door actually needed to be adjusted.

But the point of this is that after I found the two discussions listed above, I found several others where the expert just wouldn't listen to the customer, assumed he knew everything, and screwed it up.

I'll never, ever ask a question on one of those sites.

But, there were a few good things that came out of this fiasco.  I moved the Smart Switch back to the fridge (I had it on the freezer for a few days), and took a look at the power usage during the problem:


Notice the small spikes?  It seems the compressor was turning on for a very short period, then shutting off for a very long period.  This was because the evaporator coil got too cold (no airflow) and the thermal protection kicked in and shut the compressor off.  This is very different from the graph I blogged about earlier <link>.  Another thing good about this was that I improved the performance of the appliance:


Now, the compressor is on longer, but off longer as well.  I turned the temperature control down and allowed it to stabilize at 38 F and all seems to be well.  Of course, something else can crop up and cause problems, but it looks like I fixed it.

Edit:  It's been a little over a day since I fixed the door on the fridge and I thought someone out there might be interested in the result.  Yes I fixed it, and I made out like a bandit on this:


Ignoring the couple of bumps in the middle of the chart, notice how it has settled down to a regular rythm?  It's on for about 15 minutes and off for around an hour and a half.  The huge spike in the middle is when I had the door open and the compressor kicked on at the same time; 300 W for the lights and around 400 W for the spike of the compressor starting.  The other bump right next to it was where I finally finished up assembling the fridge.  I put the drawers back in that I had take out to check things and also the temperature controller cover.  

Net, over time I'll get a feel for the usage of the fridge and a simple check every once in a while will tell me if it's working OK, or if it needs some attention.  It would be cool to completely automate the operation of this device with a little computer and radio combination, but not now, I want to take a really close look at the freezer setting nearby.  Then I'll take a look at the chest freezer I have out in the garage.  These appliance have been blamed by many people for using too much power, but my experience is the exact opposite.  The pool is my biggest electrical usage followed by the water heater.  Those I have under control with load balancing to off-peak periods and solar assistance.  Next is the two A/C units I have;  if I left them to run on their own, they would far exceed everything else, but I control when they can run also to minimize their impact on my wallet.

So, you folk that are looking at one of those multi-hundred dollar fancy thermostats to control the temperature in your house, think again.  You won't get nearly as much information from them as I do with my set up, and you won't be able to control it as well.  Sure, you'll have to actually learn something instead of buying the hype they try to sell you, but what's wrong with that?

Smart grid my butt, smart house is the solution.

Sunday, February 23, 2014

Raspberry Pi, USB, and XBee

I have two XBees hooked to my Pi now, one to control the network I've been building for a long time hooked to the serial port, and the other acting as a controller for my Iris Smart Switch hooked into a USB port.  I like the Smart Switch, so I'll be using more of them and that meant I had to figure out a better way to hook two XBees to the Pi and make it work.

I really didn't want to get into the mess of trying to get another standard serial port working because I eventually want LEDs for indicators of things that are important and maybe even a display that I can put words on.  Heck, I could decide to put voice on it at some point.  So, since the Pi comes with two USB ports, I decided to move both of the XBees to USB.  I started out with the USB explorer that I have to program the XBees:


I've had this board a long time and it just works.  Never had a problem with it, so I just plugged it into one of the USB ports on the Pi and changed my code to point to it.  It worked after a tiny bit of messing around.  Now I could control my own stuff and read the Smart Switch as well.  That proved that it could be done so I got two of these:


I chose this board so I could use a short USB cable to connect it, avoiding the problem of the bigger board above not fitting.  With these plugged into the Pi, I could still control the house and have all my GPIO pins available for whatever else I decide to do someday.  But, as usual, there was a problem.  See, USB is designed to be plugged and unplugged so you can change devices on the Pi, that unfortunately means that the address of the XBee will change each time you unplug it from the USB port.  So, one time I would have the smart switch on /dev/ttyUSB0 and the next time it would show up on /dev/ttyUSB1.  Makes coding for it more complex, and I really don't want complex right now.

It turns out that there is another way to connect to it.  Under the directory /dev is another directory 'serial'; looking in /dev/serial, I found two other directories by-id and by-path.  The by-id directory holds the device ids of the USB to serial chip and that doesn't change as you plug and unplug it.  So, I changed my code to define the serial port to this:

XBEEPORT = '/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A901QLG3-if00-port0'

Yes, it's long and obscure, but that's what variables and comments are for.  It's also hard to type in, but that's what copy and paste are good for.  All in all, not a bad way to go as long as I don't reverse which little board I have the XBee plugged into.  Remember this little trick when your USB device seems to disappear.

So, now I have all the GPIO pins available; wonder what I'm going to plug into them.

Tuesday, February 11, 2014

Using the Iris Smart Switch to Measure Appliance Power

Since I finished the example of how to operate the Iris Smart Switch with a Raspberry Pi, I couldn't wait to hook it to something and do something real with it.  I decided to measure the power usage of my refrigerator.  First, about the refrigerator:  It's a refrigerator only, it doesn't have a freezer section; I have a separate freezer in the kitchen also.  There's a reason for this besides showing off.  Out here in the sticks where a trip to the grocery store is a major undertaking, we don't go very often.  That means plenty of food storage; I have a pantry, an upright freezer and separate refrigerator in the house and a chest freezer in the garage.  Yes, I can go about two weeks before I even have to go for bread and milk.  This makes things like a shopping list that is up to date a valuable skill.  I keep it up to date and every time I'm forced into town, it goes with me.  I don't want to waste a trip.

Anyway, I put together some code and read the switch, recorded the readings in my database and updated Xively with the data.  Then I suck the accumulated data from Xively and graph it to see what the appliance is doing.  I didn't implement the ability to turn the switch on and off since who wants to shut their refrigerator off??  Here's a days worth of data on the refrigerator:



Notice how it's only on for a short amount of time and that, other than the spike when the compressor starts, it doesn't use much power?  It's on roughly 15 minutes, and off for about 30 minutes in repeating cycles.  Here is an expansion of a portion of it:


The large spike on the first 'hump' is where the compressor kicks on.  It takes a lot of power to get the compressor going, but it drops off rapidly.  The granularity of the readings is only a minute, and if I was graphing every few seconds, you would see spikes on all the humps.  However, this is an accurate representation of what is happening overall.  Notice that the 550W spike is short and that the current draw decreases over time.  The average usage is probably around 110W or so for the period where the compressor is on.  That's the amount of energy used by some incandescent bulbs !  Let's see what a door open does to the chart:



Notice that the power usage jumps (the hump on the right) to 300W when the door is open?  It's pretty sobering that the power used by the lights when the door is open is actually more than the power used to keep the darn thing cold.  Now see why they say to close the door to save energy?  They just didn't tell us that the power loss was due to the bulbs, not the fact that we're warming up the fridge.  I'll probably get arguments from the energy nerds out there, but for my appliance, this is true.  Or, at least it is right now; I plan on getting LED bulbs to take care of that silly problem in the next couple of weeks.

Of course, there's the compressor kicking on right after I closed the door because I left the door open for a couple of minutes and it had to recover the temperature.  That's why the hump for the lights is on the far right, I actually went over and opened the door to get this reading.

All in all though, the fridge is not a huge power consumer.  It's less than running a 100W bulb all the time.  Actually, it's probably close to a 40W bulb since it's off twice as long as it's on in any given period.

Let's review.  I hacked into the Lowe's smart switch using an arduino (it's what I had to play with)<link>, ported the code to python so I could run it on a Raspberry Pi <link>, and then hooked it up to an appliance and learned that it was actually doing a good job.  Actually better than I expected.  Was it worth it?  Of course it was.  Now folks out there can take my example and measure their own appliances to compare them to their own expectations and needs.

Soon, I'll get another Smart Switch and put it in the circuit for the freezer and see how much power it uses.  I expect it to be higher than the fridge because it has the same set of lights, a bigger compressor and the circuitry for auto defrost.  Auto defrost is a real power monger since it actually warms up some areas of the appliance and drains the water out to be evaporated away.  I also want to see how often it cycles since it could happen that the compressor on the freezer and the compressor on the fridge could overlap their cycles.  That would cause a spike in power usage for the overlap period, which in turn, could cause my demand usage to rise.  That's the kind of thing I want to keep track of.  Demand billing is a painful thing because a simple mistake in power usage could double your monthly power bill.  I have a long discussion about my experiences here <link>.

Now, go out and get your own system of monitors running.  Take control of your house.

Monday, February 10, 2014

Raspberry Pi and the Lowe's Iris Smart Switch

So, I got the Lowe's Iris Smart Switch working pretty well for the Arduino <link>.  The problem is that it isn't where I want the software to run.  I have a Raspberry Pi controlling the house <link> and this software should go there.  As I mentioned, I don't have a spare Pi right now, so I worked up the software for the Arduino with the full intention of moving it to the Pi as soon as it worked and I had time to mess with it.

Well, I decided the cool thing to do was to port the test software directly to the Pi in python and run it there.  I approached this with a little trepidation; taking things from an Arduino to another platform and language can drive you nuts.  First, I already have an XBee attached to the Pi; it uses the (only) serial port on the little device, so I got a Sparkfun XBee explorer <link> and plugged it into the USB port.  Fully expecting to have to jump through a bunch of hoops to get it to work, I did a simple 'cat /dev/ttyUSB0' command and actually got output to the screen on the very first try!

Sure it was garbage and didn't mean much, but I got output that corresponded to pushing the button on the switch.  Step one was done.  Next I put together a little code using the python XBee library to catch a packet and see what happened.  Right off the bat, I got this printed on the console of the Pi:

{'profile': '\xc2\x16', 'source_addr': '+\xd1', 'dest_endpoint': '\x02', 'rf_data': '\t\x00\x81T\x00', 'source_endpoint': '\x02', 'options': '\x01', 'source_addr_long': '\x00\ro\x00\x027\xb2Z', 'cluster': '\x00\xef', 'id': 'rx_explicit'}

Holy Cow, the library already had support for the ZigBee specific messages!  Notice that the fields have names already, and the ones that it took me so long to figure out are already there.  This means I can jump right in and start taking the messages from the switch apart.  It worked like a charm; there were some understanding problems in that the XBee library returns the data as character strings inside a dictionary of the various fields in a message, but these can be overcome once you catch on to what is happening.  Once I could decode the messages and print the power values and state of the switch, I implemented the commands from the Arduino code and they worked quite well.  So, here are the same capabilities that I presented for the Arduino implemented on the Raspberry Pi:

The Python Script
#! /usr/bin/python
# This is the an implementation of controlling the Lowe's Iris Smart
# Switch.  It will join with a switch and allow you to control the switch
#
#  Only ONE switch though.  This implementation is a direct port of the 
# work I did for an Arduino and illustrates what needs to be done for the 
# basic operation of the switch.  If you want more than one switch, you can
# adapt this code, or use the ideas in it to make your own control software.
#
# Have fun

from xbee import ZigBee 
from apscheduler.scheduler import Scheduler
import logging
import datetime
import time
import serial
import sys
import shlex


#-------------------------------------------------
# the database where I'm storing stuff
DATABASE='/home/pi/database/desert-home'

# on the Raspberry Pi the serial port is ttyAMA0
XBEEPORT = '/dev/ttyUSB0'
XBEEBAUD_RATE = 9600

# The XBee addresses I'm dealing with
BROADCAST = '\x00\x00\x00\x00\x00\x00\xff\xff'
UNKNOWN = '\xff\xfe' # This is the 'I don't know' 16 bit address

switchLongAddr = '12'
switchShortAddr = '12'

#-------------------------------------------------
logging.basicConfig()

#------------ XBee Stuff -------------------------
# Open serial port for use by the XBee
ser = serial.Serial(XBEEPORT, XBEEBAUD_RATE)

# this is a call back function.  When a message
# comes in this function will get the data
def messageReceived(data):
#   print 'gotta packet' 
#   print data
    # This is a test program, so use global variables and
    # save the addresses so they can be used later
    global switchLongAddr
    global switchShortAddr
    switchLongAddr = data['source_addr_long'] 
    switchShortAddr = data['source_addr']
    clusterId = (ord(data['cluster'][0])*256) + ord(data['cluster'][1])
    print 'Cluster ID:', hex(clusterId),
    if (clusterId == 0x13):
        # This is the device announce message.
        # due to timing problems with the switch itself, I don't 
        # respond to this message, I save the response for later after the
        # Match Descriptor request comes in.  You'll see it down below.
        # if you want to see the data that came in with this message, just
        # uncomment the 'print data' comment up above
        print 'Device Announce Message'
    elif (clusterId == 0x8005):
        # this is the Active Endpoint Response This message tells you
        # what the device can do, but it isn't constructed correctly to match 
        # what the switch can do according to the spec.  This is another 
        # message that gets it's response after I receive the Match Descriptor
        print 'Active Endpoint Response'
    elif (clusterId == 0x0006):
        # Match Descriptor Request; this is the point where I finally
        # respond to the switch.  Several messages are sent to cause the 
        # switch to join with the controller at a network level and to cause
        # it to regard this controller as valid.
        #
        # First the Active Endpoint Request
        payload1 = '\x00\x00'
        zb.send('tx_explicit',
            dest_addr_long = switchLongAddr,
            dest_addr = switchShortAddr,
            src_endpoint = '\x00',
            dest_endpoint = '\x00',
            cluster = '\x00\x05',
            profile = '\x00\x00',
            data = payload1
        )
        print 'sent Active Endpoint'
        # Now the Match Descriptor Response
        payload2 = '\x00\x00\x00\x00\x01\x02'
        zb.send('tx_explicit',
            dest_addr_long = switchLongAddr,
            dest_addr = switchShortAddr,
            src_endpoint = '\x00',
            dest_endpoint = '\x00',
            cluster = '\x80\x06',
            profile = '\x00\x00',
            data = payload2
        )
        print 'Sent Match Descriptor'
        # Now there are two messages directed at the hardware
        # code (rather than the network code.  The switch has to 
        # receive both of these to stay joined.
        payload3 = '\x11\x01\x01'
        zb.send('tx_explicit',
            dest_addr_long = switchLongAddr,
            dest_addr = switchShortAddr,
            src_endpoint = '\x00',
            dest_endpoint = '\x02',
            cluster = '\x00\xf6',
            profile = '\xc2\x16',
            data = payload2
        )
        payload4 = '\x19\x01\xfa\x00\x01'
        zb.send('tx_explicit',
            dest_addr_long = switchLongAddr,
            dest_addr = switchShortAddr,
            src_endpoint = '\x00',
            dest_endpoint = '\x02',
            cluster = '\x00\xf0',
            profile = '\xc2\x16',
            data = payload4
        )
        print 'Sent hardware join messages'

    elif (clusterId == 0xef):
        clusterCmd = ord(data['rf_data'][2])
        if (clusterCmd == 0x81):
            print 'Instantaneous Power',
            print ord(data['rf_data'][3]) + (ord(data['rf_data'][4]) * 256)
        elif (clusterCmd == 0x82):
            print "Minute Stats:",
            print 'Usage, ',
            usage = (ord(data['rf_data'][3]) +
                (ord(data['rf_data'][4]) * 256) +
                (ord(data['rf_data'][5]) * 256 * 256) +
                (ord(data['rf_data'][6]) * 256 * 256 * 256) )
            print usage, 'Watt Seconds ',
            print 'Up Time,',
            upTime = (ord(data['rf_data'][7]) +
                (ord(data['rf_data'][8]) * 256) +
                (ord(data['rf_data'][9]) * 256 * 256) +
                (ord(data['rf_data'][10]) * 256 * 256 * 256) )
            print upTime, 'Seconds'
    elif (clusterId == 0xf0):
        clusterCmd = ord(data['rf_data'][2])
        print "Cluster Cmd:", hex(clusterCmd),
        if (clusterCmd == 0xfb):
            print "Temperature ??"
        else:
            print "Unimplemented"
    elif (clusterId == 0xf6):
        clusterCmd = ord(data['rf_data'][2])
        if (clusterCmd == 0xfd):
            print "RSSI value:", ord(data['rf_data'][3])
        elif (clusterCmd == 0xfe):
            print "Version Information"
        else:
            print data['rf_data']
    elif (clusterId == 0xee):
        clusterCmd = ord(data['rf_data'][2])
        if (clusterCmd == 0x80):
            print "Switch is:",
            if (ord(data['rf_data'][3]) & 0x01):
                print "ON"
            else:
                print "OFF"
    else:
        print "Unimplemented Cluster ID", hex(clusterId)
        print

def sendSwitch(whereLong, whereShort, srcEndpoint, destEndpoint, 
                clusterId, profileId, clusterCmd, databytes):
    
    payload = '\x11\x00' + clusterCmd + databytes
    # print 'payload',
    # for c in payload:
        # print hex(ord(c)),
    # print
    # print 'long address:',
    # for c in whereLong:
        # print hex(ord(c)),
    # print
        
    zb.send('tx_explicit',
        dest_addr_long = whereLong,
        dest_addr = whereShort,
        src_endpoint = srcEndpoint,
        dest_endpoint = destEndpoint,
        cluster = clusterId,
        profile = profileId,
        data = payload
        )
    
#------------------If you want to schedule something to happen -----
#scheditem = Scheduler()
#scheditem.start()

#scheditem.add_interval_job(something, seconds=sometime)

#-----------------------------------------------------------------

# Create XBee library API object, which spawns a new thread
zb = ZigBee(ser, callback=messageReceived)

print "started at ", time.strftime("%A, %B, %d at %H:%M:%S")
print "Enter a number from 0 through 8 to send a command"
while True:
    try:
        time.sleep(0.001)
        str1 = raw_input("")
        # Turn Switch Off
        if(str1[0] == '0'):
            print 'Turn switch off'
            databytes1 = '\x01'
            databytesOff = '\x00\x01'
            sendSwitch(switchLongAddr, switchShortAddr, '\x00', '\x02', '\x00\xee', '\xc2\x16', '\x01', databytes1)
            sendSwitch(switchLongAddr, switchShortAddr, '\x00', '\x02', '\x00\xee', '\xc2\x16', '\x02', databytesOff)
        # Turn Switch On
        if(str1[0] == '1'):
            print 'Turn switch on'
            databytes1 = '\x01'
            databytesOn = '\x01\x01'
            sendSwitch(switchLongAddr, switchShortAddr, '\x00', '\x02', '\x00\xee', '\xc2\x16', '\x01', databytes1)
            sendSwitch(switchLongAddr, switchShortAddr, '\x00', '\x02', '\x00\xee', '\xc2\x16', '\x02', databytesOn)
        # this goes down to the test routine for further hacking
        elif (str1[0] == '2'):
            #testCommand()
            print 'Not Implemented'
        # This will get the Version Data, it's a combination of data and text
        elif (str1[0] == '3'):
            print 'Version Data'
            databytes = '\x00\x01'
            sendSwitch(switchLongAddr, switchShortAddr, '\x00', '\x02', '\x00\xf6', '\xc2\x16', '\xfc', databytes)
        # This command causes a message return holding the state of the switch
        elif (str1[0] == '4'):
            print 'Switch Status'
            databytes = '\x01'
            sendSwitch(switchLongAddr, switchShortAddr, '\x00', '\x02', '\x00\xee', '\xc2\x16', '\x01', databytes)
        # restore normal mode after one of the mode changess that follow
        elif (str1[0] == '5'):
            print 'Restore Normal Mode'
            databytes = '\x00\x01'
            sendSwitch(switchLongAddr, switchShortAddr, '\x00', '\x02', '\x00\xf0', '\xc2\x16', '\xfa', databytes)
        # range test - periodic double blink, no control, sends RSSI, no remote control
        # remote control works
        elif (str1[0] == '6'):
            print 'Range Test'
            databytes = '\x01\x01'
            sendSwitch(switchLongAddr, switchShortAddr, '\x00', '\x02', '\x00\xf0', '\xc2\x16', '\xfa', databytes)
        # locked mode - switch can't be controlled locally, no periodic data
        elif (str1[0] == '7'):
            print 'Locked Mode'
            databytes = '\x02\x01'
            sendSwitch(switchLongAddr, switchShortAddr, '\x00', '\x02', '\x00\xf0', '\xc2\x16', '\xfa', databytes)
        # Silent mode, no periodic data, but switch is controllable locally
        elif (str1[0] == '8'):
            print 'Silent Mode'
            databytes = '\x03\x01'
            sendSwitch(switchLongAddr, switchShortAddr, '\x00', '\x02', '\x00\xf0', '\xc2\x16', '\xfa', databytes)
#       else:
#           print 'Unknown Command'
    except IndexError:
        print "empty line"
    except KeyboardInterrupt:
        print "Keyboard interrupt"
        break
    except NameError as e:
        print "NameError:",
        print e.message.split("'")[1]
    except:
        print "Unexpected error:", sys.exc_info()[0]
        break

print "After the while loop"
# halt() must be called before closing the serial
# port in order to ensure proper thread shutdown
zb.halt()
ser.close()

Just like the Arduino code, this will allow a switch to join and then it will constantly update based on messages from the switch.  Here's some sample output from a run of this code:

Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xf0 Cluster Cmd: 0xfb Temperature ??
Cluster ID: 0xef Minute Stats: Usage,  60285 Watt Seconds  Up Time, 1200 Seconds
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xf0 Cluster Cmd: 0xfb Temperature ??
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xf0 Cluster Cmd: 0xfb Temperature ??
Cluster ID: 0xef Minute Stats: Usage,  65266 Watt Seconds  Up Time, 1260 Seconds
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xf0 Cluster Cmd: 0xfb Temperature ??
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 84
Cluster ID: 0xf0 Cluster Cmd: 0xfb Temperature ??
Cluster ID: 0xef Minute Stats: Usage,  70250 Watt Seconds  Up Time, 1320 Seconds
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xf0 Cluster Cmd: 0xfb Temperature ??
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xf0 Cluster Cmd: 0xfb Temperature ??
Cluster ID: 0xef Minute Stats: Usage,  75230 Watt Seconds  Up Time, 1380 Seconds
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xf0 Cluster Cmd: 0xfb Temperature ??
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xf0 Cluster Cmd: 0xfb Temperature ??
Cluster ID: 0xef Minute Stats: Usage,  80213 Watt Seconds  Up Time, 1440 Seconds
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xf0 Cluster Cmd: 0xfb Temperature ??
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xf0 Cluster Cmd: 0xfb Temperature ??
Cluster ID: 0xef Minute Stats: Usage,  85194 Watt Seconds  Up Time, 1500 Seconds
Cluster ID: 0xef Instantaneous Power 84
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xf0 Cluster Cmd: 0xfb Temperature ??
Cluster ID: 0xef Instantaneous Power 83
Cluster ID: 0xef Instantaneous Power 83

I had a little light hooked up to it that has two 40W incandescent bulbs in it so there was something to show.

Now I have the basics of reading the switch, and all I have to do now is hook it up with the rest of the software in the House Controller.  Then I can place these things wherever I want either, control of the power, or a measurement of how much power is being used.  Very nice little switch; I couldn't have built one for the price off the shelf at Lowe's.  And most importantly to me, I have control of it, not some cloud server or control device that I have to rely on a corporation's whim to change to fit my needs.

Have fun.