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

24C16N-

The 24C16N is a fairly generic EEPROM.

But what's this?!?!
AB1127A-
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.


Share this post on…

44 thoughts on “Cheap BlueTooth Buttons and Linux”

      1. Jon Burgess says:

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

        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

        Reply
  1. James says:

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

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

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

    Reply
    1. Terence Eden says:

      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.

      Reply
    2. says:

      Please, PLease DO NOT REMOVE THE HARDWIRED SAFETIES ON THAT BOILER PLEASE.
      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.

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

        Reply
    1. says:

      How did you do with 3 of them? I ordered 6 and would like to use all 6 for competitions time measurement.

      Reply
  3. Daniel says:

    Someone has a complete example how to remap ABShuter ? I want to move UP and DOWN a pdf file. Thanks.

    Reply
    1. Peter says:

      Hi Daniel,
      did you ever find a solution for your UP and DOWN on PDF files.
      It is exactly what I am looking for as well.

      Reply
  4. Matt Brunton says:

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

    Reply
  5. Adriann says:

    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

    Reply
  6. Alex Gibson says:

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

    Reply
  7. Frederic LE GARREC says:

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

    Reply
  8. says:

    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 == '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?

    Reply
    1. dzamlo says:

      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.

      Reply
      1. says:

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

        Reply
  9. john says:

    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

    Reply
  10. says:

    And how about several buttons connected to one server service at a time? Is that possible?

    Reply
  11. Quirin Lohr says:

    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.
    #/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")

    Reply
  12. Dave Thomas says:

    Hi, not sure I should post to this old thread...

    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!

    Reply
  13. AirZero says:

    sudo nano /etc/udev/rules.d/70-divoom.rules
    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

    Reply
    1. says:

      Hi - this blog post is 4 years old, so it won't be up-to-date. If you can explain what problems you're having, perhaps someone can offer help.

      Reply
      1. rijotech says:

        Sure and sorry to bother with I know this is an old post but a really useful, I'm building two devices that when I press the button will alert the police https://www.youtube.com/watch?v=mXAdaPBmKQQ
        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,

        Reply
  14. Pudrik says:

    I know the Post is a few years old but That tag actually has 5 Buttons according to the reference Schematic i found, not sure if they are programmed, also includes pinout for the serial programmer.
    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

    Reply
  15. Hi there

    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

    Reply
      1. Adam Jensen says:

        I tried that, doesn't work. I wanted to access the root to the chip so I can reprogram it instead of using the camera it can dial a number.

        Reply
        1. @edent says:

          It is extremely unlikely that you can re-program the chip to change the key it sends. If you speak to the manufacturer, they may be able to help.

          Reply

Trackbacks and Pingbacks

What links here from around this blog?

What are your reckons?

All comments are moderated and may not be published immediately. Your email address will not be published.Allowed HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre> <p> <br> <img src="" alt="" title="" srcset="">