Pcapmq: Yet another dash button hack, and many other things possible

Background

I need a solution to remind me admin the medicine to my son twice a day, especially in the busy morning. So I changed my foyer’s light to a Hue color, made a simple automation to change its color to yellow at 6:30 and red at 7:30. It can always remind me before we leave home. The problem is now I need a simple way to turn off the light and that automation as well after I gave him the dose.

The medicine cabinet is on the second floor and my Echo Dot is in the kitchen, so no voice control.

The Dash button seems a perfect fit, I can put it on the cabinet, and just click it every time I finished the job.

I know there already are tons of articles around this topic, but I don’t like any of them because they are either depends on heavy scapy (such as Dasshio) or need another stack (such as Dasher).

So I want to go to another route, I want to have a simple program can monitor network traffic, and publish a message. I want this program is running outside of HA, since it definitely needs root privilege, I also want to use a lightweight message, so that I can send out huge amount of messages if need (who knows how many network packets you will capture)

A Program Publish Packet Capture Result to MQTT

I finally decided to write a python program use pypcap and hbmqtt to publish MQTT message when captured a network packet I am interest in. It has and only has two very simple features: listen the network traffic, report the result by MQTT.

Here is the repo, https://github.com/rtfol/pcapmq

Install

I published package to pypi so you can install it by pip, but like other solution, you have to install libpcap at first

sudo apt install libpython3-dev libpcap-dev
sudo pip3 install --pre pcapmq

Packet Capture

pcapmq can be used without mqtt, it will listen the network and print the result to console. You can use following filter to capture dash button press event. Please replace 12:34:56:78:AB:CD with your dash button’s MAC address

sudo pcapmq --filter "ether src 12:34:56:78:AB:CD"  --payload-format "{} Dash button is online"

Publish Message

Home Assistant has an embedded MQTT broker. It make things really easy.

sudo pcapmq --filter "ether src 12:34:56:78:AB:CD"  --payload-format "ON" --broker-url mqtt://homeassistant:your_password@localhost --topic "home-assistant/dash/{1[0]:02X}.{1[1]:02X}.{1[2]:02X}.{1[3]:02X}.{1[4]:02X}.{1[5]:02X}"

It will connect to local mqtt broker, publish a simple ON message to the topic home-assistant/dash/your_dash_button_mac_address, as long as it found an Ethernet packet sent from your dash button’s MAC address.

Home Assistant Configuration

In HA, I use a mqtt binary sensor to represent the state of dash button. Here is the configuraiton.yml

# MQTT
mqtt:

# Binary Sensor
binary_sensor:
  - platform: mqtt
    name: "Amazon Dash Button Sensor"
    state_topic: "home-assistant/dash/12.34.56.78.AB.CD" # use . not : to avoid potential url format issue 
    payload_on: "ON"
    payload_off: "OFF"
    device_class: moving

I have some problem to deal with json message format, so I use a simple ON message, and put the MAC address in the topic. Therefore, you can use it to listen multiple buttons

However, this sensor will never turn to OFF by itself, we have to do some automation here. In automation.yml

- id: '1525596293186'
  alias: Reset Dash Button
  trigger:
  - entity_id: binary_sensor.amazon_dash_button_sensor
    from: 'off'
    platform: state
    to: 'on'
  condition: []
  action:
  - delay: 0:01
  - data:
      payload: 'OFF'
      topic: home-assistant/dash/12.34.56.78.AB.CD
    service: mqtt.publish

Finally I use a group show my button on the home page

dash_buttons:
  name: Dash Buttons
  entities:
    - binary_sensor.amazon_dash_button_sensor

Systemd

Use systemd, it will be an easy job to change my program into a service, here is my /etc/systemd/system/pcapmq.service file

[Unit]
Description=Dash button service
[email protected]

[Service]
Type=simple
ExecStart=/usr/local/bin/pcapmq --filter "ether src 12:34:56:78:AB:CD"  --payload-format 'ON' --broker-url mqtt://homeassistant:your_password@localhost --topic "home-assistant/dash/{1[0]:02X}.{1[1]:02X}.{1[2]:02X}.{1[3]:02X}.{1[4]:02X}.{1[5]:02X}"

[Install]
WantedBy=multi-user.target

Please remember to replace your button’s MAC address and password, then execute following command to run the service

sudo systemctl enable pcapmq.service
sudo systemctl start pcapmq.service

Now, press the button!

Alright, any question?

Find your button’s MAC

There are really million’s way to find out that, for example (this one)[https://github.com/danimtb/dasshio#how-to-find-the-mac-address-of-your-dash]

Why another wheel?

I do not want to install node.js on my raspberry pi, although I use node.js for my daily job. I want to practice some python instead.

How about duplicated message

Each dash button press will send out multiple packet, so I will send multiple message. But since I am using binary sensor, duplicate set state message is not matter at all.

Further Application

Next, I want to explore use pcapmq to do present detection.

More Development

pcapmq is actually just few lines of code, I will try to do some rework next weekend to better use asyncio with pypcap

Thanks

Thanks for all thoughtful discussions here, Capture Amazon Dash button press

3 Likes

Hey, thanks for this. I have had 3 different dasher type things installed on my Arch Linux system and nothing has worked so far. I haven’t tried to debug them too much as I don’t really need the functionality as yet.
This looks quite interesting so I will definitely try this one.
Thread bookmarked :slight_smile:
John

I only published pre-release package, so please use sudo pip install --pre pcapmq

Did a fresh build on RPi with DietPi/Debian Stretch. I was able to locate the MAC for the dash button, but each press results in the following error trace. MQTT message is not published. Any hints as what may be wrong?

root@DietPi:~# pcapmq --filter “ether src 78:e1:03:2b:06:88” --payload-format “ON” --broker-url mqtt://192.168.0.137 --topic “amazon/dash/{1[0]:02X}.{1[1]:02X}.{1[2]:02X}.{1[3]:02X}.{1[4]:02X}.{1[5]:02X}”
connected to MQTT broker
listening on eth0: ether src 78:e1:03:2b:06:88
ClientProtocolHandler Unhandled exception in reader coro: IncompleteReadError(‘0 bytes read on a total of 1 expected bytes’,)
ON
Disconnected from broker
Client not connected, waiting for it
Unhandled exception: ‘NoneType’ object has no attribute ‘write’

2 packets received by filter
0 packets dropped by kernel
0 packets dropped by interface
Client session is not currently connected, ignoring call
disconnected from MQTT broker
Traceback (most recent call last):
File “/usr/local/bin/pcapmq”, line 11, in
sys.exit(main())
File “/usr/local/lib/python3.5/dist-packages/click/core.py”, line 764, in call
return self.main(*args, **kwargs)
File “/usr/local/lib/python3.5/dist-packages/click/core.py”, line 717, in main
rv = self.invoke(ctx)
File “/usr/local/lib/python3.5/dist-packages/click/core.py”, line 956, in invoke
return ctx.invoke(self.callback, **ctx.params)
File “/usr/local/lib/python3.5/dist-packages/click/core.py”, line 555, in invoke
return callback(*args, **kwargs)
File “/usr/local/lib/python3.5/dist-packages/pcapmq/cli.py”, line 70, in main
client.publish(formatted_topic, message.encode()))
File “/usr/lib/python3.5/asyncio/base_events.py”, line 466, in run_until_complete
return future.result()
File “/usr/lib/python3.5/asyncio/futures.py”, line 293, in result
raise self._exception
File “/usr/lib/python3.5/asyncio/tasks.py”, line 239, in _step
result = coro.send(None)
File “/usr/local/lib/python3.5/dist-packages/hbmqtt/client.py”, line 72, in wrapper
return (yield from func(self, *args, **kwargs))
File “/usr/local/lib/python3.5/dist-packages/hbmqtt/client.py”, line 272, in publish
return (yield from self._handler.mqtt_publish(topic, message, app_qos, app_retain))
File “/usr/local/lib/python3.5/dist-packages/hbmqtt/mqtt/protocol/handler.py”, line 185, in mqtt_publish
yield from self._handle_message_flow(message)
File “/usr/local/lib/python3.5/dist-packages/hbmqtt/mqtt/protocol/handler.py”, line 198, in _handle_message_flow
yield from self._handle_qos0_message_flow(app_message)
File “/usr/local/lib/python3.5/dist-packages/hbmqtt/mqtt/protocol/handler.py”, line 219, in _handle_qos0_message_flow
yield from self._send_packet(packet)
File “/usr/local/lib/python3.5/dist-packages/hbmqtt/mqtt/protocol/handler.py”, line 443, in _send_packet
yield from packet.to_stream(self.writer)
File “/usr/local/lib/python3.5/dist-packages/hbmqtt/mqtt/packet.py”, line 202, in to_stream
writer.write(self.to_bytes())
AttributeError: ‘NoneType’ object has no attribute ‘write’
Task was destroyed but it is pending!
task: <Task pending coro=<MQTTClient.handle_connection_close() running at /usr/local/lib/python3.5/dist-packages/hbmqtt/client.py:457> wait_for=>
root@DietPi:~#

I haven’t use that in last few month, maybe the hbmqtt client need to update. I won’t have time to look at it in November, hope someone can pick it up. Pull request is welcome.

Awarecan - thanks for posting this … but I’m getting the same error as mcsSolutions.
Any help is greatly appreciated.