Friday, June 12, 2020

Python read Bluetooth Remote Shutter on Raspberry Pi


Here show how to read Bluetooth Remote Shutter using Python on Raspberry Pi. My testing unit named "AB Shutter3", with two buttons marked iOS and Android. Actually both buttons can trigger shutter of my Android phone.


Identify the input device of the remote shutter. In this step, lsinput is used to list input. Have to install input-utils.

$ sudo apt install input-utils

$ lsinput

and following commant:

$ ls /dev/input

List the input devices before and after the Bluetooth Remote Shutter to Raspberry Pi. Such that you can know the path to your BT shutter.

In my case, there are two new input devices added.
/dev/input/event5: "AB Shutter3 Consumer Control"
/dev/input/event6: "AB Shutter3 Keyboard"

But in my test, the /dev/input/event6 have NO event generated. So this exercise target to /dev/input/event5 only.

My Python exercise can run on Python 2 and 3, and evdev (https://python-evdev.readthedocs.io/en/latest/index.html) is needed. To install,

For Python3:
$ sudo pip3 install evdev

For Python2:
$ sudo pip install evdev

Python code, pyABS3.py
from evdev import InputDevice, categorize, ecodes

ABShutter3 = InputDevice('/dev/input/event5')

EV_VAL_PRESSED = 1
EV_VAL_RELEASED = 0
BTN_SHUTTER = 115

print(ABShutter3)

for event in ABShutter3.read_loop():
    if event.type == ecodes.EV_KEY:
        if event.value == EV_VAL_PRESSED:
            if event.code == BTN_SHUTTER:
                print('---')
                print('Shutter3 pressed')
                print(event)


It's found that both buttons on my shutter report the same code 115 (KEY_VOLUMEUP).


If you have such other similar device, you have to check the key code, you can use following code to list all event.

from evdev import InputDevice, categorize, ecodes

ABShutter3 = InputDevice('/dev/input/event5')

EV_VAL_PRESSED = 1
EV_VAL_RELEASED = 0
BTN_SHUTTER = 115

print(ABShutter3)

for event in ABShutter3.read_loop():
    if event.type == ecodes.EV_KEY:
        print(event)
        print(categorize(event))



Part II

After then, I borrow two more units from friends for testing. It's found that all 3 units output different combination of output.


-----------------------------------------------
Unit A:
event5: AB Shutter3 Consumer Control
event6: AB Shutter3 Keyboard

Big Button:
- event5 > KEY_VOLUMNUP

Small Button
- event5 > KEY_VOLUMNUP
-----------------------------------------------
Unit B:
event5: AB Shutter3          Consumer Control
event6: AB Shutter3          Keyboard

Big Button:
- event5 > KEY_VOLUMNUP
Small Button
- event6 > KEY_ENTER
- event5 > KEY_VOLUMNUP
-----------------------------------------------
Unit C:
event5: i Shutter Keyboard
event6: i Shutter3 Consumer Control

Big Button:
- event6 > KEY_VOLUMNUP
Small Button
- event5 > KEY_ENTER
-----------------------------------------------

Check the video:
(I capture the video on tab remotely via xrdp, so the response is slower.)


Testing Python script, pyShutter.py
# pyShutter.py
# Read Bluetooth Remote Shutter
# from /dev/input/event5 and /dev/input/event6
# filter for key down of ENTER and VOLUMNUP
#
# http://helloraspberrypi.blogspot.com/2020/06/detect-bluetooth-remote-shutter-ab.html
#
# Work on Python 3.5+
# For Reading events from multiple devices
# read https://python-evdev.readthedocs.io/en/latest/tutorial.html

from evdev import InputDevice, categorize, ecodes
import asyncio

Shutter5 = InputDevice('/dev/input/event5')
Shutter6 = InputDevice('/dev/input/event6')

EV_VAL_PRESSED = 1
EV_VAL_RELEASED = 0
KEY_ENTER = 28
KEY_VOLUMNUP = 115

print(Shutter5)
print(Shutter6)
print('=== Start ===')

async def print_events(device):
                
    async for event in device.async_read_loop():
        if event.type == ecodes.EV_KEY:
            if event.value == EV_VAL_PRESSED:
                if event.value == EV_VAL_PRESSED:
                    if event.code == KEY_ENTER:
                        print('<ENTER> Pressed')
                    elif event.code == KEY_VOLUMNUP:
                        print('<VOLUMNUP> Pressed')
                print(device.path, categorize(event), sep=': ')          
                print('---')

for device in Shutter5, Shutter6:
    asyncio.ensure_future(print_events(device))

loop = asyncio.get_event_loop()
loop.run_forever()



No comments: