2023-02-01 21:17:07

by Martin Petzold

[permalink] [raw]
Subject: How to Automatically Re-Connect Bluetooth HID over GATT (HOG) Device when BlueZ Plugin "hog" is Disabled

Hi,

Linux 5.10, BlueZ 5.55

I have a remote control which implements Bluetooth LE. If I use the
default Bluetooth daemon, I am able to pair and trust using
bluetoothctl. If the connection is lost after a while (or days) and a
button on the remote control is pressed, the daemon re-connects
automatically (because the device is paired). This is basically what I need.

But, I would also like to manually set notifying for characteristics
(Report) on the HID service within my application (Java via d-bus). This
is not possible anymore (also not via bluetoothctl) because the "hog"
(or "input") plugin manages the input device and the related HID
services are now hidden.

I then added "--noplugin=input,hog" to my Bluetooth daemon. Which is
okay, because I don't need this support for Kernel HID. Great, now the
HID services are available (also using bluetoothctl), but the peripheral
does not re-connect automatically any more. I always have to connect
manually first. I also have no signal on the d-bus when I press the
button of the remote control, when it is disconnected.

How can I enable automatic re-connect for devices, when these plugins
are disabled?

The only other way I was thinking of is to leave the "hog" plugin
enabled and use the operating system HID interface. However, my
application runs as non-root which makes it complicated and also I would
like to have direct connection and control to my device.

Thanks,

Martin



2023-02-01 21:37:56

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: How to Automatically Re-Connect Bluetooth HID over GATT (HOG) Device when BlueZ Plugin "hog" is Disabled

Hi Martin,

On Wed, Feb 1, 2023 at 1:25 PM Martin Petzold <[email protected]> wrote:
>
> Hi,
>
> Linux 5.10, BlueZ 5.55
>
> I have a remote control which implements Bluetooth LE. If I use the
> default Bluetooth daemon, I am able to pair and trust using
> bluetoothctl. If the connection is lost after a while (or days) and a
> button on the remote control is pressed, the daemon re-connects
> automatically (because the device is paired). This is basically what I need.
>
> But, I would also like to manually set notifying for characteristics
> (Report) on the HID service within my application (Java via d-bus). This
> is not possible anymore (also not via bluetoothctl) because the "hog"
> (or "input") plugin manages the input device and the related HID
> services are now hidden.
>
> I then added "--noplugin=input,hog" to my Bluetooth daemon. Which is
> okay, because I don't need this support for Kernel HID. Great, now the
> HID services are available (also using bluetoothctl), but the peripheral
> does not re-connect automatically any more. I always have to connect
> manually first. I also have no signal on the d-bus when I press the
> button of the remote control, when it is disconnected.
>
> How can I enable automatic re-connect for devices, when these plugins
> are disabled?
>
> The only other way I was thinking of is to leave the "hog" plugin
> enabled and use the operating system HID interface. However, my
> application runs as non-root which makes it complicated and also I would
> like to have direct connection and control to my device.

https://github.com/bluez/bluez/blob/master/doc/gatt-api.txt#L390

> Thanks,
>
> Martin
>


--
Luiz Augusto von Dentz

2023-02-09 09:19:09

by Martin Petzold

[permalink] [raw]
Subject: Re: How to Automatically Re-Connect Bluetooth HID over GATT (HOG) Device when BlueZ Plugin "hog" is Disabled

Hi Luiz,

Am 01.02.23 um 22:37 schrieb Luiz Augusto von Dentz:
> Hi Martin,
>
> On Wed, Feb 1, 2023 at 1:25 PM Martin Petzold <[email protected]> wrote:
>> Hi,
>>
>> Linux 5.10, BlueZ 5.55
>>
>> I have a remote control which implements Bluetooth LE. If I use the
>> default Bluetooth daemon, I am able to pair and trust using
>> bluetoothctl. If the connection is lost after a while (or days) and a
>> button on the remote control is pressed, the daemon re-connects
>> automatically (because the device is paired). This is basically what I need.
>>
>> But, I would also like to manually set notifying for characteristics
>> (Report) on the HID service within my application (Java via d-bus). This
>> is not possible anymore (also not via bluetoothctl) because the "hog"
>> (or "input") plugin manages the input device and the related HID
>> services are now hidden.
>>
>> I then added "--noplugin=input,hog" to my Bluetooth daemon. Which is
>> okay, because I don't need this support for Kernel HID. Great, now the
>> HID services are available (also using bluetoothctl), but the peripheral
>> does not re-connect automatically any more. I always have to connect
>> manually first. I also have no signal on the d-bus when I press the
>> button of the remote control, when it is disconnected.
>>
>> How can I enable automatic re-connect for devices, when these plugins
>> are disabled?
>>
>> The only other way I was thinking of is to leave the "hog" plugin
>> enabled and use the operating system HID interface. However, my
>> application runs as non-root which makes it complicated and also I would
>> like to have direct connection and control to my device.
> https://github.com/bluez/bluez/blob/master/doc/gatt-api.txt#L390
>
Thanks, I have implemented and registered the HID profile using
org.bluez.GattProfile1 and now the device (remote control) re-connects
automatically.

However, when I enable notifying on the Report characteristics of the
HID service after I received the first device properties update (with
services resolved), I miss the first Report event. If I press a button,
the remote re-connects and dbus events for device properties updated are
fine, but I don't have a Report event. If I then press again, I do get a
Report event, because I set notifying on the Report characteristics.
Setting notify seems to be too late.

What is the trick to get also the first button pressed as a Report
characteristic event?

At the moment I only have the HID service
(00001812-0000-1000-8000-00805f9b34fb) in the properties map of the
org.bluez.GattProfile1.

Thanks,

Martin

--
Martin Petzold (Inhaber & Geschäftsführer)

TAVLA Technology GmbH
Im Dau 14
50678 Köln
Deutschland

Telefon: +49 (0)221 / 3466 0885
Mobil: +49 (0)179 / 9220154
E-Mail: [email protected]


2023-03-30 18:33:41

by Martin Petzold

[permalink] [raw]
Subject: Re: How to Automatically Re-Connect Bluetooth HID over GATT (HOG) Device when BlueZ Plugin "hog" is Disabled

Dear Luiz,

I now have another issue with remote control HID integration
(non-system; direct implementation).

I am using Java with d-bus BlueZ 5.55 on Debian Linux. I have "hid" and
"input" plugin disabled on bluetooth startup.

I have one remote integrated and working. With this one after boot and
while application startup I iterate over all paired devices with
existing HID service (check for existing service UUID) and then iterate
all Report characteristics and enabling notifying for all of them (if
supported). Everything is running well with this (legacy) remote. After
pairing it also auto-connects using my own registered object manager, as
suggested by you.

Now we received our final custom remote control from our manufacturer
(other chip) and this approach does not work any more. I have tried a
lot of things now. Once the remote control is paired (which is also
somehow still buggy) and I rebooted the system with our application, the
device is found in the list as paired, BUT I cannot access the HID
service any more. Therefore, I cannot enable notifying for this remote.

What I realized is, that this remote control seems to have something
like MAC address randomization enabled (probably for security reasons).
It also does not propagate device information unless I start pairing
mode. Because of MAC address randomization it also seems that pairing is
buggy - only works sometimes with some special procedure.

I know this remote works, because if I connected in manually via
bluetoothctl sometimes I works with enabling of notifying. Also directly
after pairing it seemed to work.

Have you seen something like this before? What should I do?

Thanks,

Martin

Am 09.02.23 um 10:18 schrieb Martin Petzold:
> Hi Luiz,
>
> Am 01.02.23 um 22:37 schrieb Luiz Augusto von Dentz:
>> Hi Martin,
>>
>> On Wed, Feb 1, 2023 at 1:25 PM Martin Petzold
>> <[email protected]> wrote:
>>> Hi,
>>>
>>> Linux 5.10, BlueZ 5.55
>>>
>>> I have a remote control which implements Bluetooth LE. If I use the
>>> default Bluetooth daemon, I am able to pair and trust using
>>> bluetoothctl. If the connection is lost after a while (or days) and a
>>> button on the remote control is pressed, the daemon re-connects
>>> automatically (because the device is paired). This is basically what
>>> I need.
>>>
>>> But, I would also like to manually set notifying for characteristics
>>> (Report) on the HID service within my application (Java via d-bus).
>>> This
>>> is not possible anymore (also not via bluetoothctl) because the "hog"
>>> (or "input") plugin manages the input device and the related HID
>>> services are now hidden.
>>>
>>> I then added "--noplugin=input,hog" to my Bluetooth daemon. Which is
>>> okay, because I don't need this support for Kernel HID. Great, now the
>>> HID services are available (also using bluetoothctl), but the
>>> peripheral
>>> does not re-connect automatically any more. I always have to connect
>>> manually first. I also have no signal on the d-bus when I press the
>>> button of the remote control, when it is disconnected.
>>>
>>> How can I enable automatic re-connect for devices, when these plugins
>>> are disabled?
>>>
>>> The only other way I was thinking of is to leave the "hog" plugin
>>> enabled and use the operating system HID interface. However, my
>>> application runs as non-root which makes it complicated and also I
>>> would
>>> like to have direct connection and control to my device.
>> https://github.com/bluez/bluez/blob/master/doc/gatt-api.txt#L390
>>
> Thanks, I have implemented and registered the HID profile using
> org.bluez.GattProfile1 and now the device (remote control) re-connects
> automatically.
>
> However, when I enable notifying on the Report characteristics of the
> HID service after I received the first device properties update (with
> services resolved), I miss the first Report event. If I press a
> button, the remote re-connects and dbus events for device properties
> updated are fine, but I don't have a Report event. If I then press
> again, I do get a Report event, because I set notifying on the Report
> characteristics. Setting notify seems to be too late.
>
> What is the trick to get also the first button pressed as a Report
> characteristic event?
>
> At the moment I only have the HID service
> (00001812-0000-1000-8000-00805f9b34fb) in the properties map of the
> org.bluez.GattProfile1.
>
> Thanks,
>
> Martin
>

2023-03-30 18:36:49

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: How to Automatically Re-Connect Bluetooth HID over GATT (HOG) Device when BlueZ Plugin "hog" is Disabled

Hi Martin,

On Thu, Mar 30, 2023 at 11:16 AM Martin Petzold <[email protected]> wrote:
>
> Dear Luiz,
>
> I now have another issue with remote control HID integration
> (non-system; direct implementation).
>
> I am using Java with d-bus BlueZ 5.55 on Debian Linux. I have "hid" and
> "input" plugin disabled on bluetooth startup.
>
> I have one remote integrated and working. With this one after boot and
> while application startup I iterate over all paired devices with
> existing HID service (check for existing service UUID) and then iterate
> all Report characteristics and enabling notifying for all of them (if
> supported). Everything is running well with this (legacy) remote. After
> pairing it also auto-connects using my own registered object manager, as
> suggested by you.
>
> Now we received our final custom remote control from our manufacturer
> (other chip) and this approach does not work any more. I have tried a
> lot of things now. Once the remote control is paired (which is also
> somehow still buggy) and I rebooted the system with our application, the
> device is found in the list as paired, BUT I cannot access the HID
> service any more. Therefore, I cannot enable notifying for this remote.
>
> What I realized is, that this remote control seems to have something
> like MAC address randomization enabled (probably for security reasons).
> It also does not propagate device information unless I start pairing
> mode. Because of MAC address randomization it also seems that pairing is
> buggy - only works sometimes with some special procedure.
>
> I know this remote works, because if I connected in manually via
> bluetoothctl sometimes I works with enabling of notifying. Also directly
> after pairing it seemed to work.
>
> Have you seen something like this before? What should I do?

It is probably using the privacy (aka Resolvable Private Address/RPA),
there were quite a few fixes since 5.55 so you might want to update
your version to the latest to see if pairing works properly, note that
the D-Bus object might use the RPA address when it is first paired but
after that if you restart the daemon it will use the Identity Address,
so the any code using the device objects shall not attempt to store
and access the object based on their addresses since that can change
due to these conditions.

2023-03-30 19:16:34

by Martin Petzold

[permalink] [raw]
Subject: Re: How to Automatically Re-Connect Bluetooth HID over GATT (HOG) Device when BlueZ Plugin "hog" is Disabled

Am 30.03.23 um 20:25 schrieb Luiz Augusto von Dentz:
> Hi Martin,
>
> On Thu, Mar 30, 2023 at 11:16 AM Martin Petzold <[email protected]> wrote:
>> Dear Luiz,
>>
>> I now have another issue with remote control HID integration
>> (non-system; direct implementation).
>>
>> I am using Java with d-bus BlueZ 5.55 on Debian Linux. I have "hid" and
>> "input" plugin disabled on bluetooth startup.
>>
>> I have one remote integrated and working. With this one after boot and
>> while application startup I iterate over all paired devices with
>> existing HID service (check for existing service UUID) and then iterate
>> all Report characteristics and enabling notifying for all of them (if
>> supported). Everything is running well with this (legacy) remote. After
>> pairing it also auto-connects using my own registered object manager, as
>> suggested by you.
>>
>> Now we received our final custom remote control from our manufacturer
>> (other chip) and this approach does not work any more. I have tried a
>> lot of things now. Once the remote control is paired (which is also
>> somehow still buggy) and I rebooted the system with our application, the
>> device is found in the list as paired, BUT I cannot access the HID
>> service any more. Therefore, I cannot enable notifying for this remote.
>>
>> What I realized is, that this remote control seems to have something
>> like MAC address randomization enabled (probably for security reasons).
>> It also does not propagate device information unless I start pairing
>> mode. Because of MAC address randomization it also seems that pairing is
>> buggy - only works sometimes with some special procedure.
>>
>> I know this remote works, because if I connected in manually via
>> bluetoothctl sometimes I works with enabling of notifying. Also directly
>> after pairing it seemed to work.
>>
>> Have you seen something like this before? What should I do?
> It is probably using the privacy (aka Resolvable Private Address/RPA),
> there were quite a few fixes since 5.55 so you might want to update
> your version to the latest to see if pairing works properly, note that
> the D-Bus object might use the RPA address when it is first paired but
> after that if you restart the daemon it will use the Identity Address,
> so the any code using the device objects shall not attempt to store
> and access the object based on their addresses since that can change
> due to these conditions.
Okay, thanks. I will check new version somehow. Unfortunately I cannot
change Kernel (currently 5.10) because of several drivers, devices and
patches. I am not sure how to selectively update BlueZ and if this even
works. Debian package in sid seems to be 5.66, but aren't this only the
user space tools?

However, my object manager implementation is quite simple / dumb. There
is no relation to MAC in there (find code below).

Aren't the service and characteristics information stored in the file
system using the MAC address? This would explain, why they are not found
after the MAC address randomized.

-----

package technology.tavla.platform.os.runtime.core.system.bluetooth;

import java.util.HashMap;
import java.util.Map;

import org.freedesktop.dbus.DBusPath;
import org.freedesktop.dbus.interfaces.ObjectManager;
import org.freedesktop.dbus.types.Variant;

import
technology.tavla.platform.os.runtime.common.service.system.bus.BusManager.Bus;
import
technology.tavla.platform.os.runtime.common.service.system.bus.BusManager.BusException;
import
technology.tavla.platform.os.runtime.core.system.bluetooth.object.AbstractLocalObject;
import
technology.tavla.platform.os.runtime.core.system.bluetooth.object.LocalObject;
import
technology.tavla.platform.os.runtime.core.system.bluetooth.profile.HID;

public class LocalObjectManager extends AbstractLocalObject implements
ObjectManager {

    private Map<DBusPath, Map<String, Map<String, Variant<?>>>> objects
= new HashMap<DBusPath, Map<String, Map<String, Variant<?>>>>();

    private Map<String, Map<String, Variant<?>>> properties = new
HashMap<String, Map<String, Variant<?>>>();

    public LocalObjectManager(final Bus bus) throws BusException {
        super("/" + LocalObjectManager.class.getName().replace(".", "/"));

        bus.exportObject(this.getObjectPath(), this);

        HID profile = new HID();

        this.addObject(profile);

        bus.exportObject(profile.getObjectPath(), profile);
    }

    @Override
    public Map<DBusPath, Map<String, Map<String, Variant<?>>>>
GetManagedObjects() {
        return this.objects;
    }

    @Override
    public Map<String, Map<String, Variant<?>>> getProperties() {
        return this.properties;
    }

    public <T extends LocalObject> void addObject(T object) {
        this.objects.put(new DBusPath(object.getObjectPath()),
object.getProperties());
    }

}

-----

package technology.tavla.platform.os.runtime.core.system.bluetooth.profile;

import java.util.HashMap;
import java.util.Map;

import org.bluez.GattProfile1;
import org.freedesktop.dbus.types.Variant;

import
technology.tavla.platform.os.runtime.common.service.system.bluetooth.BluetoothManager.BluetoothService;

public class HID extends AbstractLocalProfile {

    private Map<String, Map<String, Variant<?>>> properties = new
HashMap<String, Map<String, Variant<?>>>();

    public HID() {
        super("/" + HID.class.getName().replace(".", "/"));

        Map<String, Variant<?>> map = new HashMap<>();

        map.put("UUIDs", new Variant<>(new String[] {
BluetoothService.Type.HUMAN_INTERFACE_DEVICE.getFullUUID()
        }));

        this.properties.put(GattProfile1.class.getName(), map);
    }

    @Override
    public void Release() {
        // TODO Auto-generated method stub

    }

    @Override
    public <A> A Get(String interfaceName, String key) {
        //return this.properties.get(interfaceName).get(key);
        return null;
    }

    @Override
    public <A> void Set(String interfaceName, String key, A value) {

    }

    @Override
    public Map<String, Variant<?>> GetAll(String interfaceName) {
        return this.properties.get(interfaceName);
    }

    @Override
    public Map<String, Map<String, Variant<?>>> getProperties() {
        return this.properties;
    }

}

-----

Best regards,

Martin