flutter_reactive_ble icon indicating copy to clipboard operation
flutter_reactive_ble copied to clipboard

Discover different services from Android and IOS on identical hardware

Open ride4sun opened this issue 2 years ago • 3 comments

Describe the bug when I discover a service of an OBDII UART BLE device I discover different services for IOS and Android. Android works just fine and I expect a service ID 0000fff0-0000-1000-8000-00805f9b34fb

IOS

image

Android

image

To Reproduce Steps to reproduce the behavior: simply try to connect to the device and discover the Services

  Future<bool> _discoverServices(BleDevice device) async {
    try {
      List<DiscoveredService> services =
          await _interactor.discoverServices(device.id);

      _log.finest('Services for : ${device.name} --------------------');
      services.forEach((s) => _log.finest('${s.toString()}'));

      _discoveredService = services.firstWhere(
          (service) =>
              service.serviceId.toString() ==
              '0000fff0-0000-1000-8000-00805f9b34fb',
          orElse: () => null);

      if (_discoveredService == null) {
        _log.finest(
            'Could not find Services of the devices which are matching!');
        return false;
      }

      List<DiscoveredCharacteristic> characteristics;
      try {
        characteristics = _discoveredService.characteristics;
      } catch (error) {
        _log.finest('Call to discover services failed: $error ');
        return false;
      }

      var writeCharacteristic = characteristics.firstWhere(
          (char) =>
              char.characteristicId.toString() ==
              '0000fff2-0000-1000-8000-00805f9b34fb',
          orElse: () => null);

      _writeCharacteristic = QualifiedCharacteristic(
          characteristicId: writeCharacteristic.characteristicId,
          serviceId: _discoveredService.serviceId,
          deviceId: device.id);

      var notifyCharacteristic = characteristics.firstWhere(
          (char) =>
              char.characteristicId.toString() ==
              '0000fff1-0000-1000-8000-00805f9b34fb',
          orElse: () => null);

      _notifyCharacteristic = QualifiedCharacteristic(
          characteristicId: notifyCharacteristic.characteristicId,
          serviceId: _discoveredService.serviceId,
          deviceId: device.id);

      if (_notifyCharacteristic == null || _writeCharacteristic == null) {
        _log.finest('Could not find required characteristics');
        return false;
      }

      _notifySubscription =
          _interactor.subScribeToCharacteristic(_notifyCharacteristic).listen(
        (data) {
          if (isConnected.isTrue && _disconnectLock.inLock.isFalse)
            _notify.value = data;
        },
      );
      _notifySubscription.onError((error) {
        _log.finest('Error: Notify Stream error: $error');
        _disconnect();
        loading.value = false;
      });
      return true;
    } catch (e) {
      rethrow;
    }
  }

Expected behavior Identical characteristics on IOS and Android

I tried doing the same with a general BLE scanner application nRF (Android)

Screenshot_20220125-172014 Screenshot_20220125-172411-289

Smartphone / tablet

  • Device: Iphone 6s and Motorola Edge 2021
  • OS: [e.g. iOS 15, Android 11]
  • Package version: flutter_reactive_ble: 5.0.2
  • flutter version
jay@mini obdchk % flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.8.1, on macOS 11.6 20G165 darwin-x64, locale en-US)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2020.3)
[✓] VS Code (version 1.60.2)
[✓] VS Code (version 1.44.2)
[✓] VS Code (version 1.42.1)
[✓] VS Code (version 1.41.1)
[✓] Connected device (2 available)

Peripheral device

  • Vendor, model: OBDII BLE Uart device Carista (support Bluetooth Classic and BLE)
  • https://caristaapp.com/
  • Does it run a custom firmware/software: no

ride4sun avatar Jan 26 '22 01:01 ride4sun

if i change my code like this it all starts working. I would not expected that...

Future<bool> _discoverServices(BleDevice device) async {
    try {
      List<DiscoveredService> services =
          await _interactor.discoverServices(device.id);

      _log.finest('Services for : ${device.name} --------------------');
      services.forEach((s) => _log.finest('${s.toString()}'));

      _discoveredService = services.firstWhere(
          (service) =>
              service.serviceId.toString() ==
                  '0000fff0-0000-1000-8000-00805f9b34fb' ||
              service.serviceId.toString() == 'fff0',
          orElse: () => null);

      if (_discoveredService == null) {
        _log.finest(
            'Could not find Services of the devices which are matching!');
        return false;
      }

      List<DiscoveredCharacteristic> characteristics;
      try {
        characteristics = _discoveredService.characteristics;
      } catch (error) {
        _log.finest('Call to discover services failed: $error ');
        return false;
      }

      var writeCharacteristic = characteristics.firstWhere(
          (char) =>
              char.characteristicId.toString() ==
                  '0000fff2-0000-1000-8000-00805f9b34fb' ||
              char.characteristicId.toString() == 'fff2',
          orElse: () => null);

      _writeCharacteristic = QualifiedCharacteristic(
          characteristicId: writeCharacteristic.characteristicId,
          serviceId: _discoveredService.serviceId,
          deviceId: device.id);

      var notifyCharacteristic = characteristics.firstWhere(
          (char) =>
              char.characteristicId.toString() ==
                  '0000fff1-0000-1000-8000-00805f9b34fb' ||
              char.characteristicId.toString() == 'fff1',
          orElse: () => null);

      _notifyCharacteristic = QualifiedCharacteristic(
          characteristicId: notifyCharacteristic.characteristicId,
          serviceId: _discoveredService.serviceId,
          deviceId: device.id);

      if (_notifyCharacteristic == null || _writeCharacteristic == null) {
        _log.finest('Could not find required characteristics');
        return false;
      }

      _notifySubscription =
          _interactor.subScribeToCharacteristic(_notifyCharacteristic).listen(
        (data) {
          if (isConnected.isTrue && _disconnectLock.inLock.isFalse)
            _notify.value = data;
        },
      );
      _notifySubscription.onError((error) {
        _log.finest('Error: Notify Stream error: $error');
        _disconnect();
        loading.value = false;
      });
      return true;
    } catch (e) {
      rethrow;
    }
  }

ride4sun avatar Jan 26 '22 20:01 ride4sun

Having the same problem. It looks like with services that have the predefined postfix of "0000-1000-8000-00805f9b34fb", iOS removes the postfix, but Android keeps it in. As a cross-platform library, reactive-ble should fix this and standardize on one format or the other, and not just pass through whatever the underlying libraries pass.

spekary avatar Jan 20 '23 21:01 spekary