Playing around with the Philips Hue SDK for Android

Rainbows
After having seen a friend's Hue installation I decided that I'd be interested in some of these little devices myself. The idea of being able to schedule when my lights turn on or perhaps get even more advanced with my configuration would be definitely interesting.

The developers at Philips have taken an awesome approach and published the API for these lights, which means we have the opportunity to do whatever we want with these lights. Aside from just publishing how the API works they also have an iOS and Android SDK.

Eager to work on an Android app again I grabbed all the relevant pieces and started working on new project. If you are a native to Android development you might find the SDK a little bit weird to work with! The SDK in question has definitely been a direct port from the iOS SDK, which makes some things look a little weird. The API is also very callback heavy, which can make learning it at first a little bit weird.

public class BridgeSearcher implements PHSDKListener {
    private PHHueSDK sdk;
    public BridgeSearcher() {
        sdk = PHHueSDK.create();
        sdk.setDeviceName("Bridge Searcher");
        sdk.getNotificationManager()
            .registerSDKListener(this);
        PHBridgeSearchManager manager =
            (PHBridgeSearchManager)
            sdk.getSDKService(PHHueSDK.SEARCH_BRIDGE);
        // Perform uPnP search
        manager.search(true, true);
    }
}

Now I haven't shown the callbacks yet, but this is what you need to do in order to detect all the bridges in your area. In a home you'll probably only ever have one, so you can safely assume that when you successfully detect the bridge you can grab the first (and only) element from the List.

// Still in BridgeSearcher.java -- One of the Callbacks
@Override
public void onAccessPointsFound(List<PHAccessPoint> accessPoints) {
    if(accessPoints == null || accessPoints.size() == 0){
        // Android Logging
        Log.d(
            "BridgeSearcher",
            "For whatever reason we found APs but got null or an empty collection!"
        );
        return;
    }
    PHAccessPoint ap = accessPoints.get(0);
    // Now that we have an access point lets 
    // connect to the bridge!
    ap.setUsername("BridgeSearcher");
    sdk.connect(ap);
}

So we've grabbed our detected access point and set the username. The username is required since that's how authentication works on Hue. It's not really strong or anything, so it's easy to masquerade as other apps. Though this really isn't an issue since there is a step that requires direct user input. Sending that connect attempt will actually fail because my user isn't configured yet. We will find out about that because we'll get a bunch of error callbacks as well as an authentication required callback. Note: Your username needs to be sufficiently long otherwise the Hue SDK will raise an Exception

// Still in BridgeSearcher.java -- Another callback
@Override
public void onAuthenticationRequired(PHAccessPoint ap) {
    sdk.startPushLinkAuthentication(ap);
}

With this you are now waiting for the Hue button on the bridge to be pressed. Once that button is pressed you will have a user account and can change the colours of your lamps and do a bunch of other things too.

// Again still in BridgeSearcher.java -- Final callback of this article!
@Override
public void onBridgeConnected(final PHBridge bridge) {
    // You don't need all the details in order
    // to actually modify a light. Just it's ID.
    // From my observations light IDs start at 1
    final PHLight light = new PHLight("", "1", "", "");
    Thread thread = new Thread(new Runnable(){
        boolean on = true;
        PHLightState state = new PHLightState();
        // Setting to 255 causes an exception to raise :(
        state.setBrightness(254);
        state.setHue(46920); // Make light blue
        state.setOn(true);
        bridge.updateLightState(light, state);
    });    
}

And there you have it, you've found a bridge, gone through the authorization flow and updated one of the lamps. It's a little bit weird, but one of the nice things about this is it's all asynchronous so your code doesn't need to worry about every blocking on the main thread and getting the ANR of death. Though don't forget that these all occur in a separate thread, so be sure to run any UI updating code on the main thread!