Monday, October 31, 2016

DD-WRT update and Amazon dash

My router got updated and my initial experiments had all been on a tmpfs. As a reminder to my future self, JFFS2 should be enabled for persistent storage on flash (or use a USB drive of some kind).

Following worked for me.

I then created a script on the jffs2 mount point and updated DNSMasq settings (specifically "Additional DNSMasq Options") to point to this, e.g.:


Where /jffs/dhcp_ha_post is executable:

chmod a+rwx /jffs/dhcp_ha_post

Sunday, July 24, 2016

Home Assistant, custom events and Amazon Dash Button

Last post had high level over view of Amazon Dash hacking options that have already been discovered, along with an experiment with the Amazon Dash button with my router.

HA (like many home hub solution) offers custom events, docs/wiki for this are at

I was able to get a custom event/trigger created with the following config:

  - alias: Turn on a single light when custom event fires
    # curl -X POST http://localhost:8123/api/events/MY_CUSTOM_EVENT
      platform: event
      event_type: MY_CUSTOM_EVENT
      service: homeassistant.turn_on
      entity_id: switch.switch_name

The switch name can be either derived by scanning through your config or by copy/pasting from the web UI http://localhost:8123/devState (or what ever machie HA is running on). It could even be a group etc.

Triggering this can be easily achieved via the REST interface HA offer 

As per the config example comment above, using curl is an easy way to send the event. This example is without any security, a password can be setup (presumably TLS over https too?).

My router is running dd-wrt and does NOT have curl so my terrible idea is to use netcat, and forgo security (i.e. anyone on the network can inject events) by updating the script that DNSMasq fires by manually sending an incomplete/minimal POST message:


# To be called by/from DNSMasq as dhcp-script # More information, see if [ -z "$2" ] then echo 'Missing param 2 (MAC address)' echo This script should be called by DNSMasq exit 1 fi HA_IP_ADDRESS= # Edit me! HA_IP_PORT=8123 # Send custom event to Home Assistant server # this really should use curl but it is not available # so make do with nc (netcat) { echo POST /api/events/MY_CUSTOM_EVENT_${2} HTTP/1.1.$'\r' echo Host: ${HA_IP_ADDRESS}$'\r' echo $'\r' } | nc ${HA_IP_ADDRESS} ${HA_IP_PORT}

This includes the MAC address of the Dash button in the event name (rather than making use of POST data payload, i.e. custom event parameter "event_data")

This means a custom trigger is created for each button and the HA config is the only place that needs updating, rather than the dns script.

I need to experiment with the range of the buttons now, so far all testing has been within 5m of the access point. But I'm now all setup for using these how I want :-)

One thing that other posts have mentioned is that uninstalling the Amazon store app may be desirable as it will remind you that the Dash button setup is not complete. This has been understated. I had about 15 notifications in just a few minutes!

Saturday, July 23, 2016

Yet Another Amazon Dash Button post

Searching for "amazon dash hack" yields a LOT of hits. There are some really great posts on this topic, and some less great posts. Pretty sure this post will fail in the later but this is probably mostly for me as a note taking exercise.

IMHO the definitive posts to read are:

I have the V2 button, you can read the above posts for more detail on them. I was NOT able to get this connected to my network without a mobile device. Using a laptop did NOT work. Once the Dash was hooked up to the network, I was able to change the WiFi network the Dash connected to by using a laptop but provisioning a fresh Dash can not be done this way without more digging/effort.  To change the Wifi network simply:
  1. Press and hold button for 4 secs (Amazon document 6 secs) until the led flashes blue
  2. Connect to the WiFi network the Dash is now serving on "Amazon ConfigureMe"
  3. Your device is almost certainly IP, the dash is on and is running a webserver at
  4. Accessing the server will display the firmware version, DSN number (as printed on the box and on the back of the button) and more importantly the MAC address (sans ":") which is needed to identify the button
  5. You can change the Wifi network and WiFi password the Dash uses via curl:
curl ""

If you read from the webserver with a json content type, e.g.:

curl -H "Content-Type: application/json"

Get something like this (note this has been formatted for readablility):

    "amzn_devid":"DSN: printed on back of device and from QRCode",
    "amzn_networks" :   [
                        {"ssid":"SID_HERE","bssid":"BSSID_HERE","security":"WPA AES PSK","rssi":"-72"},
                        {"ssid":"SID_HERE","bssid":"BSSID_HERE","security":"WPA AES PSK","rssi":"-72"}

As you might expect, the Dash will fail to configure if the access point it is connected to does not have Internet access.

When entering the WiFi password there is the option for Amazon to store this information. Whilst I was experimenting with this, I went through this process a lot and I must have forgotten one time to set this correctly and now Amazon has my WiFi password (for a sand boxed access point).

Matthew Petroff doesn't go into detail in how to then make use of the buttons for custom purposes but there are lots of links on that. But Ted Benson got into details on detecting the DNS/ARP connection that the Dash makes when getting its IP address for each button press at:

 There is a more sophisticated approach where the Amazon web service itself is emulated - from comments it is not clear if this works with V2 devices. This approach allows control over the LED to show some sort of state.

The V2 JK29LP has the same DHCP need as V1 (i.e. DHCP, not static address) so I explored the options there. The main options (and code samples in GitHub) I've seen are packet capture the ARP packet and then act on that, either using a framework or raw sockets

Raw socket access - this only works under Linux (maybe Mac) and does not work under Windows, even when changing the type to IF_NET

Using a packet capture framework scapy under Linux as described by Ted Benson or under Winpcap under Windows 

Buried in the comments at  Mohnish Chaudhary suggests making use of the dhcp-script that dnsmasq has.

I tried raw socket arp reading under Windows and could not get this to work, the OS errors out.
I tried raw socket arp reading under Linux and this does work (I think I had one occasion when the button press was not picked up), this was using a machine on the same WiFi network

Like Mohnish, I'm thinking packet sniffing is a little overboard for me. I have a dd-wrt router that is working fine and it uses DNSMasq. In the web interface there is a "Additional DNSMasq Options" config option, I simply set that to:


Which simply gets appended to the config file (i.e. this is not being provided via the command line parameter of the same name).

And then knocked up a quick and dirty script to see if it works:

# usage dnasmasq.... --dhcp-script=/tmp/myscript
# in dd-wrt (etc.) add line:
#    dhcp-script=/tmp/myscript



    touch ${logfile_name}  # ensure file exists on first run
    #file_size=`du -k ${logfile_name} | cut -f1`
    #max_file_size=4  # Kb

    file_size=`ls -al ${logfile_name} |awk '{print $5}'`
    max_file_size=2048  # bytes
    max_file_size=1024  # bytes

    # Simple truncation/rotation
    # NOTE this will break any `tail -f ...` usage
    if [ ${file_size} -gt ${max_file_size} ];
        mv ${logfile_name} ${logfile_name}_trunc
        echo truncated `date` > ${logfile_name}
        #tail -20 ${logfile_name}_trunc >> ${logfile_name}
        grep -v '^truncated' ${logfile_name}_trunc | tail -20 >> ${logfile_name}
        rm ${logfile_name}_trunc


echo ------------------
>> ${logfile_name}
env | grep \^D >> ${logfile_name}
echo `date` $0 ${*} >> ${logfile_name}

This works and shows the MAC address. dd-wrt includes both nc (netcat) and wget so this could proxy somewhere else without needing to packet sniff. I've yet to hook this piece up.... I'm trying to avoid writing a custom server to to receive the payload (which is usually my goto answer) and see if it can be delivered directly to

Is it worth going through the time to set this up? Dunno. But I had a fun morning playing with this :-)