API#

Client#

BluetoothDispatcher#

class able.BluetoothDispatcher(queue_timeout: float = 0.5, enable_ble_code: int = 43806, runtime_permissions: Optional[list[str]] = None)[source]#

Bluetooth Low Energy interface

Parameters
  • queue_timeout – BLE operations queue timeout

  • enable_ble_code – request code to identify activity that alows user to turn on Bluetooth adapter

  • runtime_permissions – overridden list of permissions to be requested on runtime.

property adapter: Optional[android.bluetooth.BluetoothAdapter]#

Local device Bluetooth adapter. Could be None if adapter is not enabled or access to the adapter is not granted yet.

Type

BluetoothAdapter Java object

property bonded_devices#

List of Java android.bluetooth.BluetoothDevice objects of paired BLE devices.

Type

List[BluetoothDevice]

close_gatt()#

Close current GATT client

connect_by_device_address(address: str)#

Connect to GATT Server of the device with a given Bluetooth hardware address, without scanning.

Parameters

address – Bluetooth hardware address string in “XX:XX:XX:XX:XX:XX” format

Raises

ValueError: if address is not a valid Bluetooth address

connect_gatt(device)#

Connect to GATT Server hosted by device

discover_services()#

Discovers services offered by a remote device. The status of the discovery reported with services event.

Returns

true, if the remote services discovery has been started

enable_notifications(characteristic, enable=True, indication=False)#

Enable/disable notifications or indications for a given characteristic

Parameters
  • characteristic – BluetoothGattCharacteristic Java object

  • enable – enable notifications if True, else disable notifications

  • indication – handle indications instead of notifications

Returns

True, if the operation was initiated successfully

property gatt#

GATT profile of the connected device

Type

BluetoothGatt Java object

property name#

Name of the Bluetooth adapter.

Setter

Set name of the Bluetooth adapter

Type

Optional[str]

on_characteristic_changed(characteristic)#

characteristic_changed event handler

Parameters

characteristic – BluetoothGattCharacteristic Java object

on_characteristic_read(characteristic, status)#

characteristic_read event handler

Parameters
  • characteristic – BluetoothGattCharacteristic Java object

  • status – status of the operation, GATT_SUCCESS if the operation succeeds

on_characteristic_write(characteristic, status)#

characteristic_write event handler

Parameters
  • characteristic – BluetoothGattCharacteristic Java object

  • status – status of the operation, GATT_SUCCESS if the operation succeeds

on_connection_state_change(status, state)#

connection_state_change event handler

Parameters
  • status – status of the operation, GATT_SUCCESS if the operation succeeds

  • state – STATE_CONNECTED or STATE_DISCONNECTED

on_descriptor_read(descriptor, status)#

descriptor_read event handler

Parameters
  • descriptor – BluetoothGattDescriptor Java object

  • status – status of the operation, GATT_SUCCESS if the operation succeeds

on_descriptor_write(descriptor, status)#

descriptor_write event handler

Parameters
  • descriptor – BluetoothGattDescriptor Java object

  • status – status of the operation, GATT_SUCCESS if the operation succeeds

on_device(device, rssi, advertisement)#

device event handler. Event is dispatched when device is found during a scan.

Parameters
  • device – BluetoothDevice Java object

  • rssi – the RSSI value for the remote device

  • advertisementAdvertisement data record

on_error(msg)#

Error handler

Parameters

msg – error message

on_gatt_release()#

gatt_release event handler. Event is dispatched at every read/write completed operation

on_mtu_changed(mtu, status)#

onMtuChanged event handler Event is dispatched when MTU for a remote device has changed, reporting a new MTU size.

Parameters
  • mtu – integer containing the new MTU size

  • status – status of the operation, GATT_SUCCESS if the MTU has been changed successfully

on_rssi_updated(rssi, status)#

onReadRemoteRssi event handler. Event is dispatched at every RSSI update completed operation, reporting a RSSI value for a remote device connection.

Parameters
  • rssi – integer containing RSSI value in dBm

  • status – status of the operation, GATT_SUCCESS if the operation succeeds

on_scan_completed()#

scan_completed event handler

on_scan_started(success)#

scan_started event handler

Parameters

success – true, if scan was started successfully

on_services(services, status)#

services event handler

Parameters
  • servicesServices dict filled with discovered characteristics (BluetoothGattCharacteristic Java objects)

  • status – status of the operation, GATT_SUCCESS if the operation succeeds

read_characteristic(characteristic)#

Read a given characteristic from the associated remote device

Parameters

characteristic – BluetoothGattCharacteristic Java object

request_mtu(mtu: int)#

Request to change the ATT Maximum Transmission Unit value

Parameters

value – new MTU size

set_queue_timeout(timeout)#

Change the BLE operations queue timeout

start_scan(filters: Optional[List[able.filters.Filter]] = None, settings: Optional[able.scan_settings.ScanSettingsBuilder] = None)#

Start a scan for devices. The status of the scan start are reported with scan_started event.

Parameters
  • filters – list of filters to restrict scan results. Advertising record is considered matching the filters if it matches any of the able.filters.Filter in the list.

  • settings – scan settings

stop_scan()#

Stop the ongoing scan for devices.

update_rssi()#

Triggers an update for the RSSI from the associated remote device

write_characteristic(characteristic, value, write_type: Optional[able.WriteType] = None)#

Write a given characteristic value to the associated remote device

Parameters
  • characteristic – BluetoothGattCharacteristic Java object

  • value – value to write

  • write_type – specific write type to set for the characteristic

write_descriptor(descriptor, value)#

Set and write the value of a given descriptor to the associated remote device

Parameters
  • descriptor – BluetoothGattDescriptor Java object

  • value – value to write

Decorators#

able.require_bluetooth_enabled(method)[source]#

Decorator to call BluetoothDispatcher method when runtime permissions are granted and Bluetooth adapter becomes ready.

Decorator launches system activities that allows the user to grant runtime permissions and turn on Bluetooth, if Bluetooth is not enabled.

Services#

class able.Services[source]#

Services dict

>>> services = Services({'service0': {'c1-aa': 0, 'aa-c2-aa': 1},
...                      'service1': {'bb-c3-bb': 2}})
>>> services.search('c3')
2
>>> services.search('c4')
search(pattern, flags=RegexFlag.IGNORECASE)[source]#

Search for characteristic by pattern

Parameters
  • pattern – regexp pattern

  • flags – regexp flags, re.IGNORECASE by default

Constants#

able.GATT_SUCCESS = 0#

GATT operation completed successfully

able.STATE_CONNECTED = 2#

The profile is in connected state

able.STATE_DISCONNECTED = 0#

The profile is in disconnected state

class able.AdapterState(value)[source]#

Bluetooth adapter state constants. https://developer.android.com/reference/android/bluetooth/BluetoothAdapter#STATE_OFF

OFF = 10#

Adapter is off

TURNING_ON = 11#

Adapter is turning on

ON = 12#

Adapter is on

TURNING_OFF = 13#

Adapter is turning off

class able.WriteType(value)[source]#

GATT characteristic write types constants.

SIGNED = 4#

Write characteristic including authentication signature

Permissions#

Before executing, all BluetoothDispatcher methods that requires Bluetooth adapter (start_scan, connect_by_device_address, enable_notifications, adapter property …), are asking the user to:

  1. grant runtime permissions,

  2. turn on Bluetooth adapter.

The list of requested runtime permissions varies depending on the level of the target Android API level:

  • target API level <=30: ACCESS_FINE_LOCATION - to obtain BLE scan results

  • target API level >= 31:

    • BLUETOOTH_CONNECT - to enable adapter and to connect to devices

    • BLUETOOTH_SCAN - to start the scan

    • ACCESS_FINE_LOCATION - to detect beacons during the scan

    • BLUETOOTH_ADVERTISE - to be able to advertise to nearby Bluetooth devices

Requested permissions list can be changed with the BluetoothDispatcher.runtime_permissions parameter.

class able.Permission[source]#

String constants values for BLE-related permissions. https://developer.android.com/reference/android/Manifest.permission

ACCESS_BACKGROUND_LOCATION = 'android.permission.ACCESS_BACKGROUND_LOCATION'#
ACCESS_FINE_LOCATION = 'android.permission.ACCESS_FINE_LOCATION'#
BLUETOOTH_ADVERTISE = 'android.permission.BLUETOOTH_ADVERTISE'#
BLUETOOTH_CONNECT = 'android.permission.BLUETOOTH_CONNECT'#
BLUETOOTH_SCAN = 'android.permission.BLUETOOTH_SCAN'#

Scan settings#

BLE scanning settings.

class able.scan_settings.ScanSettingsBuilder[source]#

PyJNIus wrapper for Java class android.bluetooth.le.ScanSettings.Builder. https://developer.android.com/reference/android/bluetooth/le/ScanSettings.Builder

class able.scan_settings.ScanSettings[source]#

PyJNIus wrapper for Java class android.bluetooth.le.ScanSettings. https://developer.android.com/reference/android/bluetooth/le/ScanSettings

>>> settings = ScanSettingsBuilder() \
...  .setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE) \
...  .setCallbackType(
...     ScanSettings.CALLBACK_TYPE_FIRST_MATCH |
...     ScanSettings.CALLBACK_TYPE_MATCH_LOST
...   )

Scan filters#

BLE scanning filters, wrappers for Java class android.bluetooth.le.ScanFilter.Builder https://developer.android.com/reference/android/bluetooth/le/ScanFilter.Builder

class able.filters.Filter[source]#

Bases: object

Base class for BLE scanning fiters.

>>> # Filters of different kinds could be ANDed to set multiple conditions.
>>> # Both device name and address required:
>>> combined_filter = DeviceNameFilter("Example") & DeviceAddressFilter("01:02:03:AB:CD:EF")
>>> DeviceNameFilter("Example1") & DeviceNameFilter("Example2")
Traceback (most recent call last):
ValueError: cannot combine filters of the same type
class able.filters.EmptyFilter[source]#

Bases: able.filters.Filter

Filter with no restrictions.

class able.filters.DeviceAddressFilter(address: str)[source]#

Bases: able.filters.Filter

Set filter on device address. Uses Java method ScanFilter.Builder.setDeviceAddress.

Parameters

address – Address in the format of “01:02:03:AB:CD:EF”

>>> DeviceAddressFilter("01:02:03:AB:CD:EF")
DeviceAddressFilter(address='01:02:03:AB:CD:EF')
class able.filters.DeviceNameFilter(name: str)[source]#

Bases: able.filters.Filter

Set filter on device name. Uses Java method ScanFilter.Builder.setDeviceName.

Parameters

name – Device name

class able.filters.ManufacturerDataFilter(id: int, data: typing.Union[list, tuple, bytes, bytearray], mask: typing.List[int] = <factory>)[source]#

Bases: able.filters.Filter

Set filter on manufacture data. Uses Java method ScanFilter.Builder.setManufacturerData.

Parameters
  • id – Manufacturer ID

  • data – Manufacturer specific data

  • mask – bit mask for partial filtration of the data. For any bit in the mask, set it to 1 if it needs to match the one in manufacturer data, otherwise set it to 0 to ignore that bit.

>>> # Filter by just ID, ignoring the data:
>>> ManufacturerDataFilter(0x0AD0, [])
ManufacturerDataFilter(id=2768, data=[], mask=None)
>>> ManufacturerDataFilter(0x0AD0, [0x2, 0x15, 0x8d])
ManufacturerDataFilter(id=2768, data=[2, 21, 141], mask=None)
>>> # With mask set to ignore the second data byte:
>>> ManufacturerDataFilter(0x0AD0, [0x2, 0, 0x8d], [0xff, 0, 0xff])
ManufacturerDataFilter(id=2768, data=[2, 0, 141], mask=[255, 0, 255])
>>> ManufacturerDataFilter(0x0AD0, [0x2, 21, 0x8d], [0xff])
Traceback (most recent call last):
ValueError: mask is shorter than the data
class able.filters.ServiceDataFilter(uid: str, data: typing.Union[list, tuple, bytes, bytearray], mask: typing.List[int] = <factory>)[source]#

Bases: able.filters.Filter

Set filter on service data. Uses Java method ScanFilter.Builder.setServiceData.

Parameters
  • uid – UUID of the service in the format of “0000180f-0000-1000-8000-00805f9b34fb”

  • data – service data

  • mask – bit mask for partial filtration of the data. For any bit in the mask, set it to 1 if it needs to match the one in service data, otherwise set it to 0 to ignore that bit.

>>> ServiceDataFilter("0000180f-0000-1000-8000-00805f9b34fb", [])
ServiceDataFilter(uid='0000180f-0000-1000-8000-00805f9b34fb', data=[], mask=None)
>>> # With mask set to ignore the first data byte:
>>> ServiceDataFilter("0000180f-0000-1000-8000-00805f9b34fb", [0, 0x11], [0, 0xff])
ServiceDataFilter(uid='0000180f-0000-1000-8000-00805f9b34fb', data=[0, 17], mask=[0, 255])
>>> ServiceDataFilter("0000180f", [])
Traceback (most recent call last):
ValueError: badly formed hexadecimal UUID string
>>> ServiceDataFilter("0000180f-0000-1000-8000-00805f9b34fb", [0x12, 0x34], [0xff])
Traceback (most recent call last):
ValueError: mask is shorter than the data
class able.filters.ServiceSolicitationFilter(uid: str)[source]#

Bases: able.filters.Filter

Set filter on service solicitation uuid. Uses Java method ScanFilter.Builder.setServiceSolicitation.

Parameters

uid – UUID of the service in the format of “0000180f-0000-1000-8000-00805f9b34fb”

class able.filters.ServiceUUIDFilter(uid: str, mask: Optional[str] = None)[source]#

Bases: able.filters.Filter

Set filter on service uuid. Uses Java method ScanFilter.Builder.setServiceUuid.

Parameters

uid – UUID of the service in the format of “0000180f-0000-1000-8000-00805f9b34fb”

Mask

bit mask for partial filtration of the UUID, in the format of “ffffffff-0000-0000-0000-ffffffffffff”. Set any bit in the mask to 1 to indicate a match is needed for the bit in uid, and 0 to ignore that bit.

>>> ServiceUUIDFilter('16fe0d00-c111-11e3-b8c8-0002a5d5c51b')
ServiceUUIDFilter(uid='16fe0d00-c111-11e3-b8c8-0002a5d5c51b', mask=None)
>>> ServiceUUIDFilter(
... '16fe0d00-c111-11e3-b8c8-0002a5d5c51b',
... 'ffffffff-0000-0000-0000-000000000000'
... )  
ServiceUUIDFilter(uid='16fe0d00-...', mask='ffffffff-...')
>>> ServiceUUIDFilter('123')
Traceback (most recent call last):
ValueError: badly formed hexadecimal UUID string

Advertising#

BLE advertise operations.

Advertiser#

class able.advertising.Advertiser(ble: able.android.dispatcher.BluetoothDispatcher, data: Optional[able.advertising.AdvertiseData] = None, scan_data: Optional[able.advertising.AdvertiseData] = None, interval: int = Interval.HIGH, tx_power: int = TXPower.MEDIUM)[source]#

Base class for BLE advertise operations.

Parameters
>>> Advertiser(
...            ble=BluetoothDispatcher(),
...            data=AdvertiseData(DeviceName()),
...            scan_data=AdvertiseData(TXPowerLevel()),
...            interval=Interval.MIN,
...            tx_power=TXPower.MAX
... ) 
<able.advertising.Advertiser object at 0x...>
property data#
Setter

Update advertising data

Type

Optional[AdvertiseData]

property scan_data#
Setter

Update the scan response

Type

Optional[AdvertiseData]

property interval#
Setter

Update the advertising interval

Type

int

property tx_power#
Setter

Update the transmission power level

Type

int

start()[source]#

Start advertising.

Start a system activity that allows the user to turn on Bluetooth if Bluetooth is not enabled.

stop()[source]#

Stop advertising.

on_advertising_started(advertising_set: jnius.autoclass('android.bluetooth.le.AdvertisingSet'), tx_power: int, status: able.advertising.Status)[source]#

Handler for advertising start operation (onAdvertisingSetStarted).

on_advertising_stopped(advertising_set: jnius.autoclass('android.bluetooth.le.AdvertisingSet'))[source]#

Handler for advertising stop operation (onAdvertisingSetStopped).

on_advertising_enabled(advertising_set: jnius.autoclass('android.bluetooth.le.AdvertisingSet'), enable: bool, status: able.advertising.Status)[source]#

Handler for advertising enable/disable operation (onAdvertisingEnabled).

on_advertising_data_set(advertising_set: jnius.autoclass('android.bluetooth.le.AdvertisingSet'), status: able.advertising.Status)[source]#

Handler for data set operation (onAdvertisingDataSet).

on_scan_response_data_set(advertising_set: jnius.autoclass('android.bluetooth.le.AdvertisingSet'), status: able.advertising.Status)[source]#

Handler for scan response data set operation (onScanResponseDataSet).

on_advertising_parameters_updated(advertising_set: jnius.autoclass('android.bluetooth.le.AdvertisingSet'), tx_power: int, status: able.advertising.Status)[source]#

Handler for parameters set operation (onAdvertisingParametersUpdated).

Payload#

class able.advertising.AdvertiseData(*payload: List[able.advertising.ADStructure])[source]#

Builder for data payload to be advertised.

Parameters

payload – List of AD structures to include in advertisement

>>> AdvertiseData(DeviceName(), ManufacturerData(10, b'specific data'))
[DeviceName(), ManufacturerData(id=10, data=b'specific data')]
class able.advertising.DeviceName[source]#

Bases: able.advertising.ADStructure

Include device name (complete local name) in advertise packet.

class able.advertising.TXPowerLevel[source]#

Bases: able.advertising.ADStructure

Include transmission power level in the advertise packet.

class able.advertising.ServiceUUID(uid: str)[source]#

Bases: able.advertising.ADStructure

Service UUID to advertise.

Parameters

uid – UUID to be advertised

class able.advertising.ServiceData(uid: str, data: Union[list, tuple, bytes, bytearray])[source]#

Bases: able.advertising.ADStructure

Service data to advertise.

Parameters
  • uid – UUID of the service the data is associated with

  • data – Service data

class able.advertising.ManufacturerData(id: int, data: Union[list, tuple, bytes, bytearray])[source]#

Bases: able.advertising.ADStructure

Manufacturer specific data to advertise.

Parameters
  • id – Manufacturer ID

  • data – Manufacturer specific data

Constants#

class able.advertising.Interval(value)[source]#

Advertising interval constants. https://developer.android.com/reference/android/bluetooth/le/AdvertisingSetParameters#INTERVAL_HIGH

MIN = 160#

Minimum value for advertising interval, around every 100ms

MEDIUM = 400#

Advertise on medium frequency, around every 250ms

HIGH = 1600#

Advertise on low frequency, around every 1000ms

MAX = 16777215#

Maximum value for advertising interval

class able.advertising.TXPower(value)[source]#

Advertising transmission (TX) power level constants. https://developer.android.com/reference/android/bluetooth/le/AdvertisingSetParameters#TX_POWER_HIGH

MIN = -127#

Minimum value for TX power

ULTRA_LOW = -21#

Advertise using the lowest TX power level

LOW = -15#

Advertise using the low TX power level

MEDIUM = -7#

Advertise using the medium TX power level

MAX = 1#

Maximum value for TX power

class able.advertising.Status[source]#

Advertising operation status constants. https://developer.android.com/reference/android/bluetooth/le/AdvertisingSetCallback#constants

SUCCESS = 0#
DATA_TOO_LARGE = 1#
TOO_MANY_ADVERTISERS = 2#
ALREADY_STARTED = 3#
INTERNAL_ERROR = 4#
FEATURE_UNSUPPORTED = 5#