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!


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!
AB Shutter 3 Circuit-

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
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


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
        print "Device NOT detected"


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.

    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 ] };

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.

32 thoughts on “Cheap BlueTooth Buttons and Linux

      1. The python evdev module can find the device and print the button events:

        $ sudo ./
        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

  1. Why not use `xbindkeys`? In my laptop I glue some scripts to various buttons with this `.xbindkeysrc` file in my home directory:

    m:0x0 + c:150

    m:0x0 + c:199

    m:0x0 + c:235

    "wicd-cli --wireless --disconnect && sudo rfkill block 1"
    m:0x0 + c:246

  2. Following this with interest. Do you have several of these buttons, from the same source, just the one, or several from different makes?
    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.

    1. I've only bought the one. My concern is that if they all identify as the same model, it might be hard to tell them apart in software. Interested to see how you get around it.

      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.

      1. I 100% agree with you, and a great safety warning. Glad that situation did not end as badly as it could have.

        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?

  3. Hi Terence, thanks for this page - I found a selfie button in my local PoundWorld store, looks exactly like the one you have pictured (externally, at least), but I can't get the Pi to recognise it. Both the Pi and selfie button are working with other devices. The Pi dongle reports as " Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)" in lsusb and this seems to be the "chipset of choice" on various forums. I'm persevering & will update you as I get results (or not).

  4. is there a way to adapt this for bluetooth 4.0 buttons? I picked up some cheap ones and I can connect to them, I just can't figure out how to capture the button press when I'm connected to the button

  5. The updates have reminded me I never received those buttons I bought... gaah. Time to chase the Amazon seller...

  6. Hello, do you know a way to avoid the button going to sleep? I would like to put them in my children bags so that the RPi detects them when they enter the house. But as the button is sleeping, cannot work...

  7. Hello, I've recently built an Amazon Dash doorbell, which is basically an Tide Amazon dash which I connected to my home WIFI... I have a Pogoplug running Debian Linux, and I used an ARP probe python script which I placed in my cron jobs (it just run in a loop waiting for the Dash to connect to the WIFI) like this script:

    from scapy.all import *

    def arp_display(pkt):
    if pkt[ARP].op == 1: #who-has (request)
    if pkt[ARP].psrc == '': # 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?

    1. Yes, they go to sleep after some time and then wake up on a key press. I

      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.

      1. That's what I'm thinking I will do... they sell bluetooth buttons for $3 at the a dollar store here.... will purchase some and see if I can get it to work with my Pogoplug... I was thinking of eventually shifting my setup to my Raspberry Pi, but since I'm using the Pogoplug as a webcam server and it has lots of USB ports, I think, I'd stick with it..

  8. Can I use the bluetooth shutter button to connect to my Arduino and act as a bluetooth receiver to make a LED on/off from my phone? Instead of getting a bluetooth module for my arduino

  9. Hey, thank you very much for this post!
    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.
    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


    Description=WOL Button fuer PC


    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"

    for device in devices:
    if device.phys == "b8:27:eb:a0:40:b7":
    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')

What do you reckon?