Amazon Dash Buttons In 2017


Amazon's Dash buttons have changed since Ted Benson's original 2015 Medium article about how to hack them.
python dash-buttons raspberry-pi

Last Saturday, I took a 4 hour nap. I thought it was a fantastic use of my time, until I walked downstairs and saw that my roomate, the amateur carpenter that he is, had started and (for the most part) finished building a bar. Then I felt like I was wasting my life away, so I decided I should get around to doing a side project of my own.

Alan's Bar

Alan's Bar

Since my side project queue is a bit backed up, I decided to program a dash button to control the Phillips Hue lights in my room. A project that I decided I was going to do way back when I saw the original Amazon Dash Button hack article on Hacker News back in 2015. Based on said article, I thought the project would be a quick copy/paste job, unfortunately, dash buttons have changed a little bit over the years, so I thought I would clue anyone else who is just getting to 2015 trends in on the changes.

Getting Started

Nothing much about getting started has changed.

  1. Know python

  2. Get a RaspberryPi

  3. Get an Amazon Dash Button

    • Pro-Tip: The dash button brands that don’t sell well Amazon puts on sale for $.99
  4. Go through the setup for the dash button, until it tells you to pick which product to purchase on press. As soon as you get there, quit the app.

Now, you’re button should be communicating with your wireless network when it’s pressed, it’s time to have your RaspberryPi run a python script to detect that communication.

Detecing the button’s MAC address

While sniffing your network, we’re going to run across all kinds of packets from your laptop, phone, Roku, Xbox… literally everything connected to your network, so we need to determine your dash button’s MAC address in order to be able to tell if any given packet is from the button or one of the many other internet connected devices that tend to accumulate in a home.

Now the original article will call for you to run this scanning code to get the MAC address:

from scapy.all import *

def arp_display(pkt):
  if pkt[ARP].op == 1: #who-has (request)
    if pkt[ARP].psrc == '0.0.0.0': # ARP Probe
      print "ARP Probe from: " + pkt[ARP].hwsrc

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

But times seem to have changed.

To detect the MAC address now run:

from scapy.all import *

def arp_display(pkt):
  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=10)

But don’t forget to install the Scapy library first.

apt-get install scapy

And unless you want to occasionally get a weird error when running it, install the libraries that Scapy suggests.

apt-get install tcpdump tcpreplay wireshark

If you get this error:

socket.error: [Errno 1] Operation not permitted

run as sudo.

Oh, and you’re going to have to actually push the button (while the scanning script is running), since it will only communicate with the router on press.

ARP Probe from: MACADDESS

And, now we have the MAC address.

Detect dash button press

To detect the dash button press, the original article calls for a simple modification to the scanning script:

def arp_display(pkt):
  if pkt[ARP].op == 1: #who-has (request)
    if pkt[ARP].psrc == '0.0.0.0': # ARP Probe
      if pkt[ARP].hwsrc == 'MACADDRESS': 
        # code to call on dash button press

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

I found that that code was detecting 2 different packets from my dash button per press, so I had to modify the script to only be triggered on every other packet:

counter = True

def arp_display(pkt):
  global counter
    if pkt[ARP].op == 1: #who-has (request)
      if pkt[ARP].hwsrc == '50:f5:da:f8:d9:5e':
        if(counter):
          counter = False
          # code to call on dash button press
        else:
          counter = True

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

Pretty straight forward, as long as you haven’t taken ~4 years off from Python and remember:

  1. To add the global keyword in the arp_display function

  2. That booleans are capitalized in Python

Wrapping up

To get the program to run without terminating, we have to change the final line from:

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

To:

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

And unless you’re planning on constantly monitoring it, let’s go ahead and remove the print call:

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

Finally, don’t forget to start your program by modifying /etc/rc.local on your pi.

nano /etc/rc.local
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

python /path/to/your/fileName.py &

exit 0

Oh, and the Amazon app will send you a push notification everytime you press the button reminding you to “Finish the Setup process to use your dash button”. I just turned off push notifications from the app, and turned on text notifications for my orders.

And Finally

My dash button turning off my overhead light, and turning on my lamp.

Dash button turning off overhead light and turning on lamp

Boom!

comments powered by Disqus