The problem I have is as follows. The remotes for my garage door openers do not work. My first HA project was to wifi enable my garage door opener which I did with a Raspberry Pi wired to a relay and WebIOPi. Over time this setup became more sophisticated but there is still one problem, on my wife’s iPhone it takes several screen clicks to trigger the garage:
- unlock the phone
- swipe to the screen with openHAB (or IFTTT Do)
- open the app
- wait for it to connect and load the sitemap
- press the button to trigger the opener
This is awkward and annoying to say the least. On Android with Tasker it is easier because I can detect when I’m nearing home and bring up a button to press automatically.
I want a solution that works for my wife that is as simple as the original remote, push one button.
Solution: Amazon Dash
Amazon Dash is a small hardware device that is designed to automatically order a product from Amazon at the push of a button. But these devices have three features that allow us to use them in openHAB:
- They only cost $5, far cheaper than the cheapest DIY solution I’ve seen
- If you abort their configuration after setting up the wifi settings but before selecting a product you can press the button and it will join the network but not order anything
- When it joins the network it generates an ARP request which can be sniffed on the network
So, based on this tutorial I wrote a new class for my already existing sensor reporting script that uses scapy to sniff the network for ARP packet from the dash button’s MAC address. When such a packet is detected it publishes “Pressed” to an MQTT topic and openHAB has an Item listening on that topic and triggers the garage when a message is published.
It seems to work pretty well, though from button press to the garage starting to go up it takes 10-20 seconds.
Python Code:
The full script is available at the link above. This script also supports GPIO pins and scanning for Bluetooth devices. The Dash button specific code is as follows:
"""
Script: dash.py
Author: Rich Koshak
Date: October 22, 2015
Purpose: Checks the state of the given GPIO pin and publishes any changes
"""
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
import sys
import traceback
from scapy.all import *
class dash:
"""Represents a sensor connected to a GPIO pin"""
def __init__(self, devices, publish, logger, poll):
"""Sets the sensor pin to pull up and publishes its current state"""
self.logger = logger
self.logger.info("----------Configuring dash: ")
for addr in devices:
self.logger.info("Address: " + addr + " Topic: " + devices[addr])
self.devices = devices
self.publish = publish
self.poll = poll
def checkState(self):
"""Detects when the Dash button issues an ARP packet and publishes the fact to the topic"""
try:
def arp_display(pkt):
if ARP in pkt:
if pkt[ARP].op == 1: #who-has (request)
if pkt[ARP].psrc == '0.0.0.0': # ARP Probe
if self.devices[pkt[ARP].hwsrc] != None:
self.logger.info("Dash button pressed: " + pkt[ARP].hwsrc)
self.publish("Pressed", self.devices[pkt[ARP].hwsrc])
else:
self.logger.info("Received an ARP packet from an unknown mac: " + pkt[ARP].hwsrc)
self.logger.info("Dash: kicking off ARP sniffing")
print sniff(prn=arp_display, filter="arp", store=0, count=0)
# Never returns
self.logger.info("Dash: you should never see this")
except:
self.logger.error("Unexpected error in dash: %s", sys.exc_info()[0])
traceback.print_exc(file=sys.stdout)
def publishState(self):
"""Publishes the current state"""
openHAB Items:
Switch T_D_Garage1 "Garage Door 1" <garagedoor> // goes on the sitemap for "manual" trigger
String T_D_Dash_Tide "Tide Dash Button" { mqtt="<[mosquitto:actuators/tide:state:default]" }
String T_D_Dash_Bounty "Bounty Dash Button" { mqtt="<[mosquitto:actuators/bounty:state:default]" }
openHAB Rule:
rule "Trigger Garage Door Opener 1"
when
Item T_D_Garage1 received command or
Item T_D_Dash_Tide received update or
Item T_D_Dash_Bounty received update
then
logInfo("Garage Controller", "The garage door 1 has been triggered")
sendHttpPostRequest("http://192.168.1.201:8000/GPIO/17/sequence/500,01") // calls WebIOPi REST API
end
It might be possible to do this from a binding if I can figure out how to do the packet sniffing from Java. Despite being so slow I can think of a number of use cases where having a physical button to trigger something would come in handy.
If I figure out a way to remove or nicely cover the logo on the button I’ll post that here as a follow up.
Rich