Cheap BlueTooth Buttons and Linux
Selfie sticks - like most modern inventions - are utter tosh. But they've rapidly brought down the price of Bluetooth buttons. So who am I to complain?
Let's take the venerable AB Shutter 3 - You can find it on Amazon for around £2 including postage - or around $2 on AliExpress. Frankly, that's stupidly cheap.
OK, let's put this to work as something other than a vanity clicker! There are no instructions which come with this, it's delivered in a little plastic bag and that's it. Time to get hacking!
Aim
Once paired to a server, like the Raspberry Pi, pressing the button should run a program to turn on my Lifx bulbs.
Cracking It Open
With the battery panel slipped off and the cell removed, it's fairly easy to open the case. Fingernails are sufficient - no screws or glue!
It's an AIROHA AB1126A.
AB1126A is an optimized single-chip solution which integrates baseband and radio for wireless human input device applications especially for remote smartphone camera control. It complies with Bluetooth system version 3.0.
But what happens when we ZOOM! ENHANCE!?

The 24C16N is a fairly generic EEPROM.
But what's this?!?!
The chip is listed as an AB1127A. A chip which, seemingly, doesn't exit. Onwards!
Getting Started
When switched into the "on" position, the dongle is ready to pair.
From the Ubuntu command line:
$ hcitool scan
Scanning ...
80:00:00:00:EE:E0 AB Shutter 3
Aha! We've found it. What sort of device is it?
$ hcitool inq
Inquiring ...
80:00:00:00:EE:E0 clock offset: 0x0acd class: 0x002540
It shows up a a keyboard. Let's connect to it and trust it.
$ bluez-simple-agent hci0 80:00:00:00:EE:E0
Release
New device (/org/bluez/794/hci0/dev_80_00_00_00_EE_E0)
$ bluez-test-device trusted 80:00:00:00:EE:E0
$ bluez-test-input connect 80:00:00:00:EE:E0
To check that it is seen and connected properly:
$ xinput
↳ AB Shutter 3 id=13 [slave keyboard (3)]
Nice! Running xinput query-state "AB Shutter 3"
allows us to see which keyboard keys are activated when the buttons are pressed.
It turns out that the iOS buttons sends Volume Up (key 123) whereas the Android button sends Enter (key 36).
It works! Sorta...
Pressing the selfie-button instantly sends the command to my computer! Well... until the button goes to sleep. The device is powered by a CR2032 battery which, despite the power efficiencies of Bluetooth, isn't magical.
After a few minutes of idleness, the device goes to sleep. Pressing any button wakes it up and repairs the connection - but then another button press is required to send a key press. The pairing process only takes a couple of seconds, so it's not quite instant.
Make it do something useful
Having an external button which can increase the volume or send an enter command isn't very useful. I want to press the button and have a program run which will (for example) turn on my lights.
Run a program when the Bluetooth connection is made
Because the device goes to sleep after a few minutes of inactivity, we need a way to listen for a connection. So, when a button is pressed for the first time, the device connects and a program is run.
I've half-inched the instructions from this InOut Board tutorial.
First of all, make sure Python has the ability to work with Bluetooth:
sudo apt-get install python-bluez
#!/usr/bin/python
import bluetooth
import time
while True:
print "Checking " + time.strftime("%a, %d %b %Y %H:%M:%S", time.gmtime())
result = bluetooth.lookup_name('80:00:00:00:EE:E0', timeout=5)
if (result != None):
print "Device detected"
# Do Something
else:
print "Device NOT detected"
time.sleep(6)
With that running constantly in the background, you can perform an action whenever the device connects.
Run a program when a button is pressed
Right, this is where it gets tricky! Ubuntu doesn't seem to differentiate between different keyboards attached to a device. This means you can't use loadkeys to swap keys, nor xkb.
You can, however, use xkbcomp to remap the buttons on a specific device (thanks to Stephen Wing for that tip).
This will convert the Volume Up to XF86Launch1
and Enter to XF86Launch2
- those are multimedia keycodes which shouldn't be assigned to anything by default.
remote_id=$(
xinput list |
sed -n 's/.*AB Shutter 3.*id=\([0-9]*\).*keyboard.*/\1/p'
)
[ "$remote_id" ] || exit
mkdir -p /tmp/xkb/symbols
cat >/tmp/xkb/symbols/custom <<\EOF
xkb_symbols "remote" {
key { [ XF86Launch1 ] };
key { [ XF86Launch2 ] };
};
EOF
setxkbmap -device $remote_id -print | sed 's/\(xkb_symbols.*\)"/\1+custom(remote)"/' | xkbcomp -I/tmp/xkb -i $remote_id -synch - $DISPLAY 2>/dev/null
The script needs to be re-run every time the Bluetooth connection is re-established. Probably best to run it on reconnect as part of the Python code above.
So, that remaps the inputs for that Bluetooth button. Ok, but how do we get XF86Launch1
to launch a program?
It's pretty easy to set keyboard shortcuts in the GUI- but how do we do it on the command line? Well, you can't. There's no way to tell a shell to run a program when a specific key has been pressed.
So, it's back to Python and listening for the key to be pressed. Which I have no idea how to do!
If you know how to detect multimedia keys, please leave a comment or answer this StackOverflow question.
Or - let me know a better, more obvious way that I'm missing!
BlueTooth buttons are available on AliExpress and Amazon for UK customers.
Jon Burgess says:
The /dev/input interface should let you grab the events before they get seen by X11 / xkb so it would work in a headless setup as well.
Terence Eden says:
/dev/input/event
I need. Onwards!Jon Burgess says:
https://gist.github.com/jburgess777/a6dd67e7fbaaee82c856
$ sudo ./getButton.py
device /dev/input/event17, name "AB Shutter 3", phys "00:1b:10:00:2a:ec"
key event at 1456268812.859839, 115 (KEY_VOLUMEUP), down
key event at 1456268812.860800, 115 (KEY_VOLUMEUP), up
key event at 1456268813.736843, 28 (KEY_ENTER), down
key event at 1456268813.909845, 28 (KEY_ENTER), up
The grab() call should prevent the key presses from being seen by anything else
James says:
"$HOME/bin/do_suspend.sh"
m:0x0 + c:150
XF86Sleep
"$HOME/bin/do_toggle_touchpad.sh"
m:0x0 + c:199
XF86TouchpadToggle
"$HOME/bin/do_autoselect_monitor.sh"
m:0x0 + c:235
XF86Display
"wicd-cli --wireless --disconnect && sudo rfkill block 1"
m:0x0 + c:246
XF86WLAN
Terence Eden says:
I've been thinking on similar lines, per twitter, and wonder about changing the device firmware to choose a different key. Reason for this is I want several buttons to each have different functions. Another advantage is it could work on PC and Mac easily.
Your way is very neat for Pi control and way easier to repeat under Linux, so I will reproduce it for my boiler automation as a boost button.
Will order 3 from the same vendor and see if I can also get at the firmware via those UART tags. Having control over either side of the mapping would be superb.
Terence Eden says:
We had a wonderful brilliant software-oriented college-graduate do the control system update design for boiler controls (Where - don't ask).
He "ripped out all that electrical stuff".
A "failure" stopped his computer and six each six-inch valves on a full-pressure gas line opened up into one hot boiler and five cold ones with a common chimney.
The technician in the building knew he could not run away fast enough to escape the blast, so he stayed and manually killed the gas.
Do not remove or bypass the hardwired safeties on any fueled device - you could do jail time.
Please withhold my email address for obvious reasons.
To be specific about the scope of my own tinkering, my combi boiler has a dedicated timer control interface, which is accessible to end users. It is of the 'zero volts' type, meaning that you are operating a simple switch, closing a circuit that starts and ends at the main control board, which I DO NOT MESS WITH.
I already had an aftermarket timer switch, more sophisticated than the onboard timer, but still very closed.
I have this on now, but have tested previously replacing it with a standalone Pi, implementing a simple timing schedule.
I am preparing a nicer, web controllable version to run on the pi permanently. I am interested in using the bluetooth buttons to give it a 'just boost now' option which my wife, who is competent but disinterested in IT, a tangible improvement over our current system, and to remove the need for her to access the web page.
I plan 4 vital safety features, even given that I am using a purpose built timer control interface:
1) The interface will be one designed for switching mains from a Pi/Arduino, with proper separation of the high and low voltage sections, even though it doesn't need to be, for a few pounds extra it gave me a much more robust switch. The relay fails open, so the boiler turns off if it dies.
2) The Pi does not get to control the boiler direct. The switch signal has to be passed via an Arduino, whose only role in life is to sit in between and enforce a policy that the boiler cannot be switched on or off more than once per minute, or 10 times in 1 hour. If the Pi asks for more frequent changes, it reschedules if within 10 seconds, or sends back an error. This is because boilers are not designed to be turned on and off like a PWM duty cycle, and could be damaged if they spent all day turning on and off. The Arduino also sends a signal every hour to the Pi to say it is alive and still running its program, because I am anal about debugging in any live system.
3) The Pi only accepts connections from within my home network AND there will be a PIN page before I put it 'live'.
4) The Pi, Arduino and relay are in a sensible electronics enclosure, with good cabling, glands and cable strain relief, for the control wire, 5VDC in and wired ethernet. There is no onboard wifi, and the mains power point is some distance from the Pi.
This is the result of my own risk assessment and mitigation thoughts, and doesn't constitute a recipe for anyone seeking to do the same thing - may be worth considering the above, but research the risks yourself.
Is there anything more I could/should think about, in terms of potential risks and mitigations?
Daniel says:
Peter says:
did you ever find a solution for your UP and DOWN on PDF files.
It is exactly what I am looking for as well.
Matt Brunton says:
Adriann says:
Alex Gibson says:
Frederic LE GARREC says:
Thanks.
Terence Eden says:
dzamlo says:
You can find all of this on https://gist.github.com/dzamlo/16bc43e20f299e2206659ff0c3b2306b
It may be useful for somebody.
eni23 says:
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)
once the Dash is pressed, it connects to the WIFI and disconnects, of which my Pogoplug detects the MAC address and executes a bash script... The Bash script basically just emails a screen grab from my CCTV using RTSP, sends the JPG to Flickr, and posts it to my facebook page... I also attached a USB speaker to my Pogoplug, and it then plays a WAV file (DING-DONG.WAV) which notifies people at home that there is someone at the door...
I planned on using a bluetooth button instead as the Dash is limited to 1000 presses before it dies and the battery is hardwired...
I was thinking that all I need is to figure out the button press from Bluetooth, but as you say, the bluetooth button goes to sleep mode, and wakes up on first press?
dzamlo says:
f you don't care which button is pressed, you could do something similar to what you did with the dash: detect when a Bluetooth device with the correct identifier is paired with you. udev may help with that, maybe, I don't know.
john says:
Terence Eden says:
Terence Eden says:
Quirin Lohr says:
Perhaps somebody is helped with my solution for my headless raspberry pi3:
An udev rule which matches the MAC Address of the button, could be one for different buttons.
#/etc/udev/rules.d/98-wolbutton.rules
ATTRS{phys}=="b8:27:eb:a0:40:b7", SYMLINK+="wolpc", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}="wolbuttonpc.service"
This rule triggers a systemd service which starts a python script
/etc/systemd/system/wolbuttonpc.service
[Unit]
Description=WOL Button fuer PC
[Service]
Type=simple
ExecStart=/usr/local/bin/wolbutton.pc.py
Restart=no
/usr/local/bin/wolbutton.pc.py
The python script, slightly modified from Jon Burgess, sends a wol packet at first run and then every time the button goes up (holding the button emits a lot of button downs for me)
#!/usr/bin/env python
import sys
import evdev
from wakeonlan import wol
import syslog
devices = [evdev.InputDevice(fn) for fn in evdev.list_devices()]
if len(devices) == 0:
print "No devices found, try running with sudo"
sys.exit(1)
for device in devices:
if device.phys == "b8:27:eb:a0:40:b7":
device.grab()
wol.send_magic_packet("AC:22:0B:C5:5C:CF")
for event in device.read_loop():
#event at 1492803542.433958, code 115, type 01, val 00
if event.code == 115 and event.type == 01 and event.value == 00:
syslog.syslog('WOL gesendet')
wol.send_magic_packet("AC:22:0B:C5:5C:CF")
kinnalru says:
Bluebutton
Simple daemon that allows you to execute action when bluetooth button shutter pressed. So you can control your PC by low energy button device and few scripts.
https://github.com/kinnalru/bluebutton
Dave Thomas says:
I bought a "Bluetooth Remote Shutter". I'm able to connect and trust it from an RPI running Jessie Stretch.
I can see button pushes using the getButton.py script!
But, there are many events that occur with each button push. For example when I push what is probably "KEY_3" I see this:
key event at 1534185281.995662, 4 (KEY_3), up
key event at 1534185281.995662, 193 (KEY_F23), up
key event at 1534185281.995662, 194 (KEY_F24), up
key event at 1534185281.995662, 184 (KEY_F14), up
key event at 1534185281.995719, 189 (KEY_F19), up
key event at 1534185281.995719, 190 (KEY_F20), up
key event at 1534185281.995719, 191 (KEY_F21), up
key event at 1534185281.995719, 192 (KEY_F22), up
key event at 1534185281.995740, 185 (KEY_F15), up
key event at 1534185281.995740, 186 (KEY_F16), up
key event at 1534185281.995740, 187 (KEY_F17), up
key event at 1534185281.995740, 188 (KEY_F18), up
So, I wonder if the device is actually sending all those keys or whether something in the rpi is running a "macro" on receipt of certain keyboard input.
Where/how would I check for this?
Regardless, I figure I could ignore the extra "keystrokes" and use the first one in each burst. But, I'd like to understand what's goin on.
Thanks!
AirZero says:
ACTION=="add", SUBSYSTEMS=="input", ATTRS{name}=="11:75:58:C5:2D:6F", OWNER="username", SYMLINK+="divoom", TAG+="systemd" #, ENV{SYSTEMD_WANTS}="divoom.service"
sudo nano /etc/systemd/system/divoom.service
[Unit]
Description=Divoom smartlight play button listener
[Service]
Type=simple
User=yourusername
ExecStart=/home/yourusername/project.sh
sudo nano project.sh
#!/bin/bash -eu
cd /home/username/projectname/
evtest --grab /dev/divoom |grep --line-buffered 'value 1$' | while read line ; do
espeak "yeah this works"
done
rijotech says:
Nothing else seems to work, any Idea on how to find a new solution?
rijotech says:
and I noticed most new bluetooth Selfie buttons are not working with any of these techniques, the only one working is the one from the Amazon link also I noticed when using this command sudo showkey nothing happen when I press the already paired AB Shutter3 but that is not the case with the one from the Amazon link,
Pudrik says:
https://wkretype.bdimg.com/retype/zoom/c53d1d2daaea998fcc220ef5?pn=1&o=jpg_6&md5sum=c5c3c60e692d5c4b647440703cd37a03&sign=012a421845&png=0-&jpg=0-
The chip also comes in a QFN40 fashion
https://wkretype.bdimg.com/retype/zoom/26f4c793680203d8ce2f2428?pn=1&o=jpg_6&md5sum=6743835bee00fb7cd3eb66f3af8014a3&sign=a3f40cc33a&png=0-11381&jpg=0-156245
I just purchased this and I want to use it beside selfie. Like let say dial a number on android device for one button and the other for another number. I tried to install it on the pc but the drivers gave an error.
Thanks
@edent says:
Adam Jensen says:
@edent says: