quick_blue icon indicating copy to clipboard operation
quick_blue copied to clipboard

[Windows] Unhandled Exception: PlatformException(IllegalArgument, Unknown devicesId: .... , null, null)

Open rebeccasc opened this issue 2 years ago • 6 comments

QuickBlue irregularly throws an exception when calling

await QuickBlue.setNotifiable(
            device.address,
            myUartServiceUUID,
            myUartCharacteristicsUUID,
            BleInputProperty.notification);

This exception does not always occur thats why I assume it's a timing error.

Here's the full code:


// scan for device
String deviceId;
QuickBlue.scanResultStream.listen((result) {
     deviceId = result.deviceId;
     // return if device found
});
QuickBlue.startScan();
// wait some time for scanning
await Future.delayed(const Duration(seconds: 1));
QuickBlue.stopScan();

// set value handler
QuickBlue.setValueHandler((String deviceId, String characteristicId, Uint8List value) {
          // do something with the recevied values
 });

// connect and set notifiable
QuickBlue.connect(deviceId);
// give quick_blue some time to handle async function
await Future.delayed(const Duration(seconds: 2));
await QuickBlue.setNotifiable(
            deviceId,
            myUartServiceUUID,
            myUartCharacteristicsUUID,
            BleInputProperty.notification);
// give quick_blue some time to handle async function
await Future.delayed(const Duration(seconds: 2));

What I did trying to fix it:

  • added delays (see ahead)
  • checked for the correct deviceId. The deviceId comes from the scan result and stable works for QuickBlue.connect(deviceId);

Is this related to: #93, or #90?

Does anyone have an idea how I can fix/avoid the exception?

Thanks!

rebeccasc avatar Dec 03 '22 17:12 rebeccasc

You can use prerelease plugin version 0.5.0-dev.2 In this version, the author completed the receiving serviceId and characteristicIds from device for Windows.

QuickBlue.setConnectionHandler(_handleConnectionChange);
QuickBlue.setServiceHandler(_handleServiceDiscovery);

void _handleConnectionChange(String deviceId, BlueConnectionState state) {
    if (state == BlueConnectionState.connected) {
      QuickBlue.discoverServices(deviceId);
    }
  }

//The main point: This handler is called multiple times during the connection process
void _handleServiceDiscovery(String deviceId, String serviceId, List<String>? characteristicIds) {
    if (deviceId.isNotEmpty && serviceId.isNotEmpty && characteristicIds != null && characteristicIds.length > 1) {
      //Update: Here you are already dealing with different services and you can choose which you need, no need any Future and delays :-)
     }
    }
  }

alevlako avatar Dec 04 '22 11:12 alevlako

@alevlako Thanks for the fast response!

You can use prerelease plugin version 0.5.0-dev.2

Have tried this. Unfortunately this does not fix the error...

rebeccasc avatar Dec 09 '22 08:12 rebeccasc

@rebeccasc Hi, did you find any solution or workaround?

AErmek avatar Jun 15 '23 09:06 AErmek

@rebeccasc Hi, did you find any solution or workaround?

I fixed it with some workaround. Maybe it's not the smartest way to solve it but it works for me.

First I wrap the code block with an flutter runZonedGuarded so the error can be caught. It turned out that the thrown error cannot be caught by a simple try-catch statement. Because the error will be thrown irregularly I simply try to run the code 5 times. Practice shows that it usually works with the second call. The code looks like this:

var connectionRetry = 5;
while (connectionRetry > 0 && !(await connectPlatformWindows())) {
   // connection failed, try again
   connectionRetry--;
}

Future<bool> connectPlatformWindows() async {
    var success = true;
    await runZonedGuarded(() async {
        // run the code ahead ...
        QuickBlue.setValueHandler((String deviceId, String characteristicId, Uint8List value) {
             // do something with the recevied values
         });
        
        QuickBlue.connect(deviceId);

        // give quick_blue some time to handle async function
        await Future.delayed(const Duration(seconds: 2));

        await QuickBlue.setNotifiable(
                deviceId,
                myUartServiceUUID,
                myUartCharacteristicsUUID,
                BleInputProperty.notification);

        // give quick_blue some time to handle async function
        await Future.delayed(const Duration(milliseconds: 250));
    }, (e, stack) {
      success = false;
    });
    return success;
}

Hope it helps.

rebeccasc avatar Jun 15 '23 09:06 rebeccasc

@rebeccasc Hi, did you find any solution or workaround?

I fixed it with some workaround. Maybe it's not the smartest way to solve it but it works for me.

First I wrap the code block with an flutter runZonedGuarded so the error can be caught. It turned out that the thrown error cannot be caught by a simple try-catch statement. Because the error will be thrown irregularly I simply try to run the code 5 times. Practice shows that it usually works with the second call. The code looks like this:

var connectionRetry = 5;
while (connectionRetry > 0 && !(await connectPlatformWindows())) {
   // connection failed, try again
   connectionRetry--;
}

Future<bool> connectPlatformWindows() async {
    var success = true;
    await runZonedGuarded(() async {
        // run the code ahead ...
        QuickBlue.setValueHandler((String deviceId, String characteristicId, Uint8List value) {
             // do something with the recevied values
         });
        
        QuickBlue.connect(deviceId);

        // give quick_blue some time to handle async function
        await Future.delayed(const Duration(seconds: 2));

        await QuickBlue.setNotifiable(
                deviceId,
                myUartServiceUUID,
                myUartCharacteristicsUUID,
                BleInputProperty.notification);

        // give quick_blue some time to handle async function
        await Future.delayed(const Duration(milliseconds: 250));
    }, (e, stack) {
      success = false;
    });
    return success;
}

Hope it helps.

Thanks for reply, It looks really interesting workaround. I'have tried it , but infortunately, in my case i'm getting native windows fatal crash on first call of connect method (even runZonedGuarded not catching exception). I really don't know why this package has so chaotic behavior for windows platform implementation. I've also tried to make connection via win32 package with winsock2, but there are also has its own issues. Now I'm just stuck.

AErmek avatar Jun 19 '23 04:06 AErmek

... in my case i'm getting native windows fatal crash on first call of connect method (even runZonedGuarded not catching exception). I really don't know why this package has so chaotic behavior for windows platform implementation. I've also tried to make connection via win32 package with winsock2, but there are also has its own issues. Now I'm just stuck.

The plugin behaves like this when there is no bluetooth receiver (dongle) connected to the PC. This is a known issue and it has the fix.

alevlako avatar Jun 19 '23 18:06 alevlako