chipweinberger / flutter_blue_plus

Flutter plugin for connecting and communicationg with Bluetooth Low Energy devices, on Android, iOS, macOS
Other
791 stars 478 forks source link

[Help]: The proper way of scanning for a specific device #901

Closed raphasauer closed 5 months ago

raphasauer commented 5 months ago

Requirements

Have you checked this problem on the example app?

Yes

FlutterBluePlus Version

1.32.7

Flutter Version

3.3.10

What OS?

Android

OS Version

Android 9 and up

Bluetooth Module

esp32-s

What is your problem?

I have a question on what's the best way to handle scanning for a specific device. Let's say I wan't to connect to a device x, and every time I turn on my app I scan for said device. If it's not found, I should scan again. However, I am not quite handling the "If it's not found" part well.

My current code looks something like this:

Future<void> bluetoothLowEnergyScan(BuildContext context) async {
  // First I verify if adpater is on and permissions are given, not shown here

  // Create a timeout timer
    Timer _t = Timer(
      Duration(seconds: 120),
      () {
        if (bleDiscStreamSubscription != null) {
          bleDiscStreamSubscription!.cancel();
        }
        resetBluetoothConnection();
        bluetoothLowEnergyScan(context);
      },
    );
    // Check if device is already paired
    var bondedDevices = await FlutterBluePlus.bondedDevices;

    // Creates a default device used when device is not paired
    var defaultdesiredDevice =
        BluetoothDevice(remoteId: DeviceIdentifier("00:00:00:00:00:00"));

    // Fetches desired device
    var desiredDevice = bondedDevices.firstWhere(
        (device) =>
            device.advName == 'DesiredDevice' || device.platformName == 'DesiredDevice',
        orElse: () => defaultdesiredDevice);

    // If the returned device is not the default
    if (desiredDevice.remoteId.str != "00:00:00:00:00:00" && !_bondedAttempted) {
      try {
        _t.cancel();
        await _connectBluetoothLowEnergy(desiredDevice, context);
      } catch (e) {
        _bondedAttempted = true;
        log("[bluetoothLowEnergyScan] Error: $e");
      }
    } else {

      // Scans for the desired device
      bleDiscStreamSubscription = FlutterBluePlus.onScanResults.listen(
        (results) async {
          if (results.isNotEmpty) {
            ScanResult r = results.last;

            // If the device is found, cancel the timer and stop scanning
            if (r.advertisementData.advName == 'desiredDevice' ||
                r.device.platformName == 'desiredDevice') {
              log('[bluetoothLowEnergyScan] desiredDevice found!');
              _t.cancel();
              FlutterBluePlus.stopScan();
              await _connectdesiredDeviceBluetoothLowEnergy(r.device, context);
            } else {
              log('[bluetoothLowEnergyScan] ${r.device.remoteId}: "${r.device.advName}" found!');
            }
          }
        },
        onError: (e) => log('[bluetoothLowEnergyScan] Error: $e'),
      );
        await FlutterBluePlus.startScan(
          timeout: const Duration(seconds: 120),
          continuousUpdates: false,
          continuousDivisor: 1,
        );
      FlutterBluePlus.cancelWhenScanComplete(bleDiscStreamSubscription!);
    }
}

However, I do not believe this is the best approach. What would be the "proper" way to achieve this?

Thanks for the library and for your time.

Logs

//No logs
chipweinberger commented 5 months ago
  1. scan
  2. write remoteId to file
  3. next time, just create BluetoothDevice directly from remoteId and call device.connect
  4. if failure, delete file, go back to step 1
raphasauer commented 5 months ago

Thank you!