I'm running one of the Bluez examples on a raspberry pi 3 B+.

Output from using bluetoothctl then running show shows that some GATT services are available:

Name: raspberrypi
Alias: raspberrypi
Class: 0x400000
Powered: yes
Discoverable: no
Pairable: yes
UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control        (0000110e-0000-1000-8000-00805f9b34fb)
UUID: SIM Access                (0000112d-0000-1000-8000-00805f9b34fb)
UUID: Generic Access Profile    (00001800-0000-1000-8000-00805f9b34fb)
UUID: PnP Information           (00001200-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
UUID: Battery Service           (0000180f-0000-1000-8000-00805f9b34fb)
UUID: Heart Rate                (0000180d-0000-1000-8000-00805f9b34fb)
UUID: Vendor specific           (12345678-1234-5678-1234-56789abcdef0)
Modalias: usb:v1D6Bp0246d052B
Discovering: no

Discovering the services on an iPhone or a Mac will display the battery service, heart rate service and vendor specific service. On an Android device however only the Generic Attribute Profile and Generic Access Profile are found. Android devices used so far are a Motorola Moto G3, Sony Xperia XZ2 and a Huawei P20 Pro. Using LightBlue and BLE Scanner for service discovery.

Additional information

/lib/systemd/system/bluetooth.service has the --experimental flag set.

The Huawei phone has had no issues connecting to other bluetooth low energy devices in the past which leads me to think this isn't necessarily an Android problem.

Answering my own question here.

As described on this github issue: raspberry pi has a dual mode bluetooth chip. Android phone by default tries to connect using a classic mode. We must force Android to attempt to connect using low energy.

// Explicitly setting low energy mode is only available in later versions
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    m_gatt = m_bluetoothDevice.connectGatt(m_context, false, this, BluetoothDevice.TRANSPORT_LE);
}
else {
    try {
        // try private api access instead if we are below Marshmallow
        Method connectGattMethod = m_bluetoothDevice.getClass().getMethod("connectGatt", Context.class, boolean.class, BluetoothGattCallback.class, int.class);
        m_gatt = (BluetoothGatt)connectGattMethod.invoke(m_bluetoothDevice, m_context, false, this, 2);
    } 
    catch (Exception e) {
        // Ok, we can't get private api access. Let's just use the normal method and hope for the best
        m_gatt = m_bluetoothDevice.connectGatt(m_context, false, this);
    }
}

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.