Amazon Dash Button Automation

Screen-Shot-2015-03-31-at-9.23.22-AM-620x311

If you haven’t heard about them, Amazon is putting out these shiny new buttons which are basically walking advertisements for certain brands of products. You can stick them to a wall with the included adhesive or hang them somewhere with the included ring (not pictured). What is even more interesting is that when you press one of these buttons they are supposed to place an order for a new product without any interaction on your part. They connect up to your home WIFI (with a bit of initial setup through the Amazon app) and beam the order request out to Amazon on the double so you can have your new garbage bags in a jiffy.

They come in veritable cornucopia of flavors right now, 18 buttons in all at the time of this writing. With multiple different companies vying for the opportunity to pitch their wares to you and get a little ad-space on your wall. Rumor has it that these companies are even paying Amazon for the privilege of being button-ized.

856b77326349b311da4c8fa3f8c8082a

Amazon is pitching these things for $5 a piece right now to Amazon Prime members only. Although supposedly you’ll get a $5 discount when you place your first order of product X using the button. You’ve really got to hand it to Amazon here, they’re making money on both ends, from the business AND the user. Let’s forget the fact that the whole concept is just a bit ridiculous (even for a technophile like me)… that they’d expect you to pay $5 for the convenience of hitting a button to order a product. That you would be so lazy as to not even perform the most rudimentary of price comparisons. That you would be willing to pay the iron price Amazon price for whatever good… whatever it happens to be. Are we all really that lazy busy?

Poor product ideas aside, I immediately plopped down $10 in Amazon gift card money and bought two of them right before my Prime subscription ran up because something tells me these aren’t going to be on the market for very long. After being inspired by Ted Benson I had a feeling there must be something I could set these up for.

61yJkst6nVL._SY355_

I purchased the most basic dash button model I could find with the least offensive advertisements… in this case this was the Amazon Elements model. When they arrived I immediately covered up the amazon logos with a label maker and called the buttons, very memorably, #1 and #2.

IMG_20150921_080310
Here you can see the hanging rings included with the buttons, the button on the right is naked.

Setup of the buttons is really simple but you must be careful to NOT COMPLETE THE SETUP. You wouldn’t want these buttons to actually order something hahaha. If you accidentally do complete the setup (like I did), you can dissociate the button from whatever product you picked but I recall it being an extra annoying step. Read the Ted Benson article here for clues on where to abort the setup process. For me it was as simple as force-closing the app on my phone when it prompted me to select the radio-button for a corresponding product. Presto chango the button was now rendered useless. It will still connect to your home Wifi and communicate to Amazon but it will not complete the ordering process.

Actually if you were to stop right here things would be quite annoying for you because every time you hit the button it still communicates with Amazon and then the silly phone app blows-off an annoying message to you reminding you to finish setting up your button. This gets old really quickly even when I was testing– even more fun is that the notifications stack up in Android so you’d have a list a mile long of notifications unless you take the next steps.

1). Setup a static IP for the button

2). Block all traffic from that IP out to the internet

You can use “discover mode” shown in python code below to learn which MAC address your dash button has in order to properly bind it to a static IP. Regarding the ability to block traffic, not every home Wifi router can support this function but if you have a newer router like the super-awesome Asus RT-AC68U you’re good to go. In my case I built a rule that applied to all hours of every day and applied that to the IP addresses of the two buttons for all of both kinds of traffic, TCP and UDP. Basically these things are now entirely disconnected from the internet.

Selection_168

Sure enough, when I applied these rules and continued pressing these buttons, I no longer received any notifications from Amazon. One side effect of this action is that the buttons stay awake longer as they try (and fail) to communicate with Amazon; I would estimate about 30 seconds in total although I have not specifically timed it.

Onto the fun stuff.

Now that the buttons are setup I cannibalized and re-factored some code to listen for them on the network. Here is what I ended up with.

#!/usr/bin/python

import sys
import time
import socket
import struct
import logging
import binascii
import subprocess

logging.basicConfig(filename='/var/log/dashbutton.log',
                    level=logging.INFO,
                    format='%(asctime)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S -- ')

discover_mode=False

if len(sys.argv) > 1:
    if sys.argv[1] == "discover": discover_mode=True

rawSocket = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0003))
buttons={
    "00bb3aff6aea_192.168.1.00":["Button One",0,["/home/pi/scripts/WEMO/send_wemo_commands.py","sendall.toggle"]],
    "747548bd4908_192.168.1.255":["Button Two",0,["/home/pi/scripts/WEMO/send_wemo_commands.py","kitchensink.toggle"]]}

logging.info(' ### Dash Button Service Started ### ')
while True:
    packet = rawSocket.recvfrom(2048)
    ethernet_header = packet[0][0:14]
    ethernet_detailed = struct.unpack('!6s6s2s', ethernet_header)
    arp_header = packet[0][14:42]
    arp_detailed = struct.unpack('2s2s1s1s2s6s4s6s4s', arp_header)
    # skip non-ARP packets
    ethertype = ethernet_detailed[2]
    if ethertype != '\x08\x06': continue
    source_mac = binascii.hexlify(arp_detailed[5])
    dest_ip = socket.inet_ntoa(arp_detailed[8])
    identifier=source_mac+"_"+str(dest_ip)

    if discover_mode:
       logging.info("We saw an arp from MAC: " + str(source_mac) + " ip: " + str(dest_ip)+ "\n")
       continue

    if identifier in buttons:
        buttons[identifier][1] += 1 #iterate the count of button presses
        logging.info(buttons[identifier][0] + " Pressed " + str(buttons[identifier][1]) + " times.\n")
        subprocess.Popen(buttons[identifier][2],stdout=subprocess.PIPE).communicate()[0]

Or download the code from my Github Gist page.

The code has two modes in which it can be run:

  • Discover mode: ./dash_button.py discover
  • Vanilla mode: ./dash_button.py

In discover mode the script will call out whatever MAC addresses it sees sourcing ARP packets… Press your button here and see what addresses your button owns. Once you’ve defined the static IPs in your router come back to the script and update the buttons dictionary with your “tuple” of MAC and IP address followed by your colloquial name for the button, the number of times it’s been pressed and lastly the command that should be executed by subprocess when the button is pressed.

Now you can run the script in vanilla mode to test pressing your button.

A simple few lines of code which sniff all incoming traffic listening for ARPs from a specific tuple of source MAC and IP address. Since this script is essentially sniffing all incoming packets you’ll want to situate this code on a remote part of your network that doesn’t process big file transfers or the like. In my case I have this code sitting on a Raspberry Pi that isn’t used for much.

Reading the code, you can see the “tuple” as the key for the “buttons” dictionary this is the key to identifying traffic we care about. The format for the buttons dictionary is rudimentary but functional and avoids making a class for something really simple.

In my example I’m kicking off WEMO Events whenever buttons are pressed. I keep button #2 by my nightstand and press it to turn off my kitchen light when I go to bed. Button #1 just toggles every light switch in the house for fun.

Starting the Script on Boot:

I built an Upstart job to start the script at each boot. In order to use this method, you’ll need to install Upstart on your Pi with:

pi@pi ~ $ sudo apt-get install upstart
Reading package lists... Done
Building dependency tree 
Reading state information... Done
Suggested packages:
 graphviz
The following packages will be REMOVED:
 sysvinit
The following NEW packages will be installed:
 upstart
WARNING: The following essential packages will be removed.
This should NOT be done unless you know exactly what you are doing!
 sysvinit
0 upgraded, 1 newly installed, 1 to remove and 81 not upgraded.
Need to get 502 kB of archives.
After this operation, 940 kB of additional disk space will be used.
You are about to do something potentially harmful.
To continue type in the phrase 'Yes, do as I say!'
 ?] Yes, do as I say!
Get:1 http://mirrordirector.raspbian.org/raspbian/ wheezy/main upstart armhf 1.6.1-1 [502 kB]

You can see during the Upstart install the system actually prompts you for such a big change with some special language [bolded above].

After Upstart is installed give your Pi a reboot:

sudo reboot

Lastly build the Upstart job by creating a file called “/etc/init/dashbutton.conf” and adding the following contents [replacing the exec line with the location where you have stored the script on your machine]:

author "Eric Pulvino -- AlwaysTinkering.wordpress.com"
description "Upstart Script to run Amazon Dash Button service"

start on runlevel [2345]
stop on runlevel [016]

respawn

exec /home/pi/scripts/dash_button.py

That’s it. You can reboot your Pi to automatically start the service now however you could also just run the following command to start the service manually:

sudo service dashbutton start

Summary:

I’m sure there will be more in store for the buttons down the road with Halloween so close by. My typical Halloween goal is to literally scare the neighborhood children (and adults to death) so I might setup the use of the buttons to disable some of the really scary effects for 30-60 seconds when I see little children coming up the walk. Either way I’ll be sure to post some of my Halloween antics this year!

Advertisements

5 thoughts on “Amazon Dash Button Automation”

  1. I’m planning on sticking one to our old school washing machine so that we can press it when the cycle starts and get a notification 40 minutes later to check if it’s done. It sounds like it should be do-able using python and twilio.
    I’ve got two on the way and the second I’ll configure to turn my xmas lights & tree off and on via wemo.
    Will see how I get on!

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s