How I’m Using Amazon Dash Buttons for SmartThings

September 21, 2015 | Comments Off

When I first heard about Amazon Dash buttons I knew they’d likely end up being a fun and (arguably1) cheap way to control a few things on my SmartThings network. I’m certainly not the first to accomplish this but I have some insights that might be of interest.

By way of background, Amazon Dash are $5 wifi-enabled buttons that Amazon would like you to use to buy things easily. And surely there are many places that I think they are actually useful as intended. Like wherever you keep your trash bags, since you probably buy the same bags every time, you put a button, when you grab the last bag (or you’re getting low) you push the button and your standard trash bag order is placed. It’s very certainly a “first-world problem” type of thing. To set them up you use a smartphone to configure your wifi credentials2 onto the button and set up your default order. Once configured when the button is pushed it connects to your wifi network and sends a notification to Amazon that the button was pushed.

If you’re going to abuse the button for another purpose, you’ll want to know when the button is pushed, and there are 5 obvious points in the communication lifecycle where you can do this.

  1. Wifi authentication (layer 1?)
  2. ARP requests (layer 2)
  3. DHCP request (layer 3)
  4. DNS request (layer 4)
  5. HTTPS request (layer 4/7)

Each of these has their own advantages and disadvantages, all of which I won’t go into but I’ll try and summarize. ARP (where some previous attempts have been documented), DHCP and Authentication are annoying because they are very low layer, you’re likely going to need to detect the events using packet capture or something even more elaborate for the authentication part. DNS and HTTPS are easier to intercept and the challenge here is that the button will retry unsuccessful attempts so you have to suppress repeat events.

Let me cut to the chase and describe my implementation and after I’ll explore so of the approaches I abandoned. After some trial and error, for my solution I ended up intercepting the communication at the HTTPS point.

First I set up my dash buttons as others have done, configuring them onto my wifi network2, letting them communicate with Amazon and then not selecting a product at Step 3 in the registration process.

I configured the wireless network to assign DHCP normally, and I allow the DNS requests to occur as normal. However all TCP connections from the Dash buttons are redirected (via a Destination NAT rule) to a local server on port 9999 (you can choose your own port). I set up xinetd with a service3 that listens on that port and when a connection is received, start a python script called dashproxy.py3 to handle the request.

xinetd passes in the remote IP via an environment variable REMOTE_HOST. I parse this value for the last octet of the IP and have a simple lookup table to map the IP to a SmartThings switch. The script then invokes the SmartThings API to toggle the switch.

The only wrinkle with this otherwise straightforward setup is the aforementioned problem of retries. The Amazon Dash uses HTTPS and (as far as others reported) seems to expect a certain certificate chain. I work around this by not dealing with HTTPS at all. I’m only handling accepting the connection and then closing the socket. However this causes the button to retry. To workaround this I abuse a feature of xinetd that can limit the connections per IP. I allow only one connection from an IP at a time. In my Python script after I perform the work I close the file descriptors for stdin/stdout/stderr which causes xinetd to close the TCP socket. At this point the dash button will retry to reconnect. However instead of exiting the Python script I issue a sleep for 10 seconds. Because the process hasn’t exited xinetd will reject the retry connections by accepting and closing the sockets without re-invoking the Python script. This effectively means the script is only invoked once per button push and the retry attempts are successfully suppressed by xinetd’s connection limiting.

On the SmartThings side I basically follow what other tutorials have described in setting up a RESTful SmartApp and giving it access to the switches it needs to control. My biggest issue here was figuring out the OAuth and API endpoints. I wasted an embarrassing amount of time flailing on this until I found the section of the docs named “Just the URLs” and that was the piece of information I needed. Here’s the way I ended up doing this.

As a one time process, in a browser I issue the with code request and then the access token request. This gives me the endpoint URL and access token needed to make API requests and then hard code this into the script.

The other API requests the are 1) to get the list of switches to map a switch name to a switch ID (optional) and 2) the API call to toggle the switch. For reference I used this SmartApp for an API.

Other Avenues I pursued and abandoned:

I tried doing this at the DHCP and DNS layers.

For DHCP it was difficult to effectively limit the devices that would have their DHCP redirected to a different port because the only thing you can key on is a MAC address and this isn’t normally exposed by a UDP socket.

I had a working implementation with DNS redirected but the issue was suppressing the retries. It would have been possible to avoid the retries altogether if I could have made a valid DNS response but after a bit of researching with Scapy (which I’m sure could do it) I couldn’t find working examples of how to parse data read from a socket and/or compose a DNS response (though I had something I think would have worked). Lacking that the dash button would retry to resolve but because I couldn’t do the rate limiting trick on UDP (in truth I hadn’t thought of it yet) I switched to the HTTPS interception.

Footnotes

  1. JDRoberts makes an argument about the cost of using these buttons
  2. I actually set up a separate wireless network for the Amazon Dash buttons. For me this made it easier to apply the traffic modifications. Also, be careful about giving Amazon your wifi password.
  3. Here’s the code listings for my dashproxy project

Resources: