WebBluetoothCG / ble-test-peripheral-android

A BLE Peripheral Simulator App
https://play.google.com/store/apps/details?id=io.github.webbluetoothcg.bletestperipheral
Apache License 2.0
390 stars 129 forks source link

Battery service (180F) not available #95

Closed milesfrain closed 6 years ago

milesfrain commented 6 years ago

Not sure if this is a Linux/Chrome bug or related to #94. I'm running on Ubuntu 18.04 with Chrome. Heartrate test seems to work fine, so I'm confused why there are issues with Battery simulation.

I'm testing through this page: https://googlechrome.github.io/samples/web-bluetooth/battery-level.html Seeing the following "Live Output":

Requesting Bluetooth Device...
Connecting to GATT Server...
Getting Battery Service...
Argh! NotFoundError: No Services matching UUID 0000180f-0000-1000-8000-00805f9b34fb found in Device.

I found that exact 0000180f-... battery_service UUID in the android code here: https://github.com/WebBluetoothCG/ble-test-peripheral-android/blob/277fbf7c586d579a9d270d71f7891144dea5e4d5/app/src/main/java/io/github/webbluetoothcg/bletestperipheral/BatteryServiceFragment.java#L45

The reset energy app works: https://googlechrome.github.io/samples/web-bluetooth/reset-energy.html

Live output of:

Requesting Bluetooth Device...
Connecting to GATT Server...
Getting Heart Rate Service...
Getting Heart Rate Control Point Characteristic...
Writing Heart Rate Control Point Characteristic...
> Energy expended has been reset.

Which successfully resets the energy expended value to zero in the android app.

Trying to troubleshoot with bluetoothctl (Linux CLI utility). Seeing reasonable GATT listing "Heart Rate Control Point" (2A39) when opening the heartrate tab in the android app:

menu gatt
list-attributes
Primary Service
    /org/bluez/hci0/dev_65_56_A7_7E_47_2C/service0001
    00001801-0000-1000-8000-00805f9b34fb
    Generic Attribute Profile
Characteristic
    /org/bluez/hci0/dev_65_56_A7_7E_47_2C/service0001/char0002
    00002a05-0000-1000-8000-00805f9b34fb
    Service Changed
Primary Service
    /org/bluez/hci0/dev_65_56_A7_7E_47_2C/service0028
    0000180d-0000-1000-8000-00805f9b34fb
    Heart Rate
Characteristic
    /org/bluez/hci0/dev_65_56_A7_7E_47_2C/service0028/char0029
    00002a37-0000-1000-8000-00805f9b34fb
    Heart Rate Measurement
Descriptor
    /org/bluez/hci0/dev_65_56_A7_7E_47_2C/service0028/char0029/desc002b
    00002902-0000-1000-8000-00805f9b34fb
    Client Characteristic Configuration
Descriptor
    /org/bluez/hci0/dev_65_56_A7_7E_47_2C/service0028/char0029/desc002c
    00002901-0000-1000-8000-00805f9b34fb
    Characteristic User Description
Characteristic
    /org/bluez/hci0/dev_65_56_A7_7E_47_2C/service0028/char002d
    00002a38-0000-1000-8000-00805f9b34fb
    Body Sensor Location
Characteristic
    /org/bluez/hci0/dev_65_56_A7_7E_47_2C/service0028/char002f
    00002a39-0000-1000-8000-00805f9b34fb
    Heart Rate Control Point

But when switching over to the Battery tab, I don't see the battery service listed.

menu gatt
list-attributes
Primary Service
    /org/bluez/hci0/dev_5C_91_FB_35_1C_CE/service0001
    00001801-0000-1000-8000-00805f9b34fb
    Generic Attribute Profile
Characteristic
    /org/bluez/hci0/dev_5C_91_FB_35_1C_CE/service0001/char0002
    00002a05-0000-1000-8000-00805f9b34fb
    Service Changed

Upon a fresh connection, I do see the 180F battery status UUID logged with the [CHG] tag, but it does not persist with list-attributes.

[miles g5]# connect 5C:91:FB:35:1C:CE
Attempting to connect to 5C:91:FB:35:1C:CE
[CHG] Device 5C:91:FB:35:1C:CE Connected: yes
Connection successful
[CHG] Device 54:59:49:F9:57:73 ServicesResolved: no
[CHG] Device 54:59:49:F9:57:73 Connected: no
[DEL] Characteristic
    /org/bluez/hci0/dev_54_59_49_F9_57_73/service0001/char0002
    00002a05-0000-1000-8000-00805f9b34fb
    Service Changed
[DEL] Primary Service
    /org/bluez/hci0/dev_54_59_49_F9_57_73/service0001
    00001801-0000-1000-8000-00805f9b34fb
    Generic Attribute Profile
[DEL] Device 54:59:49:F9:57:73 miles g5
[NEW] Primary Service
    /org/bluez/hci0/dev_5C_91_FB_35_1C_CE/service0001
    00001801-0000-1000-8000-00805f9b34fb
    Generic Attribute Profile
[NEW] Characteristic
    /org/bluez/hci0/dev_5C_91_FB_35_1C_CE/service0001/char0002
    00002a05-0000-1000-8000-00805f9b34fb
    Service Changed
[CHG] Device 5C:91:FB:35:1C:CE UUIDs: 00001800-0000-1000-8000-00805f9b34fb
[CHG] Device 5C:91:FB:35:1C:CE UUIDs: 00001801-0000-1000-8000-00805f9b34fb
[CHG] Device 5C:91:FB:35:1C:CE UUIDs: 0000180f-0000-1000-8000-00805f9b34fb
[CHG] Device 5C:91:FB:35:1C:CE ServicesResolved: yes
g-ortuno commented 6 years ago

Sounds like BlueZ is not exposing the battery service. That usually happens when a BlueZ plugin claims the service. Maybe try disabling plugins?

milesfrain commented 3 years ago

Yep. Disabling the battery plugin worked. I couldn't figure out how to do that when you replied, but have since found the details in this SO answer. The solution is to edit /lib/systemd/system/bluetooth.service and add -P battery to end of bluetoothd:

ExecStart=/usr/lib/bluetooth/bluetoothd -P battery
dlech commented 3 years ago

FWIW, sudo systemctl edit bluetooth.service with the following contents will probably work better for most people.

[Service]
ExecStart=
ExecStart=-/usr/lib/bluetooth/bluetoothd -P battery

If changes are made directly to /lib/systemd/system/bluetooth.service, they will be overwritten whenever the bluez package is updated.

milesfrain commented 3 years ago

What is the reason for the empty assignment and the leading hyphen in the next line? Would this not work?

[Service]
ExecStart=/usr/lib/bluetooth/bluetoothd -P battery
dlech commented 3 years ago

Services allow more than one ExecStart, ExecStart= is a special case to say "don't run any previous ExecStart, only the new ones after this". So without it, the service will try to start bluetoothd twice.

https://www.freedesktop.org/software/systemd/man/systemd.service.html

milesfrain commented 3 years ago

Thanks for the link.

I'm still a bit confused about whether an "empty string" is considered "zero commands". I guess not, since that's disallowed with Type=dbus for bluez.

Here are the relevant nuggets from that manual:

Unless Type= is oneshot, exactly one command must be given. When Type=oneshot is used, zero or more commands may be specified. Commands may be specified by providing multiple command lines in the same directive, or alternatively, this directive may be specified more than once with the same effect. If the empty string is assigned to this option, the list of commands to start is reset, prior assignments of this option will have no effect.

If the executable path is prefixed with "-", an exit code of the command normally considered a failure (i.e. non-zero exit status or abnormal exit due to signal) is recorded, but has no further effect and is considered equivalent to success.

dlech commented 3 years ago

It is not an "empty" command, it means delete all previous commands. Since the dbus type can only have one command, we have to delete the old one before we can add a new one. In the end there is still exactly one command.