Thursday, January 16, 2014

Arduino and the Iris Zigbee switch

A friend of mine is looking for a way to control a light remotely.  His problem, and mine also, is that these darn things are expensive and require a controller.  He specifically wanted something that used the Zigbee protocol because they are capable of being controlled by an XBee device.  He pointed me to the Iris line at Lowe's.  Being eaten up with curiosity, I went to Lowe's and looked at the devices.

They have an entire line of devices for lights, doors, garage, etc.  The problem I saw was that, once again, you're stuck with their controller that you can't change, their website that will probably go down at the least useful time (and has a number of times), and a monthly charge that they can raise any time they want to.  I even prowled through their terms of service (yuck) and it looks to me like they can use the data for anything they want to.  Also, they can change their terms of service at any time, leaving your data to their use.  I hate that crap.  Here we go, buy their stuff and then are subject to whatever they want to do over the years.  Why don't they just sell us the darn switches, publish a reasonable API that we can use, and let us live our lives outside their monthly charges and control?

What's needed here is for someone to figure out their switches, make them work with a little computer of some kind, and put how they did it on the web for the entire world to play with.  That'll show them.

Welcome to my work hooking an Arduino to an XBee and controlling an Iris light switch remotely.

Edit: But before you go and implement this, take a look at my second post on this experiment, there are some things to avoid <link>.

First, I chose their Iris Smart Plug <link> because it looks cool, can be tested without installing it into the wall, and measures the power going through it.  Does this sound like my perfect device or what?  I can use one of these to measure power anywhere in the house and have it report to my Raspberry Pi where I can forward it to a cloud server (or three, or four) for examination over time.  This little device is right down my alley.  Now, all I have to do is make it work ... right ?




I could have bought their controller and decoded the interaction with a sniffer and proceeded to duplicate it on my Pi, but there were some problems with this idea:  I don't have a spare Pi right now, the interaction is encrypted, I don't have a sniffer; what the heck am I going to do with this $30 paperweight?  Off to the web I go.

I only found one, yes one, place where anyone had any sort of success hacking this device.  Over at Jeelabs a contributor, CapnBry, had managed to make it work using code on a Windows PC <link>, but his description of how it worked read like classic Greek; totally out of my league.  Try as I might, there just wasn't anyplace else that turned up with something more comprehensible to me.  I had to just bite the bullet and start trying to talk to the switch.  After all, I've worked with XBees for years; how hard can it be?

At this point, you're probably thinking that this is just another post about how I tried to make it work and gave up because I just couldn't get enough information, didn't have the time, or the hardware didn't live up to expectations.  Well, not so; I have the working switch being remotely controlled by an Arduino setting right over there.  And yes, I'm going to tell you how I did it, and provide the code so you can repeat the experiment.  Hopefully, you'll expand on my efforts and let me know about it so we can all benefit and move along.

Like I said earlier, I wanted to put this on a Raspberry Pi, but I didn't have a spare one to experiment with, so I got an Arduino and XBee out of my parts bin, slapped them together, and programmed the XBee as a controller.  This is where I ran into my first obstacle.  How to set up the XBee?  First, you have to use a Series 2 XBee or better; none of this will work on a Series 1 XBee (now do you understand why I chose series 2)?  The notable items in the setup of the XBee are:

ZigBee Stack Profile 2
Encryption Enable 1
Encryption Options 1
API Enable 2
API Output Mode 3
XBee Modem XB24-ZB, ZIGBEE Coordinator API, Version 21A7 (or better)

And, Encryption Key set to something that you can remember.  You cannot read this register after you set it, so put in something you can't forget if you need it later.  Once set, I haven't needed it since, but you never know.

All the parameters can be set using XCTU and it is relatively easy to set up for this once you know what you're doing.  The other parameters can be matched to whatever you're used to using.  Don't think this came easily!  It took me almost a full day of messing around to get it working at all, so if you have trouble, double check everything.

Next, I wanted to use Andrew Rapp's XBee library for the Arduino, but he didn't put in support for the special messages needed to communicate with a ZigBee device.  Specifically there are two messages that are used (almost) exclusively for ZigBee communications: Explicit Addressing ZigBee Command Frame 0x11 and ZigBee Explicit Rx Indicator 0x91; these are not supported by Andrew's library.  However, the library is too nice to allow something like that to stop me, so I extended the library to support these two messages and added support to the ZBTxStatusResponse to be able to get the frame ID back (he missed that little thing).  These changes allowed me to use the library and all its features to speed up the hack.

OK, armed with a library specially modified to work with ZigBee devices and an XBee that should be able to talk to them, I put some code together to monitor traffic.  I immediately got traffic from the switch.  There was a series of messages that I couldn't understand and a lot of bytes to figure out what they meant.  Back to the link above where the guy stated that he had made it work.  The problem was with language.  He said things like, "You: (Endpoint=0x02, Profile=0xc216, Cluster=0x00f0) FrameControl=0x19 ClusterCmd=0xfa data=0x00 0x01"  What is an Endpoint?  A Profile?  These things were totally foreign and strange.  So I hunted down the ZigBee specification <link> and it was HUGE and filled with jargon specific to the protocol that made reading it an exercise in learning to speak ancient Sanskrit.  I also found an Endpoint document that talked about the interaction of devices during a process called 'Joining' <link>.  After reading a significant portion of these I started to understand.  None of the web sites I visited actually described what most of this stuff was, but it boils down to this:

There's a device that supports ZigBee as an end point.  It's things like light switches, door locks, devices that actually do something; these are called ZigBee Device Objects.  There's things that control these devices, they're called servers.  Each device has profiles, these profiles are code that are specific to the device.  Each profile has clusters; these clusters are where the code to do something is hooked.  So, you'll send a message to a device, profile something, cluster something, with some data about what you want to do.  Add to this the fact that each device has a 64 bit address, a 16 bit address, and needs special formatting to the message and the task becomes a bit daunting ... a whole lot daunting.


After prowling around documentation for hours I started to get a glimmer of what was going on and I finally found a key to these things that was way down in the XBee user's guide.  Round about page 122 the Digi folk talk about how to send and receive messages to a ZigBee device.  That was the key that got me going.  Now that I understood a little more than half of what the guy CapnBry was talking about, I started deconstructing the messages from the switch and looking at what was going on.


The switch sends a message announcing that it exists, then it sends another message that tells some stuff about what it can do.  These messages come after the hardware itself gets set up.  There are messages (we don't have to worry about) that take place just to get the XBee coordinator to recognize it.  Then the little device sends another message specifically from the hardware.  See, the ZigBee protocol is general purpose and has support for devices that haven't been invented yet, but the manufacturers ignore that and roll their own stuff under the 'Manufacturer Specific' provisions of the specification.  That means that even if you support the Zigbee protocol, it won't work with the various devices because they hide everything under the special provisions ... jerks.  So, you have to fiddle with things to get them to work.  The manufacturer AlertMe is notable for this tactic, and AlertMe manufactures the devices that Lowe's sells.  


So, these three messages come out of the switch and it's your responsibility to respond correctly to them and get the device to recognize your code as a valid controller; that's what meant by 'Joining'.  What happens is that the switch has a hardware 64 bit address and randomly chooses a 16 bit address to send the messages with.  If it doesn't get a proper response, it steps to another channel and tries the same thing again.  It does this for quite a while before it give up and just shuts down.  So you watch the messages, it stops a while and the messages start again.  Eventually it just give up all together.  Each time you see the set of three messages, it will have a different 16 bit address, so you have to save this address to respond to so that it will listen.  If you're too slow, it won't pay attention because it has already changed the address it pays attention to.


The sequence is documented in the code below, but basically, you wait for the first two messages to come in then respond to both of them.  Then, you interact with the device and it will join with your homemade controller.  From that point on, it will report the power usage every three seconds with a summary every minute.  There's other stuff that is sent by the switch, but I wasn't interested enough in it to bother decoding it; consider those items an exercise for the student.


Once you get it working, you'll find out how nice this switch is.  It monitors the power and reports it every three seconds or so.  It latches the state of the switch such that if the power fails, it comes back in the same state it was in when the power failed.  The little light on it doesn't follow properly, but that can be controlled with software.  It reports a state change back.  That means that if I walk over and push the button, it will send a message that the light has been changed.  You can ask the switch the state of the light and it will answer back to you.  So you can check to see if the outside lights were left on.  This switch is actually pretty nice.


But enough of the bragging.  Here's the code, but remember, this is an example of how to do it.  It isn't an example of coding style, proper formatting, or even the right way to do it.  It's the actual code I used to figure out how the switch works. It will compile using the Arduino IDE 1.0.5 and needs the special modifications to the XBee library I added to support the Zigbee specific messages.  Just let me know if you need the changes and I'll put them somewhere you can grab them.  It also needs the latest SoftwareSerial library because I use software pins to connect to the XBee and the console to monitor and send commands.


The Arduino Sketch
/* This is an examination of Zigbee device communication using an XBee Specifically using the Lowe's Iris switch. This device plugs into an outlet and has a plug on the front for your appliance. It controls the on/off of the appliance and measures the power usage as well. It's a lot like a remote control Kill-a-Watt. */ #include <XBee.h> #include <SoftwareSerial.h> XBee xbee = XBee(); XBeeResponse response = XBeeResponse(); // create response and command objects we expect to handle ZBExpRxResponse rx = ZBExpRxResponse(); XBeeAddress64 switchLongAddress; uint16_t switchShortAddress; uint16_t myFrameId=1; // for debugging, it's nice to know which messages is being handled // Define NewSoftSerial TX/RX pins // Connect Arduino pin 2 to Tx and 3 to Rx of the XBee // I know this sounds backwards, but remember that output // from the Arduino is input to the Xbee #define ssRX 2 #define ssTX 3 SoftwareSerial nss(ssRX, ssTX); void setup() { // start serial Serial.begin(9600); // and the software serial port nss.begin(9600); // now that they are started, hook the XBee into // Software Serial xbee.setSerial(nss); Serial.println("started"); } void loop() { // doing the read without a timer makes it non-blocking, so // you can do other stuff in loop() as well. Things like // looking at the console for something to turn the switch on // or off (see waaay down below) xbee.readPacket(); // so the read above will set the available up to // work when you check it. if (xbee.getResponse().isAvailable()) { // got something Serial.println(); Serial.print("Frame Type is "); // Andrew called the XBee frame type ApiId, it's the first byte // of the frame specific data in the packet. Serial.println(xbee.getResponse().getApiId(), HEX); // // All ZigBee device interaction is handled by the two XBee message type // ZB_EXPLICIT_RX_RESPONSE (ZigBee Explicit Rx Indicator Type 91) // ZB_EXPLICIT_TX_REQUEST (Explicit Addressing ZigBee Command Frame Type 11) // This test code only uses these and the Transmit Status message // if (xbee.getResponse().getApiId() == ZB_EXPLICIT_RX_RESPONSE) { // now that you know it's a Zigbee receive packet // fill in the values xbee.getResponse().getZBExpRxResponse(rx); // get the 64 bit address out of the incoming packet so you know // which device it came from Serial.print("Got a Zigbee explicit packet from: "); XBeeAddress64 senderLongAddress = rx.getRemoteAddress64(); print32Bits(senderLongAddress.getMsb()); Serial.print(" "); print32Bits(senderLongAddress.getLsb()); // this is how to get the sender's // 16 bit address and show it uint16_t senderShortAddress = rx.getRemoteAddress16(); Serial.print(" ("); print16Bits(senderShortAddress); Serial.println(")"); // for right now, since I'm only working with one switch // save the addresses globally for the entire test module switchLongAddress = rx.getRemoteAddress64(); switchShortAddress = rx.getRemoteAddress16(); //Serial.print("checksum is 0x"); //Serial.println(rx.getChecksum(), HEX); // this is the frame length //Serial.print("frame data length is "); int frameDataLength = rx.getFrameDataLength(); //Serial.println(frameDataLength, DEC); uint8_t* frameData = rx.getFrameData(); // display everything after first 10 bytes // this is the Zigbee data after the XBee supplied addresses Serial.println("Zigbee Specific Data from Device: "); for (int i = 10; i < frameDataLength; i++) { print8Bits(frameData[i]); Serial.print(" "); } Serial.println(); // get the source endpoint Serial.print("Source Endpoint: "); print8Bits(rx.getSrcEndpoint()); Serial.println(); // byte 1 is the destination endpoint Serial.print("Destination Endpoint: "); print8Bits(rx.getDestEndpoint()); Serial.println(); // bytes 2 and 3 are the cluster id // a cluster id of 0x13 is the device announce message Serial.print("Cluster ID: "); uint16_t clusterId = (rx.getClusterId()); print16Bits(clusterId); Serial.println(); // bytes 4 and 5 are the profile id Serial.print("Profile ID: "); print16Bits(rx.getProfileId()); Serial.println(); // byte 6 is the receive options Serial.print("Receive Options: "); print8Bits(rx.getRxOptions()); Serial.println(); Serial.print("Length of RF Data: "); Serial.print(rx.getRFDataLength()); Serial.println(); Serial.print("RF Data Received: "); for(int i=0; i < rx.getRFDataLength(); i++){ print8Bits(rx.getRFData()[i]); Serial.print(' '); } Serial.println(); // // I have the message and it's from a ZigBee device // so I have to deal with things like cluster ID, Profile ID // and the other strangely named fields that these devices use // for information and control // if (clusterId == 0x13){ Serial.println("*** Device Announce Message"); // In the announce message: // the next bytes are a 16 bit address and a 64 bit address (10) bytes // that are sent 'little endian' which means backwards such // that the most significant byte is last. // then the capabilities byte of the actual device, but // we don't need some of them because the XBee does most of the work // for us. // // so save the long and short addresses switchLongAddress = rx.getRemoteAddress64(); switchShortAddress = rx.getRemoteAddress16(); // the data carried by the Device Announce Zigbee messaage is 18 bytes over // 2 for src & dest endpoints, 4 for cluster and profile ID, // receive options 1, sequence number 1, short address 2, // long address 8 ... after that is the data specific to // this Zigbee message Serial.print("Sequence Number: "); print8Bits(rx.getRFData()[0]); Serial.println(); Serial.print("Device Capabilities: "); print8Bits(rx.getRFData()[11]); Serial.println(); } if (clusterId == 0x8005){ // Active endpoint response Serial.println("*** Active Endpoint Response"); // You should get a transmit responnse packet back from the // XBee first, this will tell you the other end received // something. // Then, an Active Endpoint Response from the end device // which will be Source Endpoint 0, Dest Endpoint 0, // Cluster ID 8005, Profile 0 // it will have a payload, but the format returned by the // Iris switch doesn't match the specifications. // // Also, I tried responding to this message directly after // its receipt, but that didn't work. When I moved the // response to follow the receipt of the Match Descriptor // Request, it started working. So look below for where I // send the response } if (clusterId == 0x0006){ // Match descriptor request Serial.println("*** Match Descriptor Request"); // This is where I send the Active Endpoint Request // which is endpoint 0x00, profile (0), cluster 0x0005 uint8_t payload1[] = {0,0}; ZBExpCommand tx = ZBExpCommand(switchLongAddress, switchShortAddress, 0, //src endpoint 0, //dest endpoint 0x0005, //cluster ID 0x0000, //profile ID 0, //broadcast radius 0x00, //option payload1, //payload sizeof(payload1), //payload length myFrameId++); // frame ID xbee.send(tx); Serial.println(); Serial.print("sent active endpoint request frame ID: "); Serial.println(myFrameId-1); // // So, send the next message, Match Descriptor Response, // cluster ID 0x8006, profile 0x0000, src and dest endpoints // 0x0000; there's also a payload byte // // {00.02} gave clicks uint8_t payload2[] = {0x00,0x00,0x00,0x00,0x01,02}; tx = ZBExpCommand(switchLongAddress, switchShortAddress, 0, //src endpoint 0, //dest endpoint 0x8006, //cluster ID 0x0000, //profile ID 0, //broadcast radius 0x00, //option payload2, //payload sizeof(payload2), //payload length myFrameId++); // frame ID xbee.send(tx); Serial.println(); Serial.print("sent Match Descriptor Response frame ID: "); Serial.println(myFrameId-1); // // Odd hardware message #1. The next two messages are related // to control of the hardware. The Iris device won't join with // the coordinator without both of these messages // uint8_t payload3[] = {0x11,0x01,0x01}; tx = ZBExpCommand(switchLongAddress, switchShortAddress, 0, //src endpoint 2, //dest endpoint 0x00f6, //cluster ID 0xc216, //profile ID 0, //broadcast radius 0x00, //option payload3, //payload sizeof(payload3), //payload length myFrameId++); // frame ID xbee.send(tx); Serial.println(); Serial.print("sent funny hardware message #1 frame ID: "); Serial.println(myFrameId-1); // // Odd hardware message #2 // uint8_t payload4[] = {0x19,0x01,0xfa,0x00,0x01}; tx = ZBExpCommand(switchLongAddress, switchShortAddress, 0, //src endpoint 2, //dest endpoint 0x00f0, //cluster ID 0xc216, //profile ID 0, //broadcast radius 0x00, //option payload4, //payload sizeof(payload4), //payload length myFrameId++); // frame ID xbee.send(tx); Serial.println(); Serial.print("sent funny hardware message #2 frame ID: "); Serial.println(myFrameId-1); } else if (clusterId == 0xf6){ // This is something specific to the Endpoint devices // and I haven't been able to find documentation on it // anywhere Serial.println("*** Cluster ID 0xf6"); } if (clusterId == 0x00ef){ // // This is a power report, there are two kinds, instant and summary // Serial.print("*** Power Data, "); // The first byte is what Digi calls 'Frame Control' // The second is 'Transaction Sequence Number' // The third is 'Command ID' if (rx.getRFData()[2] == 0x81){ // this is the place where instant power is sent // but it's sent 'little endian' meaning backwards int power = rx.getRFData()[3] + (rx.getRFData()[4] << 8); Serial.print("Instantaneous Power is: "); Serial.println(power); } else if (rx.getRFData()[2] == 0x82){ unsigned long minuteStat = (uint32_t)rx.getRFData()[3] + ((uint32_t)rx.getRFData()[4] << 8) + ((uint32_t)rx.getRFData()[5] << 16) + ((uint32_t)rx.getRFData()[6] << 24); unsigned long uptime = (uint32_t)rx.getRFData()[7] + ((uint32_t)rx.getRFData()[8] << 8) + ((uint32_t)rx.getRFData()[9] << 16) + ((uint32_t)rx.getRFData()[10] << 24); int resetInd = rx.getRFData()[11]; Serial.print("Minute Stat: "); Serial.print(minuteStat); Serial.print(" watt seconds, Uptime: "); Serial.print(uptime); Serial.print(" seconds, Reset Ind: "); Serial.println(resetInd); } } if (clusterId == 0x00ee){ // // This is where the current status of the switch is reported // // If the 'cluster command' is 80, then it's a report, there // are other cluster commands, but they are controls to change // the switch. I'm only checking the low order bit of the first // byte; I don't know what the other bits are yet. if (rx.getRFData()[2] == 0x80){ if (rx.getRFData()[3] & 0x01) Serial.println("Light switched on"); else Serial.println("Light switched off"); } } } else if (xbee.getResponse().getApiId() == ZB_TX_STATUS_RESPONSE) { ZBTxStatusResponse txStatus; xbee.getResponse().getZBTxStatusResponse(txStatus); Serial.print("Status Response: "); Serial.println(txStatus.getDeliveryStatus(), HEX); Serial.print("To Frame ID: "); Serial.println(txStatus.getFrameId()); } else { Serial.print("Got frame type: "); Serial.println(xbee.getResponse().getApiId(), HEX); } } else if (xbee.getResponse().isError()) { // some kind of error happened, I put the stars in so // it could easily be found Serial.print("************************************* error code:"); Serial.println(xbee.getResponse().getErrorCode(),DEC); } else { // I hate else statements that don't have some kind // ending. This is where you handle other things } if (Serial.available() > 0) { char incomingByte; incomingByte = Serial.read(); Serial.println(atoi(&incomingByte), DEC); if (atoi(&incomingByte) == 0){ // turn the light off lightSet(0); } else if (atoi(&incomingByte) == 1){ // turn the light on lightSet(1); } } } void lightSet(int val){ uint8_t payload1[] = {0x11,0x00,0x01,03}; uint8_t payload2[] = {0x11,0x00,0x02,0x00,0x01}; if (val==0){ Serial.println("Light Off"); } else { Serial.println("Light On"); payload2[3] = 0x01; } ZBExpCommand tx = ZBExpCommand(switchLongAddress, switchShortAddress, 0, //src endpoint 2, //dest endpoint 0x00ee, //cluster ID 0xc216, //profile ID 0, //broadcast radius 0x00, //option payload1, //payload sizeof(payload1), //payload length myFrameId++); // frame ID xbee.send(tx); Serial.println(); Serial.print("sent switch off 1 frame ID: "); Serial.println(myFrameId-1); tx = ZBExpCommand(switchLongAddress, switchShortAddress, 0, //src endpoint 2, //dest endpoint 0x00ee, //cluster ID 0xc216, //profile ID 0, //broadcast radius 0x00, //option payload2, //payload sizeof(payload2), //payload length myFrameId++); // frame ID xbee.send(tx); Serial.println(); Serial.print("sent switch off 2 frame ID: "); Serial.println(myFrameId-1); } // these routines are just to print the data with // leading zeros and allow formatting such that it // will be easy to read. void print32Bits(uint32_t dw){ print16Bits(dw >> 16); print16Bits(dw & 0xFFFF); } void print16Bits(uint16_t w){ print8Bits(w >> 8); print8Bits(w & 0x00FF); } void print8Bits(byte c){ uint8_t nibble = (c >> 4); if (nibble <= 9) Serial.write(nibble + 0x30); else Serial.write(nibble + 0x37); nibble = (uint8_t) (c & 0x0F); if (nibble <= 9) Serial.write(nibble + 0x30); else Serial.write(nibble + 0x37); }

Once you get it running you can turn the switch on by typing a 1 in the input line of the Arduino IDE terminal and clicking send.  A zero will turn the switch off.  That's all I really supported in this version, future work will obviously expand the capabilities.  Also, if you kill the sketch, wait until at least one message has been sent by the switch.  The code above needs the 16 and 64 bit address of the switch to work and I didn't put any provisions in to save it; it has to come from the switch.  Every message from the switch carries the addresses, so just wait for one to come in before trying to send something.  Since this is the very first version of this effort, the switch can sometimes fail to 'join'.  This isn't a problem, just let the two devices interact for about 20 seconds or so, unplug the switch and plug it back in.  It'll take off and work.

Edit: About an hour after I posted this I got a brainstorm and figured out how to get the switch to 'join' reliably.  Now, you can reset the switch by unplugging it, press the button to discharge any caps, plug it in, and then press the switch 8 times within about 8 seconds.  The switch will start all over in its interaction, and then start sending power readings.  When (notice I didn't say 'if') I get another one, I'll have to modify this code to support two devices, but one works fine.  The code box above has been updated to hold the latest.

Here's the output from the Arduino from first start up after joining.  I turn the switch on and off during the session.  Notice that the power usage is 83 (two little bulbs in a lamp) and that the switch is constantly sending its status over the network.  There's an extra piece of debugging in this; I print all the bytes sent to the XBee, so the lines that begin with the 7E are lines that are actually being sent to the switch.

started

Frame Type is 91
Got a Zigbee explicit packet from: 000D6F00 0237B25A (A6C4)
Source Endpoint: 02
Destination Endpoint: 02
Cluster ID: 00EF
Profile ID: C216
Length of RF Data: 5
RF Data Received: 09 00 81 53 00 
Power Data, Instantaneous Power is: 83

Frame Type is 91
Got a Zigbee explicit packet from: 000D6F00 0237B25A (A6C4)
Source Endpoint: 02
Destination Endpoint: 02
Cluster ID: 00F0
Profile ID: C216
Length of RF Data: 16
RF Data Received: 09 00 FB 1C 26 25 DA 03 4A 32 00 00 CB EA 01 00 
0
Light Off
7E 0 18 11 1 0 D 6F 0 2 37 B2 5A A6 C4 0 2 0 EE C2 16 0 0 11 0 1 3 E5 
sent switch off 1 frame ID: 1
7E 0 19 11 2 0 D 6F 0 2 37 B2 5A A6 C4 0 2 0 EE C2 16 0 0 11 0 2 0 1 E5 
sent switch off 2 frame ID: 2

Frame Type is 8B
Status Response: 0
To Frame ID: 2

Frame Type is 91
Got a Zigbee explicit packet from: 000D6F00 0237B25A (A6C4)
Source Endpoint: 02
Destination Endpoint: 02
Cluster ID: 00EE
Profile ID: C216
Length of RF Data: 5
RF Data Received: 09 70 80 06 E0 
Light switched off

Frame Type is 91
Got a Zigbee explicit packet from: 000D6F00 0237B25A (A6C4)
Source Endpoint: 02
Destination Endpoint: 02
Cluster ID: 00EF
Profile ID: C216
Length of RF Data: 12
RF Data Received: 09 00 82 A4 0D 00 00 90 F6 00 00 00 
Power Data, Minute Stat: 3492 watt seconds, Uptime: 63120 seconds, Reset Ind: 0

Frame Type is 91
Got a Zigbee explicit packet from: 000D6F00 0237B25A (A6C4)
Source Endpoint: 02
Destination Endpoint: 02
Cluster ID: 00EF
Profile ID: C216
Length of RF Data: 5
RF Data Received: 09 00 81 50 00 
Power Data, Instantaneous Power is: 80

Frame Type is 91
Got a Zigbee explicit packet from: 000D6F00 0237B25A (A6C4)
Source Endpoint: 02
Destination Endpoint: 02
Cluster ID: 00EF
Profile ID: C216
Length of RF Data: 5
RF Data Received: 09 00 81 00 00 
Power Data, Instantaneous Power is: 0
1
Light On
7E 0 18 11 3 0 D 6F 0 2 37 B2 5A A6 C4 0 2 0 EE C2 16 0 0 11 0 1 3 E3 
sent switch off 1 frame ID: 3
7E 0 19 11 4 0 D 6F 0 2 37 B2 5A A6 C4 0 2 0 EE C2 16 0 0 11 0 2 1 1 E2 
sent switch off 2 frame ID: 4

Frame Type is 8B
Status Response: 0
To Frame ID: 4

Frame Type is 91
Got a Zigbee explicit packet from: 000D6F00 0237B25A (A6C4)
Source Endpoint: 02
Destination Endpoint: 02
Cluster ID: 00EE
Profile ID: C216
Length of RF Data: 5
RF Data Received: 09 70 80 07 00 
Light switched on

Frame Type is 91
Got a Zigbee explicit packet from: 000D6F00 0237B25A (A6C4)
Source Endpoint: 02
Destination Endpoint: 02
Cluster ID: 00EF
Profile ID: C216
Length of RF Data: 5
RF Data Received: 09 00 81 53 00 
Power Data, Instantaneous Power is: 83

Frame Type is 91
Got a Zigbee explicit packet from: 000D6F00 0237B25A (A6C4)
Source Endpoint: 02
Destination Endpoint: 02
Cluster ID: 00F0
Profile ID: C216
Length of RF Data: 16
RF Data Received: 09 00 FB 1C 26 9D DA 03 4A 32 00 00 C6 F6 01 00 

Have fun.


31 comments:

  1. I am developing a solution to replace wall switches for light control. It's designed to have a Moteino dropped in for wireless control, perhaps could be adapted for xbee. Thought I'd mention it here for reference or just as an idea, more here: http://lowpowerlab.com/blog/2013/12/24/switchmote-one-step-closer-to-reality/

    ReplyDelete
    Replies
    1. Nice little device you have there. If it had an XBee on it it would be an incredible remote control for around the house. Since XBee has the protocol built in, it could be used for everything a home controller wants. I have a number of other things I could mention, but I'm not sure you'll get back here anytime soon.

      Delete
  2. My device has a fully capable arduino (the Moteino) so it can make decisions and even be autonomous of any central controller. The idea is to independently sync multiple lights together and create scenes (ie turn more lights on/off at the same time from remote locations). I believe that would be a challenge with XBee but I could be wrong. A Xbee version would probably be popular as well so that's something I might consider but need to test the waters with the current version.

    ReplyDelete
    Replies
    1. I understand the problems you're looking at. I use a central controller that receives from various XBees and then makes decisions for the house in general. Each remote device (an XBee equipped arduino) has certain functions that it handles autonomously like temperature control, default timing for a water heater, etc. The overall override capability is under the house controller.

      Using a switch like yours, I would simply send "Scene 1" to the controller and it would turn on whatever is appropriate: stereo to quiet romantic music, lights low, hot tub on, etc.

      My controller is a raspberry pi with an XBee hanging off the serial port which, so far, has handled things really well. This makes your idea of the switch compelling.

      As you progress, think about the various advantages. The XBee can interface to Zigbee devices (I'm slowly proving that), it handles store-forward for extending the network, has a well documented interface, various language interfaces so it can talk to a variety of machines, ... I could go on and on.

      I absolutely hate the idea of being trapped into some corporations idea of a controller and end devices hooked to some cloud server that they control. So, keep at the switch, it could become a very important item in future DIY home automation.

      Delete
    2. Dave's central house controller has proven to be quite a powerful little program. I began incorporating his controller into my home automation project back in early December and the more I work with his code the more powerful I find the system to be. All it took was for me to read through his work with the XBee radios and I was sold on them. I had read quite a bit on them from different places and they all seemed to be a bit too vague on the actual operation of the devices. One site kinda told you how to set them up, another kinda told you how to use them. Dave wrapped it all up in one place and made me them seem simple enough to make the plunge. So much easier that pulling CAT5 cable everywhere and hoping the Ethernet Shield doesn't crash on me.

      Congrats Dave, you made short work of that device. Trick now will be do you integrate it into the house controller or leave it out on the Arduino and control it from there using the house controller? Either way works depending on how many of them you can control form the Arduino....

      Delete
    3. Welllll, I tried to integrate it into my house controller using the same XBee network that is already controlling the house. It not only didn't work, the attempt wiped out my network.

      Insert a really, really heavy sigh right here

      It wasn't a total waste of time though. I discovered something new about the XBees that had slipped by me and I also found out why I blew up the network. But, there doesn't seem to be a way to share a network with non-ZigBee specific messages and messages targeted for a ZigBee device. I'll be checking this out further and I'll post a synopsis of what's going on.

      If I'm right, it can't be combined, I'll be creating a second device to handle the ZigBee switches. These switches are really cool and do everything I want in something like this. Imagine putting one on a refrigerator, you can tell how much power it is using and graph usage over a few days. The device probably won't be an Arduino though, since I need to save the addresses and the network could get extensive over time, it looks like a Raspberry Pi would be a good solution.

      Any input is welcome.

      Delete
  3. Thanks for all your hard work! After reading this yesterday I ran to Lowes last night to look for an Iris light switch and -almost- all of the Iris products I saw (light switches, outlets, etc) said zwave specifically and are GE brand. I did notice the same outlet you are using here and it doesn't specifically specify protocol. So is Iris switching to zwave or what are the chances these GE Iris "zwave" light switches and outlets will work using your method? Thanks alot!

    ReplyDelete
  4. Zwave and ZigBee are different things and one won't work with the other. The way they do it is to have a Zwave controller as well as a ZigBee controller in the same box. So, NO, I can't control a Zwave switch with my code.

    It does appear that Iris is switching to Zwave though. I seem to remember several devices in their line being ZigBee and I can't find them on their web page anymore. Their little window sensors and a couple of other items seem to be ZigBee, but not the cool wall switches and outlets.

    ReplyDelete
  5. Dave,

    I just wanted to say I got the Iris switch on and off a light with your code. I must of missed the software serial at first, so that through me for a loop. But once I noticed that obvious detail, boom! working perfectly. Thanks for the hard work. I have been reading this blog for some time and waiting for the day to have a house and start automating it. Also look into MQTT :)

    ReplyDelete
  6. Have you had success with any manufactures other than Alertme? I was thinking of the orbit irrigation timer as a project. It seems to be different in that it only sends a device announce (13) and no others.

    ReplyDelete
    Replies
    1. Actually, no. My experience with ZigBee in general has been a real turn off for the protocol. What started off as a really good idea has seemed to flounder with all the manufacturers opting for 'special provisions' to try and capture some portion of the marketplace. When I start working with sprinklers, I'll go the old fashioned route. I'll set up an arduino with an XBee hooked to it and a set of relays controlling regular ol' sprinkler valves.

      I can buy all the parts ready made from web suppliers without having to worry about protocols, and my house controller can easily send commands to the sprinklers and even sample moisture sensors if I want to go that far with it.

      But, if you want to experiment, just grab the code above and play with it a while. Several folk have used the code to examine devices.

      Delete
    2. I understand your irritation with the protocol. Like all good things that could be great, it is monetized and hijacked for profit. I appreciate your response and hope you have fun with your next project.

      Delete
    3. The ZWave devices are actually very easy to use. I added a Razberry board to my RPi and have been having a blast with the ZWave stuff. Rebuilding my RPi at the moment due to (I believe) data corruption due to using a microSD in an adapter...

      Delete
  7. Dave, how did you figure out the two odd hardware messages that were required to join, but you did not know what they did. How did you know to send them?

    ReplyDelete
    Replies
    1. Remember up above in the narrative I mentioned a guy named CapnBry? He made it work first, but it took me days to understand what he was saying. That's where I got the idea for the two messages, and from there I poked around until I got it working. I asked CapnBry the same thing and he said he used a special sniffer and a complete system to map out the messages. He saved me having to do that part.

      Delete
  8. Can anyone help me convert an iris smart plug 120v into a 220v/240v 50hz for powering an split ac running at 850-900 watts?

    ReplyDelete
    Replies
    1. Somewhere on this blog I have a picture of the switch when I opened one up to look inside. There you will see a relay. The relay is rated for 15A at 240V, so it should be able to handle the current. The problem is that whether or not the electronics can handle multiple voltage levels is unknown.

      You can always get a power adapter and run it at 120, then close a relay with the switch that controls the A/C.

      Maybe if you take a close look at the power supply in the switch you can tell if it handles multiple voltages, a lot of them do.

      Delete
    2. hey, if you want I can ship one of these to you:
      http://www.lumiere.co.za/custpics/0/38/133/adhoco-c1-product-description.pdf

      Delete
  9. I would like the "the special modifications to the XBee library". Could you please put them somewhere I can "grab them".

    Thanks,

    Mark

    ReplyDelete
    Replies
    1. It's in GitHub under https://github.com/draythomp/Desert-Home-Arduino

      Look in the libraries directory.

      Delete
  10. Dear Desert Home,
    I have read your blog with interest. As I did use E-inzicht which resembles your Iris Zigbee switch closely. But in ocotober last year the utility firm decided to terminate the project ( http://members.ziggo.nl/olav.buunen/energie/einzicht.htm ) so now I am left with 4 E-inzicht plugs with the only functionality the physical switch. Although I asked the firm for alternative support they could not give any information about that.
    My question is could I use your setup to get data and get the long distance switching functionality back.
    Thank you for your efforts, Frank

    ReplyDelete
    Replies
    1. Those look a LOT like the AlertMe wall outlets for Europe. Of course I'm not certain, but it looks like it is worth a try.

      Delete
  11. Hi, I'm a beginner to play zigbee, I have a zigbee smart-plug and a Digi Xbee connect to my adurino uno, I find some example code in this book "Building_Wireless_Sensor_Networks_Using_Arduino" and successful to control on/off of the smart-plug, but I don't know how to get the state of smart-plug, and the meter of smart-plug. I try your code with the latest XBee.h from "andrewrapp" but got some error "'ZBExpRxResponse' does not name a type" and "ZBExpCommand does not name a type".
    Can you update the code or point me how to fix these error?

    Thanks
    Eric

    ReplyDelete
    Replies
    1. I haven't looked at the latest header files at all, but it sounds like you need to prowl through them a bit to see which names changed from my code. This is just a compiler error.

      Delete
  12. I'm getting the same compiling error "ZBExpRxResponse' does not name a type" did you find what the changed name is or whythis error is appearing?

    ReplyDelete
  13. Same issue: I'm getting the same compiling error "ZBExpRxResponse' does not name a type". I started looking at the code. Looks like there are several class name changes and possible some architecture changes. I plan to see if I can get it working, but it will take looking at the old and new code to figure it out.

    ReplyDelete
  14. Wow, got it. The issue is that if you install the library via Arduino, you are getting the code from andrewrapp: https://github.com/andrewrapp/xbee-arduino. But the examples from Desert Home are using the XBEE library from https://github.com/draythomp/Desert-Home-Arduino/tree/master/libraries/XBee. They are similar, but quite different.

    If you want to install the DH library instead of the one "built in"to the Arduino libraries tool, you can follow this guide https://www.arduino.cc/en/Guide/Libraries to download the compressed zip from github and put the library folder in the right place.

    You will want to either remove the one you installed or install another copy of the Arduino software.

    ReplyDelete
  15. I tested this theory and was able to compile https://gist.github.com/bgentry/6e4f7840b22c9743640ca38ade6a844a with only the expected changes related to Serial ports and only having 1 on the Uno. I haven't actually run the code yet.

    ReplyDelete
  16. You are very gifted in your abilities to crack these Iris products from Lowes. I see code published on gethub and was curious if it was possible to get any of it to work with Smartthings ? I think all of this is completely fantastic what you have been able to accomplish with these Iris devices.

    ReplyDelete