flutter_reactive_ble icon indicating copy to clipboard operation
flutter_reactive_ble copied to clipboard

Connection problem Samsung S20 FE

Open Berkant35 opened this issue 1 year ago • 2 comments

Hello, we have a mobile application, and this mobile app is designed to control multiple electronic devices over BLE. I'm experiencing some issues with this situation. While it works flawlessly with 6 devices that I want to connect to, it doesn't work properly on the Samsung S20 I've indicated below. As seen in the video, our customer can connect to 4 devices initially but fails to connect to 2 of them. However, when the application is closed and everything is refreshed, it can connect to all 6 devices seamlessly. Do you have any suggestions for a solution to this?

import 'dart:async';

import 'package:flutter/material.dart'; import 'package:flutter_reactive_ble/flutter_reactive_ble.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../catchpad_flutter_lib_init.dart'; import '../provs/ble_prov.dart'; import 'device_model.dart'; import 'reactive_state.dart';

class BleScanner implements ReactiveState<BleScannerState> { BleScanner(this.ref) : _ble = ref.watch(bleProv); final Ref ref;

final FlutterReactiveBle _ble;

StreamController<BleScannerState>? _stateStreamController; bool _pushedStateOnce = true;

StreamSubscription? _subscription;

var _devices = <DeviceModel>{}; final _lastdevices = <DeviceModel>{};

@override Stream<BleScannerState> get state { return _stateStreamController!.stream; }

void updateDeviceInfo(DeviceModel newDev) { final d = <DeviceModel>{};

for (var dev in _devices) {
  if (dev.id == newDev.id) {

    d.add(newDev);
  } else {
    d.add(dev);
  }
}
_devices.clear();
_devices = Set<DeviceModel>.from(d);

_pushState();

}

void deleteDevices(List<String> deadList) async { pauseScan(); _lastdevices.clear(); for (var deadId in deadList) { if (_devices.map((e) => e.id).contains(deadId)) { _devices.removeWhere((element) => element.id == deadId); } } _pushState(); resumeScan(); }

void refreshScan({required List<DiscoveredDevice> connectedDevices}) async { final lastdevices = Set<DiscoveredDevice>.from(_lastdevices); for (var condev in connectedDevices) { lastdevices.removeWhere((lastdev) => lastdev.id == condev.id); } final orgdevs = Set<DiscoveredDevice>.from(_devices); final intersections = lastdevices.intersection(orgdevs); for (var intersec in intersections) { if (!lastdevices.any((lastdev) => lastdev.id == intersec.id)) { _devices.remove(intersec); } } /* if (connectedDevices.isNotEmpty) { debugPrint('${connectedDevices.map((e) => e.name)}'); for (var condev in connectedDevices) { lastdevices } lastdevices.removeWhere((lastdev) => connectedDevices .any((connecteddev) => lastdev.id != connecteddev.id)); } if (_devices.isNotEmpty) { final orgdevs = _devices.toList(); for (var orgdev in orgdevs) { if (!lastdevices.map((e) => e.id).contains(orgdev.id)) { _devices.removeWhere((dev) => dev.id == orgdev.id); } } } */

_pushState();
debugPrint('${_devices.map((e) => e.name)}');
debugPrint('${lastdevices.map((e) => e.name)}');
_lastdevices.clear();

}

void hardRefreshScan( {required List<DiscoveredDevice> connectedDevices}) async { pauseScan();

for (var condev in connectedDevices) {
  if (!_devices.map((e) => e.id).contains(condev.id)) {
    _devices.remove(condev);
  }
}
debugPrint('${_devices.map((e) => e.name)}');
debugPrint('${_lastdevices.map((e) => e.name)}');

_pushState();
resumeScan();

}

void pauseScan() { if (_subscription != null) { _subscription?.pause(); } }

void resumeScan() { if (_subscription != null) { _subscription?.resume(); } }

void startScan() async { init(); logger.i('Start ble discovery'); _subscription = _ble.scanForDevices( withServices: [], requireLocationServicesEnabled: true, // serviceUuids, ).listen( (device) { // if (!device.isCPDevice) return;

    // dont add already added devices
    if (device.isCPDevice) {
      _lastdevices.add(device);
      if (_devices.any((element) => element.id == device.id)) {
        return;
      }
      _devices.add(device);
      if (_pushedStateOnce) {
        _pushState();
        Future.delayed(const Duration(seconds: 3))
            .then((value) => _pushedStateOnce = false);
      }
    }
  },
  onError: (Object e) => logger.e(
    'Device scan fails with error: $e',
  ),
  onDone: () {
    logger.d('Device scan is done.');
  },
);

_pushState();

//await Future.delayed(scanDuration);

//stopScan();

}

void _pushState() { if (!isClosed) { _stateStreamController!.add( BleScannerState( deviceModels: _devices, scanIsInProgress: _subscription != null, ), ); } }

bool get isClosed => _stateStreamController == null || _stateStreamController!.isClosed;

Future stopScan() async { logger.i('Stop ble discovery');

if (_subscription != null) {
  await _subscription?.cancel();
  _subscription = null;
}

if (!isClosed) {
  await dispose();
}

}

Future dispose() async { _pushState();

// I've commented out these lines, because
// as there is a widgdt listening to the
// this stream, if we reinitialize the
// stream when the user pressed scan
// button, the user's stream reference
// will stay fixed on the old instance
// of the stream. idk if this makes sense
// to you, this is the best I can explain.
// but also, here's a small demonstration:
//
// WidgetA => listening to
// a = _stateStreamController.stream
// when we close and nullify
// _stateStreamController,
// WidgetA will stay fixed on a and not
// listen to the new stream.
// this is exactly the case in
// lib/ui/device/device_list.dart _DevList
// Widget.
//
// if you did not understand yet, don't
// worry, just leave this as is and it would
// work just fine for the eternity of this
// codebase.
//
// await _stateStreamController?.close();
// _stateStreamController = null;

}

void init() { _stateStreamController ??= StreamController(); } }

@immutable class BleScannerState { const BleScannerState({ required Set<DeviceModel> deviceModels, required this.scanIsInProgress, }) : _deviceModels = deviceModels;

final Set<DeviceModel> _deviceModels; final bool scanIsInProgress;

List<DeviceModel> get deviceModels => _deviceModels.where((element) => element.isCPDevice).toList(); }

pubspec.yaml

name: catchpad publish_to: "none" version: 1.0.22+44 environment: sdk: ^3.0.5

dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter

intl: ^0.18.0 cupertino_icons: ^1.0.2 freezed_annotation: "2.2.0" flutter_downloader: ^1.10.2 badges: ^2.0.3 json_annotation: "4.7.0" auto_size_text: ^3.0.0 fl_chart: ^0.63.0 awesome_dialog: ^3.0.2 path_provider: ^2.0.13 get_it: ^7.2.0 firebase_core: ^2.1.1 cloud_firestore: ^4.0.3 firebase_auth: ^4.1.0 file_picker: ^5.2.4 flutter_keyboard_visibility: ^5.2.0 shared_preferences: ^2.0.15 connectivity_plus: ^3.0.2 flutter_animation_progress_bar: ^2.3.1 rotated_corner_decoration: ^2.1.0+1 flutter_slidable: ^2.0.0 duration: ^3.0.12

#validation regexpattern: ^2.5.0

#context kartal: ^3.2.0

#svg flutter_svg: ^1.1.6 lottie: ^2.3.2

#battery_for_start_game_condition battery_plus: ^4.0.0

adnan

life_saver_extensions: git: url: [email protected]:adnanjpg/life_saver_extensions.git loading: git: url: [email protected]:adnanjpg/loading.git paginationer: git: url: [email protected]:adnanjpg/paginationer.git

kaan

animated_search_bar: git: url: [email protected]:trailon/flutter_animated_search_bar.git

using the stabl release produces an error.

https://github.com/rrousselGit/river_pod/issues/815#issuecomment-1019378470

flutter_riverpod: ^2.0.2 flutter_easyloading: ^3.0.5 rflutter_alert: ^2.0.4 permission_handler: ^9.2.0 back_button_interceptor: ^6.0.1 enum_to_string: ^2.0.1 xrandom: ^0.7.0+1 flutter_sound: ^9.1.3 logger: ^1.1.0 # logger_flutter: # the official version is so old that it # does not support null safety 🤓 # git: # url: [email protected]:trailon/logger_flutter.git flutter_colorpicker: ^1.0.3 modal_bottom_sheet: ^2.0.1 sms_autofill: ^2.2.0 adaptive_dialog: ^1.6.3

flutter_rating_stars: 1.0.3+4

flutter_midi_pro: ^1.0.5

percent_indicator: ^4.2.3

catchpad

catchpad_flutter_lib: # path: /Users/adnanfahed/catchpad_flutter_lib.git/main git: url: [email protected]:catchpad/catchpad_flutter_lib.git

streamer: # path: /Users/adnanfahed/streamer git: url: [email protected]:catchpad/streamer.git

url_launcher: ^6.1.2 flutter_time_picker_spinner: ^2.0.0 numberpicker: ^2.1.1 string_to_hex: ^0.2.2 firebase_crashlytics: ^3.1.2

location: ^4.2.0 nanoid: ^1.0.0 platform_device_id: ^1.0.1 device_information: ^0.0.4 safe_device: ^1.1.4

dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^1.0.0 build_runner: ^2.4.6 freezed: "2.2.1" json_serializable: "6.5.4" flutter_launcher_icons: ^0.10.0 flutter_native_splash: ^2.2.12 graphic: ^2.2.0 font_awesome_flutter: ^10.1.0 package_info_plus: ^4.0.2

flutter_icons: android: "launcher_icon" ios: false image_path: "assets/app_icon/app_icon.png" adaptive_icon_background: "#191819" adaptive_icon_foreground: "assets/app_icon/app_icon_big.png"

flutter_native_splash: background_image: assets/app_icon/cpsplash.png fullscreen: true android_12: # App icon background color. icon_background_color: "#1b1819"

# Splash screen background color.
color: "#1b1819"
# App icon foreground image.
image: assets/app_icon/app_icon_big.png

web: false

flutter: generate: true uses-material-design: true assets: - assets/app_icon/ - assets/lang/ - assets/animation/lottie/ - assets/images/ - assets/images/svg/ - assets/images/games/ - assets/images/vehicles/ - assets/images/emotions/ - assets/images/shapes/ - assets/images/fruits/ - assets/images/decorations/

- assets/audio/sandbox/
- assets/audio/general/
- assets/audio/language_game/
- assets/audio/animals_game/
- assets/audio/letters_game/
- assets/audio/effect_game/
- assets/audio/music_game/
- assets/audio/vehicles_game/
- assets/audio/colors_game/
- assets/audio/catch_the_pad_game/

fonts: - family: CatchPadIcons fonts: - asset: assets/fonts/CatchPadIcons.ttf - family: Poppins fonts: - asset: assets/fonts/poppins/Thin.ttf weight: 100 - asset: assets/fonts/poppins/ThinItalic.ttf weight: 100 style: italic - asset: assets/fonts/poppins/ExtraLight.ttf weight: 200 - asset: assets/fonts/poppins/ExtraLightItalic.ttf weight: 200 - asset: assets/fonts/poppins/Light.ttf weight: 300 - asset: assets/fonts/poppins/LightItalic.ttf weight: 300 - asset: assets/fonts/poppins/Regular.ttf weight: 400 - asset: assets/fonts/poppins/Italic.ttf weight: 400 - asset: assets/fonts/poppins/Medium.ttf weight: 500 - asset: assets/fonts/poppins/MediumItalic.ttf weight: 500 style: italic - asset: assets/fonts/poppins/SemiBold.ttf weight: 600 - asset: assets/fonts/poppins/SemiBoldItalic.ttf weight: 600 style: italic - asset: assets/fonts/poppins/Bold.ttf weight: 700 - asset: assets/fonts/poppins/BoldItalic.ttf weight: 700 - asset: assets/fonts/poppins/ExtraBold.ttf weight: 800 - asset: assets/fonts/poppins/ExtraBoldItalic.ttf weight: 800 style: italic - asset: assets/fonts/poppins/Black.ttf weight: 900 - asset: assets/fonts/poppins/BlackItalic.ttf weight: 900 style: italic flutter_intl: enabled: true

flutter doctor Please commit your changes or stash them before you merge. Aborting berkantcalikusu@Berkants-MacBook-Pro catchpad % flutter --version
Flutter 3.10.5 • channel stable • https://github.com/flutter/flutter.git Framework • revision 796c8ef792 (8 weeks ago) • 2023-06-13 15:51:02 -0700 Engine • revision 45f6e00911 Tools • Dart 3.0.5 • DevTools 2.23.1 berkantcalikusu@Berkants-MacBook-Pro catchpad % flutter doctor Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel stable, 3.10.5, on macOS 13.4.1 22F770820d darwin-arm64, locale en-TR) [✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0-rc2) [✓] Xcode - develop for iOS and macOS (Xcode 14.3.1) [✓] Chrome - develop for the web [✓] Android Studio (version 2021.2) [✓] Android Studio (version 2022.2) [✓] IntelliJ IDEA Community Edition (version 2022.2.4) [✓] VS Code (version 1.80.1) [✓] Connected device (3 available) [✓] Network resources

Berkant35 avatar Aug 06 '23 09:08 Berkant35

did you try using a bluetooth explorer app like Nrfconnect and try to connect to the devices. Also did you receive any errors in logcat?

I would be very cautious with connecting a lot of ble devices at the same time because the OS can always decide to disconnect because it needs the bandwidth for other connections (WIFI or BLE).

remonh87 avatar Aug 07 '23 18:08 remonh87

I didn't. Because this problem occurred on the customer's end, and this phone is located remotely from me. I am already working with my real devices smoothly.

"I would be very cautious with connecting a lot of ble devices at the same time because the OS can always decide to disconnect because it needs the bandwidth for other connections (WIFI or BLE)."

Thank you for this advice. How can I manage to fix it? Should I add a delay or try something else?

Berkant35 avatar Aug 10 '23 08:08 Berkant35