Wednesday 8 April 2015

Trying to bring some Awesomation to Insteon

Insteon hub next to Netatmo
weather station
I recently got my hands on an Insteon Hub and plug in mains switch, so I set about integrating them with my Awesomation project.  The aim was to have Insteon devices (switch) controlled by other Awesomation devices (such as a Z Wave or Wemo motion sensors).

Insteon recently launched a cloud based API for their hub, which fits perfectly with Awesomation’s cloud based architecture.  On the face of it, their API is a pretty standard RESTful/JSON OAuth2 cloud API.  As Awesomation already supports both the Nest and Netatmo OAuth2 APIs, it should have been trivial to add another…

To begin with, you’ll need a Client ID and Secret - and no automated forms here like the Nest/Netatmo services.  It’s not so bad though, as once you fill out a form they send you the details a few days later.  But then things start to get a little weird.  Insteon’s OAuth implementation does not have anywhere to register the callback URLs, which as I understand leaves them wide open to covert redirect attacks.  What's more, when getting your token from the auth URL you must not provide a redirect URL; otherwise you get ‘401: Unauthorized’.  I wish they gave better error messages, or mentioned this in the documentation: that would have saved me a few hours of trial and error!

I would also be remiss if I didn’t mention their slightly strange scheme for authenticating each request - you are required to pass the following headers:

Authentication: APIKey example_api_key_135fhn80w35hynainrsg0q824hyn
Authorization: Bearer example_access_135fhn80w35hynainrsg0q824hyn

But at least this is documented (although not in the auth section of the docs!).

Once happily authenticated with the service, it was time to fetch a list of devices.  This was relatively straightforward, but nowhere in the API could I find a way to receive the state of the switch!  Hopefully this is an oversight on my part.

Finally, I wanted to wire up my abstract light switch data model such that my motion sensors could control the lights.  For this you need to use the commands API; you create a command object, and then poll the object until it completes (yuk!).  Initially all I got were stack traces, as I forgot to set my request content-type to ‘application/json’ (interestingly the stack traces indicate their stack is all Microsoft .Net and C#).  After fixing this I couldn’t get any further - every command I created was stuck in the pending state.  Debugging this led me further down the the rabbit hole...

Searching around the net I stumbled on this excellent blog post explaining how the outside world communicates with the Insteon hub - the hub relies on UPnP to open a hole in your firewall, and then tells a central service (running on AWS it seems) the IP address of your house.  Of course I have the one ‘obscure’ router which doesn’t support UPnP - an Apple AirPort Extreme!  I don’t understand why Insteon can’t use a websocket to push commands down to hubs, like any other sane home automation hub I’ve seen (Awesomation included!).  Not only does this punch through home routers more successfully, it requires zero configuration and can be much more secure than opening an unencrypted HTTP port to the outside world!  After mapping the port through my router (see this ‘guide’, not for the faint hearted) I confirmed the outside world could talk to my house by tethering my laptop to my phone and using http://connect.insteon.com, but alas, the commands API still did not work.  I’d note that picking apart Insteon’s basic site indicated they don’t use their own API, but rather connect directly to the router and manipulate it that way.

And this is where I ran out of weekend time, the whole Insteon API leaving a sour taste in my mouth.  The API still very much seems in an alpha state - a weak sign up flow, security problems, poor documentation, stack traces and non-functional commands.  I hope other people have had more success than I, and I welcome someone pointing out the mistakes in my code.  I’ve filed bugs with Insteon and will post a follow up when I get this working, but at this point, I can’t recommend anyone attempts to integrate with this API.