Android Bluetooth Low Energy functions

BLE functions could be used with the able library.

%load_ext pythonhere
%connect-there
%%there
from kivy.logger import Logger
from able import BluetoothDispatcher, GATT_SUCCESS

BLE dispatcher callbacks results should be printed in logs:

%there -b log

Setup BLE interface

with logging callbacks

%%there
class BLE(BluetoothDispatcher):

    def on_connection_state_change(self, status, state):
        Logger.info("on_connection_state_change: status=%s, state=%s", status, state)
        if status == GATT_SUCCESS and state:
            Logger.info("Connection: succeed")

    def on_services(self, status, services):
        Logger.info("on_services: status=%s", status)
        if status == GATT_SUCCESS:
            Logger.info("services discovered: %s", list(services.keys()))
            # save discovered services object
            self.services = services

    def on_characteristic_read(self, characteristic, status):
        Logger.info("on_characteristic_read: status=%s, characteristic=%s", status,
                    characteristic.getUuid().toString())
        if status == GATT_SUCCESS:
            Logger.info("Characteristic read: succeed")


ble = BLE()
print(ble)
<BLE object at 0xd16151b0>

Get list of paired BLE devices

%%there
for device in ble.bonded_devices:
    # device: https://developer.android.com/reference/android/bluetooth/BluetoothDevice
    print(type(device), device.getName(), "address:", device.getAddress())
<class 'jnius.reflect.android.bluetooth.BluetoothDevice'> Amazfit Bip Watch address: BB:BB:BB:BB:BB:11

Connect to remote device by a hardware address

In this example device hardware address address is known.

%%there
ble.connect_by_device_address("AA:AA:AA:AA:AA:11")

Discover device services and characteristics

Wait a while, while device is connected. Start services discovery:

%%there -d 5
ble.discover_services()

Wait a while, while services discovered. Print connected device characteristics:

%%there -d 2
print(type(ble.services))
for service, characteristics in ble.services.items():
    print(f"Service {service} characteristics:")
    for characteristic in characteristics:
        print(f"\t*{characteristic}")
<class 'able.structures.Services'>
Service 16fe0d00-c111-11e3-b8c8-0002a5d5c51b characteristics:
	*16fe0d01-c111-11e3-b8c8-0002a5d5c51b
	*16fe0d02-c111-11e3-b8c8-0002a5d5c51b
	*16fe0d03-c111-11e3-b8c8-0002a5d5c51b
	*16fe0d04-c111-11e3-b8c8-0002a5d5c51b
	*16fe0d05-c111-11e3-b8c8-0002a5d5c51b

Read characteristic

In this example, it is known that target device has characteristic with UUID = 16fe0d01-c111-11e3-b8c8-0002a5d5c51b
This characteristic is readable, and always returns a string value: “test”.

%%there
characteristic = ble.services.search("0d01")  
print(f"Characteristic UUID found: {characteristic.getUuid().toString()}")
print(f"Characteristic object: {characteristic}")
# https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic#getStringValue(int)
print(f"Characteristic value is not available yet: {characteristic.getStringValue(0)}")

ble.read_characteristic(characteristic)
Characteristic UUID found: 16fe0d01-c111-11e3-b8c8-0002a5d5c51b
Characteristic object: <android.bluetooth.BluetoothGattCharacteristic at 0xd164e550 jclass=android/bluetooth/BluetoothGattCharacteristic jself=<LocalRef obj=0x65d6 at 0xcdfa3ef0>>
Characteristic value is not available yet: None

Wait a while, and check characteristic value.
on_characteristic_read message should appear in logs

%%there -d 2
# https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic#getStringValue(int)
print(characteristic.getStringValue(0))
test