Issue
Trying to communicate with a BLE device (smart lamp).
I use the following dependency:
<dependency>
<groupId>com.github.hypfvieh</groupId>
<artifactId>bluez-dbus</artifactId>
<version>0.1.3</version>
</dependency>
Very interesting library, by far the best I have found so far for BLE, in term of code quality, dependency management, and clarity...
The problem is, I have a working gatttool command like this, running on a Raspberry Pi 4:
gatttool --device=C4:AC:05:42:73:A4 -t random --char-write-req -a 0x1f -n a001037F
... which set the brightness of the lamp to 100%. Note the value of the address (ie. "-a 0x1f"), which corresponds to the attribute "char value handle" in gattool "characteristics":
handle: 0x001e, char properties: 0x28, char value handle: **0x001f**, uuid: **44092842-0567-11e6-b862-0002a5d5c51b**
I try to make the same using bluez-dbus in java. My implementation seems correct, but the lamp doesn't respond. I have the following trace with dbus-monitor :
method call time=1600276508.729104 sender=:1.184 -> destination=org.bluez serial=210 path=/org/bluez/hci0/dev_C4_AC_05_42_73_A4/service001d/**char001e**; interface=org.bluez.GattCharacteristic1; member=WriteValue
array of bytes [
0a 01 03 7f
]
array [
]
method return time=1600276508.776261 sender=:1.5 -> destination=:1.184 serial=6589 reply_serial=210
It looks everything is fine except bluez-dbus pick up the value 0x001e (aka. the "handle" in gatttool characteristics), to drive the lamp, where it should have been 0x001f ("char value handle" in gatttool).
Do you know if this is a bad usage of the library, an error on the device, or what ?
Here is a little excerpt of the code, if you need more you can look here: https://github.com/sebpiller/luke-roberts-lamp-f
BluetoothDevice lampF = manager.getDevices(true)
.stream()
.filter(e -> Objects.equals(e.getAddress(), config.getMac()))
.findFirst()
.get();
....
String uuid = config.getCustomControlService().getUuid();
BluetoothGattService customControlService = Objects.requireNonNull(lampF.getGattServiceByUuid(uuid));
LOG.info("found GATT custom control service {} at UUID {}", customControlService, uuid);
....
String externalApiUuid = config.getCustomControlService().getUserExternalApiEndpoint().getUuid();
externalApi = Objects.requireNonNull(customControlService.getGattCharacteristicByUuid(externalApiUuid));
...
private void sendCommandToExternalApi(LukeRoberts.LampF.Command command, Byte... parameters) {
reconnectIfNeeded();
try {
externalApi.writeValue(/*reversed*/ command.toByteArray(parameters), Collections.emptyMap());
} catch (DBusException e) {
throw new IllegalStateException("unable to change brightness: " + e, e);
}
}
Thanks for your time !
EDIT:
I am an idiotic-dyslexic. 0x0a is not the same as 0xa0.
Sometimes I'd like to crush my head on the wall....
Thanks for your help :)
Solution
gattool is one of the eight tools that have been deprecated by BlueZ.
To debug this I would advise using bluetoothctl
to workout what the correct paths are for the connected device. A session might look like this:
pi@raspberrypi:~ $ bluetoothctl
[bluetooth]# connect C4:AC:05:42:73:A4
[my lamp]# menu gatt
[my lamp]# select-attribute 44092842-0567-11e6-b862-0002a5d5c51b
[my lamp:/service0032/char0036]# write 0xa0 0x01 0x03 0x7F
Attempting to write /org/bluez/hci0/dev_C4_AC_05_42_73_A4/service0032/char0036
On the command line, to show you all the paths can be done with generic D-Bus tools:
pi@raspberrypi:~ $ busctl tree org.bluez
Once you have the paths then you can do it from the command line with D-Bus.
pi@raspberrypi:~ $ busctl call org.bluez /org/bluez/hci0/dev_DE_82_35_E7_43_BE org.bluez.Device1 Connect
pi@raspberrypi:~ $ busctl call org.bluez /org/bluez/hci0/dev_DE_82_35_E7_43_BE/service0032/char0036 org.bluez.GattCharacteristic1 WriteValue aya{sv} 4 0xa0 0x01 0x03 0x7f 0
Hopefully with the knowledge from these experiments you can better understand what is going on with the Java application.
Answered By - ukBaz