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:
Terence Eden says:
/dev/input/event
I need. Onwards!Jon Burgess says:
James says:
Terence Eden says:
Terence Eden says:
Daniel says:
Peter says:
Matt Brunton says:
Adriann says:
Alex Gibson says:
Frederic LE GARREC says:
Terence Eden says:
dzamlo says:
eni23 says:
dzamlo says:
john says:
Terence Eden says:
Terence Eden says:
Quirin Lohr says:
kinnalru says:
Dave Thomas says:
AirZero says:
rijotech says:
rijotech says:
Pudrik says:
@edent says:
Adam Jensen says:
@edent says: