Added support of bluetooth remote G20BTS PRO to my Volumio on RPI4

Looking for some help please. I think i figured out the name (G20BTS and the MAC address.
I was able to pair the remote. Only the off button works. I cannot control the volume with volume buttons. Looking for some help please ! :blush: I ran the python script and it gives me this, "No such file or directory: ‘/dev/input/kbd’ seems like its looking for a keyboard? anyways I’m totally stuck now.

txs

Please post the output of:
cat /proc/bus/input/devices

volumio@pi4version3:~$ cat /proc/bus/input/devices                                                  
I: Bus=0005 Vendor=1d5a Product=c081 Version=0000
N: Name="G20BTS Keyboard"
P: Phys=B8:27:EB:21:47:5E
S: Sysfs=/devices/virtual/misc/uhid/0005:1D5A:C081.0001/input/input0
U: Uniq=AB:6B:70:5B:57:CF
H: Handlers=sysrq kbd leds event0
B: PROP=0
B: EV=12001f
B: KEY=306ff 0 0 0 0 483ffff 17aff32d bfd44446 0 0 3ff 130ff3 8b17c007 ffff7bfa d9415fff febeffdf ffefffff ffffffff fffffffe
B: REL=1040
B: ABS=1 0
B: MSC=10
B: LED=1f

I: Bus=0005 Vendor=1d5a Product=c081 Version=0000
N: Name="G20BTS Mouse"
P: Phys=B8:27:EB:21:47:5E
S: Sysfs=/devices/virtual/misc/uhid/0005:1D5A:C081.0001/input/input1
U: Uniq=AB:6B:70:5B:57:CF
H: Handlers=mouse0 event1
B: PROP=0
B: EV=17
B: KEY=70000 0 0 0 0 0 0 0 0
B: REL=903
B: MSC=10

I: Bus=0005 Vendor=1d5a Product=c081 Version=0000
N: Name="G20BTS"
P: Phys=B8:27:EB:21:47:5E
S: Sysfs=/devices/virtual/misc/uhid/0005:1D5A:C081.0001/input/input2
U: Uniq=AB:6B:70:5B:57:CF
H: Handlers=event2
B: PROP=0
B: EV=100001

Next:
cat /dev/input/event0
Shake mouse or hit buttons and see if there is a response and report back.

cat /dev/input/event1
Shake mouse or hit buttons and see if there is a response and report back.

cat /dev/input/event2
Shake mouse or hit buttons and see if there is a response and report back.

Yes I get a response. Like weird characters on the screen. on event0 only.
jk▒e▒sjk▒e▒▒
like this.

try if this does the trick. Just a guess as I don’t have the hardware.

while True:
    dev_list_file = open(dev_list_filename, 'r')

    dev_found = False
    infile_path = "/dev/input/"
    for line in dev_list_file:
        if '=' in line:
            tokens = line.split('=')
            if  'G20BTS Keyboard' in tokens[1]:
                dev_found = True
            if dev_found and 'Handlers' in tokens[0]:
                tokens = tokens[1].split(' ')
                infile_path = infile_path + tokens[3]
                break

    dev_list_file.close()
    if dev_found:
        EVENT_SIZE = struct.calcsize("llHHIllHHIllHHI")
        file = open(infile_path, "rb")
        event = file.read(EVENT_SIZE)
        pressed = -1
        while event:
            (tv_sec1, tv_usec1, type1, code1, value1, tv_sec2, tv_usec2, type2, code2, value2, tv_sec2, tv_usec3, type3, code3, value3) = struct.unpack("llHHIllHHIllHHI", event)
            if pressed == -1:
                pressed = value1

                url = ''

                if value1 == 786666:
                    url=URL + 'volume&volume=minus'
                elif value1 == 786665:
                    url=URL + 'volume&volume=plus'
                elif value1 == 786637:
                    url = URL + 'toggle'
                elif value1 == 786658:
                    url = URL + 'volume&volume=toggle'
                elif value1 == 786614:
                    url = URL + 'prev'
                elif value1 == 786613:
                    url = URL + 'next'
                if len(url) > 0:
                    try:
                        requests.get(url=url, timeout=0.000000001)
                    except requests.exceptions.ReadTimeout:
                        pass
            elif pressed == value1:
                pressed = -1
            event = file.read(EVENT_SIZE)
    else:
        time.sleep(1)

A different approach, as many USB “Air-mouse” devices have 1 to many events, the code will not work. As it is only looking at one event.

This code can be extended to multiple events.

#!/usr/bin/python3

import time
import asyncio
import requests
from evdev import InputDevice, categorize, ecodes   # sudo apt-get install python3-evdev

URL='http://localhost:3000/api/v1/commands/?cmd='

# If mouse has more then one event, comment out what is not needed
event0 = InputDevice('/dev/input/event0')
#event1 = InputDevice('/dev/input/event1')
event2 = InputDevice('/dev/input/event2')
#event3 = InputDevice('/dev/input/event3')

STATUS = 0

# Keys see: https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
EV_VAL_PRESSED = 1
EV_VAL_RELEASED = 0
# event0:
KEY_ENTER =      28
KEY_LEFT =       105
KEY_RIGHT =      106
KEY_UP =         103
KEY_DOWN =       108
KEY_PAGEDOWN =   109
KEY_PAGEUP =	 104
# event1:
# event2:
KEY_VOLUMEDOWN = 114
KEY_VOLUMEUP =	 115
KEY_PLAYPAUSE =  164
# event2:

print(event0)
#print(event1)
print(event2)
#print(event3)
print('=== Start ===')

async def print_events(device):
    global  STATUS            
    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_PLAYPAUSE:
                        print('<Play/Pause> Pressed')
                        url = URL + 'volume&volume=toggle'
                    elif event.code == KEY_LEFT:
                        print('<LEFT> Pressed')
                        url = URL + 'prev'
                    elif event.code == KEY_RIGHT:
                        print('<RIGHT> Pressed')
                        url = URL + 'next'
                    elif event.code == KEY_VOLUMEUP:
                        print('<RIGHT> Pressed')
                        url=URL + 'volume&volume=plus'
                    elif event.code == KEY_VOLUMEDOWN:
                        print('<RIGHT> Pressed')
                        url=URL + 'volume&volume=minus'                        
                if len(url) > 0:
                    try:
                        requests.get(url=url, timeout=0.000000001)
                    except requests.exceptions.ReadTimeout:
                        pass      
                print(device.path, categorize(event), sep=': ')          
                print('---')

for device in event0, event2:
    asyncio.ensure_future(print_events(device))

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

No joy with changing to g20bts keyboard.
a couple of things. I do not have a screen on this device. does it need a screen maybe to work?
also if I run the python script I get this :
File “g20.py”, line 29, in
file = open(infile_path, “rb”)
FileNotFoundError: [Errno 2] No such file or directory: ‘/dev/input/kbd’
Maybe that’s a hint to whats going on.
Also, the usb code you sent is way above my capabilities.
Well hopefully you have other thoughts. Thanks!

Seems you’re not following my instruction and still run the code from the opening post.
I’ve adapted that part in Added support of bluetooth remote G20BTS PRO to my Volumio on RPI4 - #14 by Wheaten

You say that event0 was providing output:

N: Name="G20BTS Keyboard"
H: Handlers=sysrq kbd leds event0
TOKEN:        0   1   2    3

So you need to count. Hence I gave you this piece

if  'G20BTS Keyboard' in tokens[1]:
                dev_found = True
            if dev_found and 'Handlers' in tokens[0]:
                tokens = tokens[1].split(' ')
                infile_path = infile_path + tokens[3]

As you mention:

FileNotFoundError: [Errno 2] No such file or directory: ‘/dev/input/kbd’

Seems your code is still from the opening post:
infile_path = infile_path + tokens[1]
So it reads token[1] => kbd, but you need token[3] => event0

Many thanks, your right, I did not have the change you suggested entered correctly.
Unfortunately still no joy. I am going to take a break and then start over and go over everything very carefully. However I do feel I have it all correct.
It would be easier to just get a “JustBoom” remote, but here in Canada it is not available. I really am hoping I can get this going because it will increase my Volumio experience substantially! Maybe I have a directory problem. When I first ssh to Volumio, how do I navigate to /home/volumio?

The I would suggest to take the script form my post:

You only need to identify the buttons that populate event0

I’m sorry, I don’t know how to do all that. Thank you for all the help.
I don’t see a way forward, I checked everything and I don’t see anything wrong.
just doesn’t work. unless I’m suppose to have a screen installed. Could the problem be key codes? never did any changes there…

Anyways, I got triggerhappy working with this remote!!! so yeah. just started playing with it. but it looks like i can do what I want!

I bought another remote for my other system. it has the latest volumio image 3.6 but the remote never shows up when I do a scan on within bluetoothctl.
very frustrarting!

Actually it show up the first time from a fresh sd volumio image write. Fails to connect and then you never see it again unless you do a factory reset.

have you tried to use a BT remote that comes with a dongle?

No. I have not tried that.
So frustrating as I have this working on one of my systems.
Any idea why I have to do a factory reset between attempts to discover the remote.
I can see it on first boot of a fresh build, try to connect, fails most of the time, then you never see it again in the scan unless you do a factory reset.
Thanks for your suggestion.

maybe something like this?

is that what you had in mind? or give up on BT and go for a “just boom” remote ? kinda pricey…

You need to look for a remote that have the buttons you need. For me all the BT remotes I have (with dongle) just works.
like:

or:

Hmmm. I found these on the canadian website. Looks the same as what you have suggested.
Is this BT? How would I pair it and would it work with triggerhappy?
If it does, I’ll order it. txs is one better than the other? I just want volume control really…

no need to pair, they do it automatically, hence the dongle.
unfortunately I have no experience using triggerhappy, as I coded the BT receive response myself.
But I see no reason why this would fail.