Monday, July 25, 2016

Controlling Philips Hue lights with an Amazon Dash button

So I have read around online that people have found a way to hack Amazon Dash buttons. Without doing much research, I jumped on buying a few Amazon Dash buttons for $1 during Amazon Prime Day. Once I got them and started working on hacking them to do what I wanted, I realized things were not as clear-cut ready as I thought it was. But luckily a few people had a great head start and it didn't take much tweaking in order to succeed.


Using a Docker image for my project


I usually use a Docker container for each Home Automation project that I create, and this one is no different. I used the image y0no/python-scapy as my starting point. I created a Bash script setup.sh that would prepare the container with the necessary tools:

    #!/bin/bash

    apt-get --assume-yes install python-pip
    pip install scapy qhue

    echo "Running dashControl.py:"
    python /home/dashControl.py

The Python script dashControl.py will be described below. Python pip is needed in order to install Scapy and Qhue which will be described as well.

Then I have the following script that runs the Docker container, executes the script above and links the /home/ directory of the container to my host directory where I keep all these scripts:

    #!/bin/bash

    /usr/local/bin/docker kill Scapy
    /usr/local/bin/docker rm Scapy
    containerID=$(/usr/local/bin/docker run --name=Scapy -d -ti --privileged --net=host -v /volume2/docker/scapy/:/home/ y0no/python-scapy)
    /usr/local/bin/docker exec $containerID /bin/sh -c "/home/setup.sh"

Setting up the Dash button


The first step involves using the Amazon phone app to add a new Dash device under Your Account. Follow the directions in order to connect the button to your home Wi-Fi, but then exit the app when it asks you what product you want the button to order.

Next we need to determine what the MAC address of the Dash button is. Every time the Dash button is pressed, it announces itself onto the LAN with an ARP probe. We are going to listen for these announcements to use as triggers.

The following Python command is used in order to determine the button's MAC address:

    from scapy.all import *

    def arp_display(pkt):
      global execute, bedroomLight_state
      if pkt[ARP].op == 1: #who-has (request)
            print "ARP Probe from: " + pkt[ARP].hwsrc
    print sniff(prn=arp_display, filter="arp", store=0, count=0)

All of that amazing work is thanks to Ted Benson and his article on medium.com.

Once change you may see from the original script in the link is that I removed the part where it checks for the IP address being 0.0.0.0. I just set it to print out all ARP probes. Based on the timing of when I would press the button, I could determine which one it was. Also note that the count was set to 0 instead of 10, which means the script will indefinitely continue to sniff until you exit.

So once you execute this Python script and press a button on the Dash, you should have it's MAC address.

Python script to control my Hue lights


Now the only part missing was to execute something when the ARP probe is detected. I wanted to use the Dash buttons to control my Philips Hue lights, so I modified the Python script to do just that. 


I found a python script called Qhue on GitHub which I used in order to send the control commands to turn the lights on or off. I followed the instructions on the GitHub page to create the Hue user and also this page to get the Hue Bridge IP Address.

Finally, I came up with the following Python script that worked great:


###########################################################################
import time
from scapy.all import *

# Variables for each Dash button MAC address
bedroom_dash = 'AA:BB:CC:DD:EE:00'
livingroom_dash = 'AA:BB:CC:DD:EE:01'

###########################################################################

from qhue import Bridge

# Connect to Hue bridge
b = Bridge("192.168.1.17", "USER_NAME_345235346")

# Used to only trigger Dash button once
execute = True

# Variables for Hue lights
bedroomLight = b.lights[1]
livingroomLight = b.lights[2]

# Get current state of each light
def updateStates():
        global bedroomLight_state, livingroomLight_state
        bedroomLight_state= bedroomLight().get(u'state').get(u'on')
        livingroomLight_state = livingroomLight().get(u'state').get(u'on')

updateStates()

###########################################################################


def arp_display(pkt):
  global execute, bedroomLight_state, livingroomLight_state

  if pkt[ARP].op == 1: #who-has (request)
      if pkt[ARP].hwsrc.upper() == bedroom_dash.upper():
        if execute:
          updateStates()
          # Flip the light state
          bedroomLight_state = not bedroomLight_state
          # Send the new light state
          bedroomLight.state(on=bedroomLight_state)
        execute = not execute
      if pkt[ARP].hwsrc.upper() == livingroom_dash.upper():
        if execute:
          updateStates()
          # Flip the light state
          livingroomLight_state = not livingroomLight_state
          # Send the new light state
          livingroomLight.state(on=livingroomLight_state)
        execute = not execute


print sniff(prn=arp_display, filter="arp", store=0, count=0)
###########################################################################

Working Beautifully



I have read a discussion that the button is suppose to last only about 1,000 clicks. And with the blinking red light showing that the shopping operation failed, the battery life of the button can possibly be much worse than 1,000 clicks due to the request failure. Even if it doesn't last long, it was a very fun and cheap project to complete with these $1 Amazon Dash buttons. I probably wouldn't have gotten them at the $5 mark, though.

Overall they have been pretty useful when I don't want to yell at my Amazon Echo or take out my phone to toggle my lights. And it was much cheaper than purchasing a Philips Hue Tap Switch.

7 comments:

  1. Hello! I'm a non-programmer searching for a really basic guide on how to set up some light switches like this. Unfortunately I'm over my head starting at what a Docker image is. Do you happen to know of any good resources that'll explain exactly what software to use, and where/how to copy and paste code? Thanks!

    ReplyDelete
    Replies
    1. https://en.wikipedia.org/wiki/Docker_(software)

      Pretty decent info there.

      Delete
  2. thanks a lot. it works but the MAC addresses need to be defined as a srting of lowercase characters

    ReplyDelete
    Replies
    1. Valid point! I have updated the code so that the MAC address comparison is done with both changed to uppercase.

      Delete
  3. Is the code copied to the Dash directly? Is the Dash then interacting directly with the Philips Hue Hub?

    ReplyDelete
  4. Oh, see it is loaded on the docker site; so it works only when connected to the Internet with access to the stored script on docker

    ReplyDelete
    Replies
    1. Technically it can all be offline. The Dash button is always off. When you press the button it connects to Wi-Fi and broadcasts it's presence. So all that is needed is a script ran on a computer to detect when the Dash button announces its presence to know that the button was pressed.

      Delete