Home Automation Armageddon!

I have a friend who is new to programming and has asked me how I do it. It made me reflect for a minute to think about the patterns I take while learning something new or even completely broken and then get it working. Curious myself now, I decided to document a simple project from start to finish.

I found some relatively inexpensive “WiFi” LED light bulbs online that have an open developer community and documented network protocol. I grabbed a set of bulbs and the WiFI controller off of the internet and then setup the whole getup using the web instructions. After playing with the provided app, I started coming up with harebrained ideas about tricks I could pull using the API. So I started hacking.

Some background on the Mi-Light WiFi

I read the documentation on the product and found some code that used the protocol.

The way the whole system works is a combination of (a cloud service maybe?), the WiFi connector, and radio control of the various lights in your house. Pairing is easiest through the app and flipping lights on and off (with the switch) seems to help when pairing. Once the lights are paired with the WiFi connector, it uses radio to control them.

Network messages to the router are extremely simple, UDP packets sent to the listener on the router are handled and the commands are transmitted over radio to the lights. Btw, I like this protocol, it’s obviously simple and does specifically what you say. It’s no surprise to me that as much code exists out there working against the system.

Here’s the rub. As far as I could tell, the protocol changed between the time that most of the demo apps were made and when I had received my lights. When I tried the code I could find, I encountered issues and needed to diagnose so I started coding my own tests and reverse engineering.

Testing the Network Protocol for the Mi-Light

You need a way to monitor UDP packets and to send UDP packets. My home machine happens to be Windows so I got things rocking with a little WinPCap, Packet Sender, and SmartSniff. The plan is to use the sender to test the network API and then use the sniffer to monitor the responses. This way, I can clear out any potential network / protocol bug issues.

To kick things off, I tested the WiFi discovery query, which is a broadcast (255.255.255.255) UDP send to port 48899 over the network that the WiFi connector is paired with.  I tracked the broadcast packets using SmartSniff and the output looks something like this:

 

The packet of interest is the response from the Mi-Light that includes its IP and MAC addresses. This response contains a tuple with the IP and MAC address of the WiFi connector. At this point I gave myself a little high-five because I now had a relatively simple discovery protocol that could be worked with and I had verified the light system was operational on my network.

Time to try some more fun stuff. A short UDP blast to my WiFi connector on port 8899 was definitely in order. Packets out were:

00000000  42 00 55                                           B.U

And my living room lights turned on, along with all my other lights, soo awesome. Time to try turning them off, I sent the following packets to the server on 192.168.1.174, port 8899:

00000000  41 00 55                                           B.U

Some decoding of the commands:

The first byte (41 or 42) is the command from the documentation, the rest is a packet suffix. For any of the commands, you just need to check the op code table:

	            Hexidecimal (byte)	 Decimal (integer)

RGBW COLOR LED ALL OFF	   0x41	           65

RGBW COLOR LED ALL ON	   0x42	           66

DISCO SPEED SLOWER	   0x43	           67

DISCO SPEED FASTER	   0x44	           68

GROUP 1 ALL ON		   0x45	           69	(SYNC/PAIR RGB+W Bulb within 2 seconds of Wall Switch Power being turned ON)

GROUP 1 ALL OFF		   0x46	           70

GROUP 2 ALL ON		   0x47	           71	(SYNC/PAIR RGB+W Bulb within 2 seconds of Wall Switch Power being turned ON)

GROUP 2 ALL OFF		   0x48	           72

GROUP 3 ALL ON		   0x49	           73	(SYNC/PAIR RGB+W Bulb within 2 seconds of Wall Switch Power being turned ON)

GROUP 3 ALL OFF		   0x4A	           74

GROUP 4 ALL ON		   0x4B	           75	(SYNC/PAIR RGB+W Bulb within 2 seconds of Wall Switch Power being turned ON)

GROUP 4 ALL OFF		   0x4C	           76

DISCO MODE	           0x4D	           77

SET COLOR TO WHITE (GROUP ALL)  0x42    100ms followed by:	0xC2

SET COLOR TO WHITE (GROUP 1)    0x45	100ms followed by:	0xC5

SET COLOR TO WHITE (GROUP 2)    0x47	100ms followed by:	0xC7

SET COLOR TO WHITE (GROUP 3)    0x49	100ms followed by:	0xC9

SET COLOR TO WHITE (GROUP 4)    0x4B	100ms followed by:	0xCB

Darn those set color to white commands!!! At this point, sending the packets in a network tool won’t suffice – but wifi light developer don’t care, this is the right problem to have. At this point, we’ve confirmed the network API works and are ready to code.

The code at this point is a super simple Visual Studio project that is definitely worth keeping around for testing lights during initial setup. I might add a setup command (send group [1..4] n times at y frequency) because this phase for lights is a trick or you can fork it and do that for me.

Crawl, walk, run…

After I have a minimal test with as few software variables as possible (sigh, crawl), I tend to start coding with a reusable template (walk). In this case, sending the messages / receiving broadcast responses is the clear point of interest. After wrapping making API calls, it then makes sense to create meaningful wrappers around API calling. In this way, you can easily refactor the API calls independently from calling the API.

To accomplish this design, I created a second project to be used while build out my utility class / library that will eventually take care of message queuing and performing API calls – all the bits relevant for integrating the lights with software.

The intermediate project used for testing the API wrapper looks something like this:

It’s a boring project, I know. But, this is how it’s supposed to be. The intermediate library is most importantly a bootstrap for a more exciting project that will take full advantage of the functioning library. While developing in an environment where I can’t be sure if anything even works, I try to minimize the variables that can interfere with determining whether the client application code is the issue or it’s the state of the system – a WiFi router and radio rig in this case.

I filled out the methods on the Utility class. These just are bootstrapped by the original starter project that I created. The API calls are abstracted out, the constants for the various supported commands are made internal, and then refactoring happens if the class is getting bloated.

A first pass over the API yields the following structure:

I also whipped together a command prompt and added console colors for flair:

At this point I have a pretty good understanding of how well my library works. Here is the GitHub commit for this change that also has a few fun tests for checking the potential of the API. The following video shows it off:

 

Making it more robust

Using a RESTful API is an easy way to connect more services to the existing UDP service and should make it easier for me to extend to mobile apps or shell scripts. I haven’t started it yet but the final phase (run) is to create a Web API endpoints project with endpoints corresponding to the API calls the controllers will make use of the library I created.

But what about testing? Where is your Test Driven Development hat?

These projects are still throwaway prototypes at this point so I haven’t yet integrated a test framework such as NUnit. Additionally, behavioral testing becomes pretty tough when you’re flipping on and off lights in the house using a fire and forget protocol. Finally, the intermediate project which exercizes the library functions as a full system test. However, physically testing all the commands can make refactoring much less of a chore to put together tests, proper, though so while things are working it’s time to take a step back and protect your code.

If the prototype needs to be iterated, the first thing that I do is refactor based on what I’ve learned while using the library. Before or during the refactor, tests are extremely helpful – if you don’t do this, things get out of control again in terms of variables (are the lights broken or is it my code?) to debug.

Testing starts with the utility library that is moved to a separate project and tested as a separate component. All further development on the library becomes TDD. Subsequent projects that use the library become TDD. Test all the things.

Thoughts on my prototype coding process

I can think of a number of projects that I have worked on where I followed exactly this pattern and I’m wondering at this point if everybody does this when working on similar projects. When I was working on the early Google+ samples, the process was:

  1. Create Quickstart app that tests a single API call – leave as test to confirm configuration
  2. Explore the potential of the API – what are the limits? (JavaScript deferral, fully testing APIs in client)
  3. Write code that takes full advantage of the API (create graphs using connections, use app activities, integrate best practices, and add tests)

Note that this process has worked for me on small projects but on larger projects and even more experimental projects, the process is entirely different. Perhaps worth another post in the future. Testing similar projects could also be worth a few words.