flutter_reactive_ble
flutter_reactive_ble copied to clipboard
Re-Enable notifications on reconnection to device
Describe the bug Basically the notifications are not re-enabled on reconnection to the ble device.
This is supported by the below code where on first setup of the .connectToDevice() listener. I recieve the below output on first connection when subscribing to the three characteristics.
D/BluetoothGatt( 3822): setCharacteristicNotification() - uuid: f3641401-00b0-4240-ba50-05ca45bf8abc enable: true
D/BluetoothGatt( 3822): setCharacteristicNotification() - uuid: f3641403-00b0-4240-ba50-05ca45bf8abc enable: true
D/BluetoothGatt( 3822): setCharacteristicNotification() - uuid: 00002a19-0000-1000-8000-00805f9b34fb enable: true
on disconnection I get the following.
D/BluetoothGatt( 5669): setCharacteristicNotification() - uuid: f3641401-00b0-4240-ba50-05ca45bf8abc enable: false
D/BluetoothGatt( 5669): setCharacteristicNotification() - uuid: f3641403-00b0-4240-ba50-05ca45bf8abc enable: false
D/BluetoothGatt( 5669): setCharacteristicNotification() - uuid: 00002a19-0000-1000-8000-00805f9b34fb enable: false
But unfortunately on reconnection when I go back into range of the BLE device (and it reconnects) I don't get a reenabling of the the notifications of those same characteristics.
Below is the complete output of during these events.
D/BluetoothGatt(17897): setCharacteristicNotification() - uuid: f3641401-00b0-4240-ba50-05ca45bf8abc enable: true
D/BluetoothGatt(17897): setCharacteristicNotification() - uuid: f3641403-00b0-4240-ba50-05ca45bf8abc enable: true
D/BluetoothGatt(17897): setCharacteristicNotification() - uuid: 00002a19-0000-1000-8000-00805f9b34fb enable: true
I/flutter (17897): periodic clock updates enabled in 54 seconds
D/BluetoothGatt(17897): onClientConnectionState() - status=0 clientIf=6 device=EF:2C:0C:2E:78:1A
D/BluetoothGatt(17897): setCharacteristicNotification() - uuid: f3641401-00b0-4240-ba50-05ca45bf8abc enable: false
D/BluetoothManager(17897): getConnectionState()
D/BluetoothManager(17897): getConnectedDevices
D/BluetoothGatt(17897): close()
D/BluetoothGatt(17897): unregisterApp() - mClientIf=6
D/BluetoothGatt(17897): setCharacteristicNotification() - uuid: f3641403-00b0-4240-ba50-05ca45bf8abc enable: false
D/BluetoothGatt(17897): setCharacteristicNotification() - uuid: 00002a19-0000-1000-8000-00805f9b34fb enable: false
I/flutter (17897): we are disconnected
D/BluetoothGatt(17897): connect() - device: EF:2C:0C:2E:78:1A, auto: true
D/BluetoothGatt(17897): registerApp()
D/BluetoothGatt(17897): registerApp() - UUID=11ead47f-0cea-470c-b384-4348265fcab4
D/BluetoothGatt(17897): onClientRegistered() - status=0 clientIf=6
D/BluetoothGatt(17897): onClientConnectionState() - status=0 clientIf=6 device=EF:2C:0C:2E:78:1A
D/BluetoothGatt(17897): discoverServices() - device: EF:2C:0C:2E:78:1A
D/BluetoothGatt(17897): onSearchComplete() = Device=EF:2C:0C:2E:78:1A Status=0
To Reproduce walk far enough away to disconnect from BLE device then go back within range of the device and reconnect to it.
Expected behavior It does re-enable notifications on reconnection
Smartphone / tablet Huawei P9 (EVA-L19) - EMUI 5.0.3 (Android Version 7)
Peripheral device nRF52832 (custom firmware) which I have tested extensively and am 99.9% sure it is not the peripheral.
Additional context Interestingly when I disable and reenable bluetooth on the phone (simulating a disconnection event) it connects and reenables the notifications (see below output).
D/BluetoothGatt(17897): setCharacteristicNotification() - uuid: f3641401-00b0-4240-ba50-05ca45bf8abc enable: true
D/BluetoothGatt(17897): setCharacteristicNotification() - uuid: f3641403-00b0-4240-ba50-05ca45bf8abc enable: true
D/BluetoothGatt(17897): setCharacteristicNotification() - uuid: 00002a19-0000-1000-8000-00805f9b34fb enable: true
D/BluetoothManager(17897): getConnectionState()
D/BluetoothManager(17897): getConnectedDevices
D/BluetoothGatt(17897): setCharacteristicNotification() - uuid: f3641401-00b0-4240-ba50-05ca45bf8abc enable: false
D/BluetoothGatt(17897): setCharacteristicNotification() - uuid: f3641403-00b0-4240-ba50-05ca45bf8abc enable: false
D/BluetoothGatt(17897): cancelOpen() - device: EF:2C:0C:2E:78:1A
D/BluetoothGatt(17897): onClientConnectionState() - status=0 clientIf=6 device=EF:2C:0C:2E:78:1A
D/BluetoothGatt(17897): close()
D/BluetoothGatt(17897): unregisterApp() - mClientIf=6
D/BluetoothGatt(17897): setCharacteristicNotification() - uuid: 00002a19-0000-1000-8000-00805f9b34fb enable: false
I/flutter (17897): we are disconnected
I/flutter (17897): periodic clock updates enabled in 22 seconds
D/BluetoothGatt(17897): connect() - device: EF:2C:0C:2E:78:1A, auto: true
D/BluetoothGatt(17897): registerApp()
D/BluetoothGatt(17897): registerApp() - UUID=c3879833-134c-416d-9c46-df8dd924163c
I/flutter (17897): connecting
D/BluetoothGatt(17897): onClientRegistered() - status=0 clientIf=6
I/art (17897): Do partial code cache collection, code=58KB, data=54KB
I/art (17897): After code cache collection, code=54KB, data=52KB
I/art (17897): Increasing code cache capacity to 256KB
I/art (17897): Compiler allocated 8MB to compile int com.google.protobuf.MessageSchema.getSerializedSizeProto3(java.lang.Object)
D/BluetoothGatt(17897): onClientConnectionState() - status=0 clientIf=6 device=EF:2C:0C:2E:78:1A
I/flutter (17897): you are connected
D/BluetoothGatt(17897): discoverServices() - device: EF:2C:0C:2E:78:1A
D/BluetoothGatt(17897): onSearchComplete() = Device=EF:2C:0C:2E:78:1A Status=0
W/BluetoothGatt(17897): onCharacteristicRead() - Device=EF:2C:0C:2E:78:1A handle=21 Status=0
I/flutter (17897): the place on the device is: thompsons
I/flutter (17897): the length of the place string is 9
I/flutter (17897): requesting count log
I/art (17897): Compiler allocated 5MB to compile void com.google.protobuf.MessageSchema.writeFieldsInAscendingOrderProto3(java.lang.Object, com.google.protobuf.Writer)
W/BluetoothGatt(17897): onCharacteristicRead() - Device=EF:2C:0C:2E:78:1A handle=13 Status=0
I/flutter (17897): setup notification listeners
D/BluetoothGatt(17897): setCharacteristicNotification() - uuid: f3641401-00b0-4240-ba50-05ca45bf8abc enable: true
D/BluetoothGatt(17897): setCharacteristicNotification() - uuid: f3641403-00b0-4240-ba50-05ca45bf8abc enable: true
D/BluetoothGatt(17897): setCharacteristicNotification() - uuid: 00002a19-0000-1000-8000-00805f9b34fb enable: true
I feel like I'm missing something here that could fix this.
Also below is the switch statement that I have put into the connectToDevice() listener.
switch(event.connectionState) {
case DeviceConnectionState.disconnecting:
{
if (event.connectionState != bleConnection.currentConnectionState) {
bleConnection.currentConnectionState = event.connectionState;
print('disconnecting');
}
}
break;
case DeviceConnectionState.connecting:
{
if (event.connectionState != bleConnection.currentConnectionState) {
bleConnection.currentConnectionState = event.connectionState;
print('connecting');
}
}
break;
case DeviceConnectionState.disconnected:
{
if (event.connectionState != bleConnection.currentConnectionState) {
bleConnection.currentConnectionState = event.connectionState;
print('we are disconnected');
requestCountLog = true;
}
}
break;
case DeviceConnectionState.connected:
{
if (event.connectionState != bleConnection.currentConnectionState) {
bleConnection.currentConnectionState = event.connectionState;
print('you are connected');
bleConnection.isConnected = true;
bleConnection.connectionController.add(true);
bleConnection.setPlace(await _ble.readCharacteristic(bleConnection.placeCharacteristic));
if (requestCountLog) {
requestCountLog = false;
print('requesting count log');
// request log data on the device.
await _ble.writeCharacteristicWithoutResponse(bleConnection.optionCharacteristic, value: [0x07]);
//once log data is complete, then send time to device.
final DateTime now = DateTime.now();
final int hour = now.hour;
final int minute = now.minute;
await _ble.writeCharacteristicWithoutResponse(bleConnection.optionCharacteristic, value: [0x04, hour, minute]);
Timer(Duration(seconds: now.second), () {
print('periodic clock updates enabled in ${now.second} seconds');
Timer.periodic(Duration(seconds: 60), (Timer t) => _getTime());
});
// once the time timer has been set, we can finally get the battery level.
bleConnection.batteryLevel = await _ble.readCharacteristic(bleConnection.batteryCharacteristic);
bleConnection.batteryStreamController.add(bleConnection.batteryLevel.last);
}
print('setup notification listeners');
bleConnection.countStream = _ble.subscribeToCharacteristic(bleConnection.countCharacteristic).listen((ev) async {
bleConnection.setCountData(ev);
}, onError: (dynamic error) {
// code to handle errors
});
//command to get log dat in log char listener
bleConnection.logStream = _ble.subscribeToCharacteristic(bleConnection.logCharacteristic).listen((ev) async {
if (ev.isNotEmpty) {
bleConnection.processLogCountData(ev);
}
});
bleConnection.batteryStream = _ble.subscribeToCharacteristic(bleConnection.batteryCharacteristic).listen((ev) async {
print('Battery notification: $ev');
bleConnection.batteryLevel = ev;
});
}
}
break;
default:
{
//statements;
}
break;
}
Thank you for the elaborate description. This really helps. I tried to reproduce it using the example app but despite I spent quite some significant time I wasn't able to. Can you check if you can reproduce the same behaviour with another phone and the example app? I do not have a Android 7 phone but I tested it with a Samsung s7 on android 8
Thanks Remonh87. I really appreciate you looking into this. Yes I will investigate if I can reproduce it the the example app.
Just doing to some testing on the example app and there is a difference in my implementation of the flutter_reactive_ble library.
The difference is that subscribing of notifications is disabled once you go back out of the dialog and is not re-enabled upon automatic reconnection even while keeping the dialog box on top.
However, thank you, as I did need to look at the example app more closely to figure it out.
I have been able to customise the example app implementation slightly in my app so that it automatically and safely cancels the StreamSubscription 'connectToDevice'
listener in the ble_device_connector.dart file.
I also listen to the Stream<ConnectionStateUpdate> state
stream in my app.
The key is to call disconnect(deviceId) in the connectToDevice
listener (in the ble_device_connector.dart file) when the DeviceConnectionState.disconnected
event is emmitted. This gracefully disconnects the device (by cancelling the listener).
Then you call widget.connector.connect(deviceId)
in the separate Stream<ConnectionStateUpdate> state
stream in my app in the DeviceConnectionState.disconnected
emitted event.
Also NOTE: the switch statement for dealing with initial reads/writes and subscriptions is in the StreamSubscription 'connectToDevice'
listener in the ble_device_connector.dart file before the _deviceConnectionController.add(event);
so that the app disconnects gracefully before trying to connect again.
@remonh87 I am alos facing a similar type of issue, where On the first attempt I connect the BLE device and was able to get the data from characteristics streams and receive the data... but if I disconnect to the same device and connect again then I can get the discover services but not getting the data while I call subscribeToCharacteristic
.
I am trying the same on the example app under this repository...
Note: Also getting multiple entries of same service id when clicking on the discovery service. Check the below screenshot.
@dhaval-k-simformsolutions I am Facing the exact same issue.
In the exact same configuration. I connect & diconnect, and then reconnect again, and I when I try to subscribe to a characteristic I get Error unsubscribing from notifications: PlatformException(reactive_ble_mobile.PluginError:3, The operation couldn’t be completed. (reactive_ble_mobile.PluginError error 3.), {}, null)
.
I can read and write a characteristic though. The issue is only in subscribing.
Have you find a workaround ? thanks.
@rowdy15 I am facing the same issue, and don't know how to deal it exactly. it is disconnected when notifying the characteristic and I try to reconnect, but it disconnect over and over again. Have you find the solution ? thanks.
Running in the same issue, is there any progress?