flutter_reactive_ble 1.0.0+1 flutter_reactive_ble: ^1.0.0+1 copied to clipboard
Reactive Bluetooth low energy (BLE) plugin that can communicate with multiple devices
Flutter reactive BLE library #
Flutter library that handles BLE operations for multiple devices.
Work in progress #
The library is feature complete but we are working at the moment on improving documentation and the example app.
Usage #
The reactive BLE lib supports the following:
- BLE device discovery
- Establishing a BLE connection
- Maintaining connection status of multiple BLE devices
- Discover services(will be implicit)
- Read / write a characteristic
- Subscribe to a characteristic
- Clear GATT cache
- Negotiate MTU size
Device discovery #
Discovering BLE devices should be done like this:
reactivebleclient.scanForDevices(withService: uuid, scanMode: ScanMode.lowLatency).listen((device) {
//code for handling results
}, onError: () {
//code for handling error
});
The withservice
parameter is required. The parameter scanmode
is only used in Android and follows the conventions
described in Android scansettings reference.
If no scanmode is specified the library will use the balanced scanmode as reference.
Establishing connection #
To interact with a device you first need to establish a connection:
reactiveBleClient.connectToDevice(
id: 'AA:BB:CC:DD:EE:FF',
servicesWithCharacteristicsToDiscover: {serviceUuid: [char1, char2]},
connectionTimeout: const Duration(seconds: 2),
).listen((connectionUpdate) {
//code to handle connection update
}, onError: (dynamic error) {
//code to handle error
});
Use for the required id parameter the device id retrieved from device discovery. For iOS this should be a UUID and for Android thisis a MAC address. When first writing or reading a BLE characteristic after establishing a connection it can take a while because the BLE stack needs to discover all services. When supplying a map with services and characteristic UUIDs you want to discover, you can speedup the usage of those services because they will be discovered when establishing a connection. This functionality is only supported by iOS. You can specify a connectionTimeout
when the client will provide an error in case the connection cannot be established within the specified time. However this does not mean that the client has cancelled the connection request on the level of the BLE stack.
There are numerous issues on the Android BLE stack that leave it hanging when you try to connect to a device that is not in range. To work around this
issue use the method connectToAdvertisingDevice
to first scan for the device and when it is found connect to it.
reactiveBleClient.connectToAdvertisingDevice(
id: 'AA:BB:CC:DD:EE:FF',
withService: serviceUuid,
prescanDuration: const Duration(seconds: 5),
servicesWithCharacteristicsToDiscover: {serviceUuid: [char1, char2]},
connectionTimeout: const Duration(seconds: 2),
).listen((connectionUpdate) {
//code to handle connection update
}, onError: (dynamic error) {
//code to handle error
});
Besides the normal connection parameters that are described at above this function also has 2 additional required parameters: withService
and prescanDuration
. PreScanDuration is the amount of time the ble stack will scan for the device before it attempts to connect (if the device is found)
Read / write characteristics #
Read characteristic
final characteristic = QualifiedCharacteristic(serviceId: serviceUuid, characteristicId: characteristicUuid, deviceId: 'AA:BB:CC:DD:EE:FF');
final response = await reactiveBleClient.readCharacteristic(characteristic);
Write with response
Write a value to characteristic and await the reaponse. The return value is a List<Int>
.
final characteristic = QualifiedCharacteristic(serviceId: serviceUuid, characteristicId: characteristicUuid, deviceId: 'AA:BB:CC:DD:EE:FF');
final response = await reactiveBleClient.writeCharacteristicWithResponse(characteristic, value: [0x00]);
Write without response
Use this operation if you want to execute multiple consecutive write operations in a small timeframe (e.g uploading firmware to device) or if the device does not provide a response. This is performance wise the fastest way of writing a value but there's a chance that the BLE device cannot handle that many consecutive writes in a row so it is recommended to do a writeWithResponse
each x times.
final characteristic = QualifiedCharacteristic(serviceId: serviceUuid, characteristicId: characteristicUuid, deviceId: 'AA:BB:CC:DD:EE:FF');
reactiveBleClient.writeCharacteristicWithoutResponse(characteristic, value: [0x00]);
Subscribe to characteristic #
Instead of periodically reading the characteristic you can also listen to the notifications (in case the specific service supports it) in case the value changes.
final characteristic = QualifiedCharacteristic(serviceId: serviceUuid, characteristicId: characteristicUuid, deviceId: 'AA:BB:CC:DD:EE:FF');
reactiveBleClient.subscribeToCharacteristic(characteristic).listen((data) {
// code to handle incoming data
}, onError: (dynamic error) {
// code to handle errors
});
Negotiate MTU size #
You can increase or decrease the MTU size to reach a higher throughput. This operation will return the actual negotiated MTU size, but it is no guarantee that the requested size will be successfully negotiated. iOS has a default MTU size which cannot be negotiated, however you can still use this operation to get the current MTU.
final mtu = await reactiveBleClient.requestMtu(deviceId: 'AA:BB:CC:DD:EE:FF', mtu: 250);
Android specific operations #
The following operations will only have effect for Android and are not supported by iOS. When using these operations on iOS the library will throw an UnSupportedOperationException.
Request connection priority
On Android you can send a connection priority update to the BLE device. The parameter priority
is an enum that uses the same spec
as the BluetoothGatt Android spec.
Using highPerformance
will increase battery usage but will speed up GATT operations. Be cautious when setting the priority when communicating with multiple devices because if you set highperformance for all devices the effect of increasing the priority will be lower.
await reactiveBleClient.requestConnectionPriority(deviceId: 'AA:BB:CC:DD:EE:FF', priority: ConnectionPriority.highPerformance);
Clear GATT cache
The Android OS maintains a table per device of the discovered service in cache. Sometimes it happens that after a firmware update a new service is introduced but the cache is not updated. To invalidate the cache you can use the cleargattCache operation.
This is a hidden BLE operation and should be used with extreme caution since usage is not encouraged by the Android team
await reactiveBleClient.clearGattCache('AA:BB:CC:DD:EE:FF');