From 693e2fbcff80f02f583f552e7b996722e6f5debd Mon Sep 17 00:00:00 2001 From: Jeroen1602 <1492076+jeroen1602@users.noreply.github.com> Date: Thu, 26 Jan 2023 10:45:32 +0100 Subject: [PATCH] Added quick blue back end The quick blue back end cannot be used because of dependency hell. But I did put all the work in creating it so here it stays in this branch until usable and needed. --- .../quick_blue_back_end/.gitignore | 30 +++ .../quick_blue_back_end/.metadata | 27 +++ .../quick_blue_back_end/README.md | 4 + .../quick_blue_back_end/analysis_options.yaml | 4 + .../lib/quick_blue_back_end.dart | 2 + .../src/ble/quick_blue_characteristic.dart | 34 ++++ .../lib/src/ble/quick_blue_device.dart | 94 ++++++++++ .../lib/src/ble/quick_blue_service.dart | 11 ++ .../lib/src/helper/connection_handler.dart | 55 ++++++ .../lib/src/helper/service_handler.dart | 74 ++++++++ .../lib/src/helper/value_handler.dart | 91 +++++++++ .../lib/src/quick_blue_back_end_io.dart | 174 ++++++++++++++++++ .../src/quick_blue_back_end_unsupported.dart | 30 +++ .../quick_blue_back_end/pubspec.yaml | 83 +++++++++ 14 files changed, 713 insertions(+) create mode 100644 lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/.gitignore create mode 100644 lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/.metadata create mode 100644 lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/README.md create mode 100644 lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/analysis_options.yaml create mode 100644 lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/quick_blue_back_end.dart create mode 100644 lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/ble/quick_blue_characteristic.dart create mode 100644 lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/ble/quick_blue_device.dart create mode 100644 lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/ble/quick_blue_service.dart create mode 100644 lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/helper/connection_handler.dart create mode 100644 lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/helper/service_handler.dart create mode 100644 lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/helper/value_handler.dart create mode 100644 lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/quick_blue_back_end_io.dart create mode 100644 lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/quick_blue_back_end_unsupported.dart create mode 100644 lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/pubspec.yaml diff --git a/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/.gitignore b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/.gitignore new file mode 100644 index 00000000..96486fd9 --- /dev/null +++ b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/.gitignore @@ -0,0 +1,30 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ diff --git a/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/.metadata b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/.metadata new file mode 100644 index 00000000..f2944cef --- /dev/null +++ b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/.metadata @@ -0,0 +1,27 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: 135454af32477f815a7525073027a3ff9eff1bfd + channel: stable + +project_type: plugin + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 135454af32477f815a7525073027a3ff9eff1bfd + base_revision: 135454af32477f815a7525073027a3ff9eff1bfd + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/README.md b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/README.md new file mode 100644 index 00000000..de9e12da --- /dev/null +++ b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/README.md @@ -0,0 +1,4 @@ +# quick_blue_back_end + +Use the `quick_blue` library as a back end. + diff --git a/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/analysis_options.yaml b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/analysis_options.yaml new file mode 100644 index 00000000..a5744c1c --- /dev/null +++ b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/quick_blue_back_end.dart b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/quick_blue_back_end.dart new file mode 100644 index 00000000..0badf7be --- /dev/null +++ b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/quick_blue_back_end.dart @@ -0,0 +1,2 @@ +export 'src/quick_blue_back_end_unsupported.dart' + if (dart.library.io) 'src/quick_blue_back_end_io.dart'; diff --git a/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/ble/quick_blue_characteristic.dart b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/ble/quick_blue_characteristic.dart new file mode 100644 index 00000000..eedafc26 --- /dev/null +++ b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/ble/quick_blue_characteristic.dart @@ -0,0 +1,34 @@ +part of quick_blue_back_end; + +class QuickBlueCharacteristic extends LHBluetoothCharacteristic { + QuickBlueCharacteristic( + final String deviceId, + final String serviceId, + final String characteristicId, + final ValueHandler valueHandler, + ) : _deviceId = deviceId, + _serviceId = serviceId, + _characteristicId = characteristicId, + _valueHandler = valueHandler, + uuid = LighthouseGuid.fromString(characteristicId); + + final String _deviceId; + final String _serviceId; + final String _characteristicId; + final ValueHandler _valueHandler; + + @override + final LighthouseGuid uuid; + + @override + Future> read() { + return _valueHandler.readValue(_deviceId, _serviceId, _characteristicId); + } + + @override + Future write(final List data, + {final bool withoutResponse = false}) { + return _valueHandler.writeValue(_deviceId, _serviceId, _characteristicId, + Uint8List.fromList(data), withoutResponse); + } +} diff --git a/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/ble/quick_blue_device.dart b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/ble/quick_blue_device.dart new file mode 100644 index 00000000..166eeab3 --- /dev/null +++ b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/ble/quick_blue_device.dart @@ -0,0 +1,94 @@ +part of quick_blue_back_end; + +/// An abstraction for the [FlutterReactiveBle] bluetooth device. +class FlutterReactiveBleBluetoothDevice extends LHBluetoothDevice { + FlutterReactiveBleBluetoothDevice( + this.device, + final ConnectionHandler connectionHandler, + final ServiceHandler serviceHandler, + final ValueHandler valueHandler) + : id = LHDeviceIdentifier(device.deviceId), + _connectionHandler = connectionHandler, + _serviceHandler = serviceHandler, + _valueHandler = valueHandler; + + final BlueScanResult device; + final ConnectionHandler _connectionHandler; + final ServiceHandler _serviceHandler; + final ValueHandler _valueHandler; + + @override + final LHDeviceIdentifier id; + + @override + Future connect({final Duration? timeout}) async { + QuickBlue.connect(device.deviceId); + if (timeout != null) { + try { + await _connectionHandler + .waitForState(device.deviceId, BlueConnectionState.connected) + .timeout(timeout); + } on TimeoutException { + await disconnect(); + rethrow; + } + } else { + await _connectionHandler.waitForState( + device.deviceId, BlueConnectionState.connected); + } + } + + @override + Future disconnect() async { + QuickBlue.disconnect(device.deviceId); + try { + await _connectionHandler + .waitForState(device.deviceId, BlueConnectionState.connected) + .timeout(const Duration(seconds: 5)); + } on TimeoutException { + lighthouseLogger.severe("Ignored error while tyring to disconnect $id"); + // ignore exception. + } finally { + _connectionHandler.removeSubject(device.deviceId); + _serviceHandler.removeSubject(device.deviceId); + } + } + + @override + Future> discoverServices() async { + QuickBlue.discoverServices(device.deviceId); + + return await _serviceHandler.waitForServices(device.deviceId).then((value) { + return value.map((serviceAndCharacteristics) { + return QuickBlueService( + serviceAndCharacteristics.serviceId, + serviceAndCharacteristics.characteristicIds + .map((final characteristic) { + return QuickBlueCharacteristic( + device.deviceId, + serviceAndCharacteristics.serviceId, + characteristic, + _valueHandler); + }).toList()); + }).toList(); + }); + } + + @override + Stream get state => + _connectionHandler.getOrCreateStream(device.deviceId).map((final state) { + switch (state) { + case BlueConnectionState.connected: + return LHBluetoothDeviceState.connected; + case BlueConnectionState.disconnected: + return LHBluetoothDeviceState.disconnected; + default: + assert(false, "This shouldn't happen"); + lighthouseLogger.severe("Unhandled device state in the converter"); + return LHBluetoothDeviceState.unknown; + } + }); + + @override + String get name => device.name; +} diff --git a/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/ble/quick_blue_service.dart b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/ble/quick_blue_service.dart new file mode 100644 index 00000000..9bd355fb --- /dev/null +++ b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/ble/quick_blue_service.dart @@ -0,0 +1,11 @@ +part of quick_blue_back_end; + +class QuickBlueService extends LHBluetoothService { + QuickBlueService(final String serviceId, this.characteristics) + : uuid = LighthouseGuid.fromString(serviceId); + + @override + final LighthouseGuid uuid; + @override + final List characteristics; +} diff --git a/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/helper/connection_handler.dart b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/helper/connection_handler.dart new file mode 100644 index 00000000..207fceb6 --- /dev/null +++ b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/helper/connection_handler.dart @@ -0,0 +1,55 @@ +part of quick_blue_back_end; + +class ConnectionHandler { + ConnectionHandler._() { + QuickBlue.setConnectionHandler(_connectionHandler); + } + + void _connectionHandler( + final String deviceId, final BlueConnectionState state) { + final subject = _subjects[deviceId]; + if (subject != null) { + subject.add(state); + } else { + lighthouseLogger.info("Could not handle connection state for $deviceId"); + } + } + + final Map> _subjects = {}; + + Stream getOrCreateStream(final String deviceId) { + return _getOrCreateSubject(deviceId).stream; + } + + BehaviorSubject _getOrCreateSubject( + final String deviceId) { + return _subjects[deviceId] ??= + BehaviorSubject.seeded(BlueConnectionState.disconnected); + } + + Future removeSubject(final String deviceId) async { + final subject = _subjects[deviceId]; + if (subject != null) { + await subject.close(); + _subjects.remove(deviceId); + } else { + lighthouseLogger.info("Could not close subject for $deviceId"); + } + } + + Future removeAllSubjects() async { + for (final subject in _subjects.values) { + await subject.close(); + } + _subjects.clear(); + } + + Future waitForState( + final String deviceId, final BlueConnectionState state) async { + final subject = _getOrCreateSubject(deviceId); + if (subject.valueOrNull == state) { + return; + } + subject.stream.firstWhere((element) => element == state); + } +} diff --git a/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/helper/service_handler.dart b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/helper/service_handler.dart new file mode 100644 index 00000000..ce886c7c --- /dev/null +++ b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/helper/service_handler.dart @@ -0,0 +1,74 @@ +part of quick_blue_back_end; + +@immutable +class ServiceData { + const ServiceData(this.serviceId, this.characteristicIds); + + final String serviceId; + final List characteristicIds; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ServiceData && + runtimeType == other.runtimeType && + serviceId == other.serviceId; + + @override + int get hashCode => serviceId.hashCode; +} + +class ServiceHandler { + ServiceHandler._() { + QuickBlue.setServiceHandler(_serviceHandler); + } + + void _serviceHandler(final String deviceId, final String serviceId, + List characteristicIds) { + final data = ServiceData(serviceId, characteristicIds); + + final set = (_services[deviceId] ??= {})..add(data); + + final subject = _subjects[deviceId]; + if (subject != null) { + subject.add(set); + } else { + lighthouseLogger.info("Could not handle connection state for $deviceId"); + } + } + + final Map>> _subjects = {}; + final Map> _services = {}; + + Stream> getOrCreateStream(final String deviceId) { + return _getOrCreateSubject(deviceId).stream; + } + + BehaviorSubject> _getOrCreateSubject(final String deviceId) { + return _subjects[deviceId] ??= BehaviorSubject.seeded({}); + } + + Future> waitForServices(final String deviceId) async { + return _getOrCreateSubject(deviceId) + .switchMap( + (final i) => TimerStream(i, const Duration(milliseconds: 150))) + .first; + } + + Future removeSubject(final String deviceId) async { + final subject = _subjects[deviceId]; + if (subject != null) { + await subject.close(); + _subjects.remove(deviceId); + } else { + lighthouseLogger.info("Could not close subject for $deviceId"); + } + } + + Future removeAllSubjects() async { + for (final subject in _subjects.values) { + await subject.close(); + } + _subjects.clear(); + } +} diff --git a/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/helper/value_handler.dart b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/helper/value_handler.dart new file mode 100644 index 00000000..d42e7513 --- /dev/null +++ b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/helper/value_handler.dart @@ -0,0 +1,91 @@ +part of quick_blue_back_end; + +@immutable +class OperationItem { + const OperationItem(this.deviceId, this.characteristicId); + + final String deviceId; + final String characteristicId; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is OperationItem && + runtimeType == other.runtimeType && + deviceId == other.deviceId && + characteristicId == other.characteristicId; + + @override + int get hashCode => deviceId.hashCode ^ characteristicId.hashCode; +} + +class ValueHandler { + ValueHandler._() { + QuickBlue.setValueHandler(_valueHandler); + } + + void _valueHandler(final String deviceId, final String characteristicId, + final Uint8List value) { + final operation = OperationItem(deviceId, characteristicId); + final completer = _readCompleters[operation]; + if (completer != null) { + completer.complete(value); + } else { + lighthouseLogger.info("Could not handle new value for deviceId $deviceId " + "and characteristic $characteristicId"); + } + } + + Future readValue(final String deviceId, final String serviceId, + final String characteristicId) async { + final operation = OperationItem(deviceId, characteristicId); + final oldCompleter = _readCompleters[operation]; + if (oldCompleter != null && !oldCompleter.isCompleted) { + // TODO: custom error! + oldCompleter.completeError(Error()); + } + final completer = Completer(); + _readCompleters[operation] = completer; + + QuickBlue.readValue(deviceId, serviceId, characteristicId); + return completer.future; + } + + final Map> _readCompleters = {}; + + Future removeReadCompleter( + final String deviceId, final String characteristicId) async { + final operation = OperationItem(deviceId, characteristicId); + final completer = _readCompleters[operation]; + if (completer != null && !completer.isCompleted) { + // TODO: custom error! + completer.completeError(Error()); + _readCompleters.remove(operation); + } else { + lighthouseLogger.info("Could not close subject for $deviceId"); + } + } + + Future removeAllReadCompleter() async { + for (final completer in _readCompleters.values) { + if (!completer.isCompleted) { + // TODO: custom error! + completer.completeError(Error()); + } + } + _readCompleters.clear(); + } + + Future writeValue( + final String deviceId, + final String serviceId, + final String characteristicId, + final Uint8List value, + final bool withoutResponse) async { + BleOutputProperty property = withoutResponse + ? BleOutputProperty.withoutResponse + : BleOutputProperty.withResponse; + QuickBlue.writeValue( + deviceId, serviceId, characteristicId, value, property); + } +} diff --git a/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/quick_blue_back_end_io.dart b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/quick_blue_back_end_io.dart new file mode 100644 index 00000000..9ab0b5c7 --- /dev/null +++ b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/quick_blue_back_end_io.dart @@ -0,0 +1,174 @@ +library quick_blue_back_end; + +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:lighthouse_back_end/lighthouse_back_end.dart'; +import 'package:lighthouse_logger/lighthouse_logger.dart'; +import 'package:lighthouse_provider/lighthouse_provider.dart'; +import 'package:mutex/mutex.dart'; +import 'package:quick_blue/quick_blue.dart'; +import 'package:rxdart/rxdart.dart'; + +part 'ble/quick_blue_characteristic.dart'; +part 'ble/quick_blue_device.dart'; +part 'ble/quick_blue_service.dart'; +part 'helper/connection_handler.dart'; +part 'helper/service_handler.dart'; +part 'helper/value_handler.dart'; + +class QuickBlueBackEnd extends BLELighthouseBackEnd { + // Make sure there is always only one instance. + static QuickBlueBackEnd? _instance; + + QuickBlueBackEnd._(); + + static QuickBlueBackEnd get instance { + return _instance ??= QuickBlueBackEnd._(); + } + + // Some state variables. + final Mutex _devicesMutex = Mutex(); + final Set _connectingDevices = {}; + final Set _rejectedDevices = {}; + + final BehaviorSubject _foundDeviceSubject = + BehaviorSubject.seeded(null); + StreamSubscription? _scanResultSubscription; + Timer? _stopTimer; + + final ConnectionHandler _connectionHandler = ConnectionHandler._(); + final ServiceHandler _serviceHandler = ServiceHandler._(); + final ValueHandler _valueHandler = ValueHandler._(); + + @override + Stream get lighthouseStream => _foundDeviceSubject.stream; + + @override + Stream get state async* { + while (true) { + yield await QuickBlue.isBluetoothAvailable().then((final value) { + if (value) { + return BluetoothAdapterState.on; + } else { + return BluetoothAdapterState.unavailable; + } + }); + await Future.delayed(const Duration(seconds: 1)); + } + } + + @override + Future startScan( + {required Duration timeout, required Duration? updateInterval}) async { + await super.startScan(timeout: timeout, updateInterval: updateInterval); + _stopTimer?.cancel(); + await _startListeningScanResults(); + try { + QuickBlue.startScan(); + _stopTimer = Timer(timeout, () { + stopScan(); + }); + } catch (e, s) { + lighthouseLogger.severe("Unhandled exception", e, s); + rethrow; + } + } + + @override + Future cleanUp() async { + _foundDeviceSubject.add(null); + _connectingDevices.clear(); + _rejectedDevices.clear(); + if (_devicesMutex.isLocked) { + _devicesMutex.release(); + } + await Future.wait([ + _connectionHandler.removeAllSubjects(), + _serviceHandler.removeAllSubjects(), + _valueHandler.removeAllReadCompleter(), + ]); + } + + @override + Future stopScan() async { + _scanResultSubscription?.pause(); + _stopTimer?.cancel(); + _stopTimer = null; + try { + QuickBlue.stopScan(); + } catch (e, s) { + lighthouseLogger.severe("Unhandled exception", e, s); + rethrow; + } + } + + Future _startListeningScanResults() async { + var scanResultSubscription = _scanResultSubscription; + if (scanResultSubscription != null) { + if (!scanResultSubscription.isPaused) { + scanResultSubscription.pause(); + } + await scanResultSubscription.cancel(); + _scanResultSubscription = null; + } + + scanResultSubscription = QuickBlue.scanResultStream.where((final device) { + for (final deviceProvider in providers) { + if (deviceProvider.nameCheck(device.name)) { + return true; + } + } + return false; + }).listen((final device) { + final deviceIdentifier = LHDeviceIdentifier(device.deviceId); + + if (_connectingDevices.contains(deviceIdentifier) || + _rejectedDevices.contains(deviceIdentifier)) { + return; + } + + // Update the last seen item. + if (updateLastSeen?.call(deviceIdentifier) ?? false) { + return; + } + + // Possibly a new lighthouse, let's make sure it's valid. + _devicesMutex.acquire().then((final _) async { + _connectingDevices.add(deviceIdentifier); + if (_devicesMutex.isLocked) { + _devicesMutex.release(); + } + + final lighthouseDevice = await getLighthouseDevice( + FlutterReactiveBleBluetoothDevice( + device, _connectionHandler, _serviceHandler, _valueHandler)); + + try { + await _devicesMutex.acquire(); + if (lighthouseDevice == null) { + lighthouseLogger.warning( + "Found a non valid device! Device id: " + "${device.deviceId}", + null, + StackTrace.current); + _rejectedDevices.add(deviceIdentifier); + } else { + _foundDeviceSubject.add(lighthouseDevice); + } + _connectingDevices.remove(deviceIdentifier); + } finally { + if (_devicesMutex.isLocked) { + _devicesMutex.release(); + } + } + }); + }); + + // Clean-up for when the stream is canceled. + scanResultSubscription.onDone(() { + _scanResultSubscription = null; + }); + _scanResultSubscription = scanResultSubscription; + } +} diff --git a/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/quick_blue_back_end_unsupported.dart b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/quick_blue_back_end_unsupported.dart new file mode 100644 index 00000000..5a7ea151 --- /dev/null +++ b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/lib/src/quick_blue_back_end_unsupported.dart @@ -0,0 +1,30 @@ +import 'package:lighthouse_back_end/lighthouse_back_end.dart'; +import 'package:lighthouse_provider/lighthouse_provider.dart'; + +class QuickBlueBackEnd extends BLELighthouseBackEnd { + // Make sure there is always only one instance. + static QuickBlueBackEnd? _instance; + + QuickBlueBackEnd._(); + + static QuickBlueBackEnd get instance { + assert(() { + throw UnsupportedError("Quick blue not supported for this platform"); + }()); + return _instance ??= QuickBlueBackEnd._(); + } + + @override + Stream get lighthouseStream => throw UnsupportedError( + "Flutter reactive ble not supported for this platform"); + + @override + Stream get state => throw UnsupportedError( + "Flutter reactive ble not supported for this platform"); + + @override + Future stopScan() { + throw UnsupportedError( + "Flutter reactive ble not supported for this platform"); + } +} diff --git a/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/pubspec.yaml b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/pubspec.yaml new file mode 100644 index 00000000..4d7608ad --- /dev/null +++ b/lighthouse_provider/lighthouse_back_ends/quick_blue_back_end/pubspec.yaml @@ -0,0 +1,83 @@ +name: quick_blue_back_end +description: A lighthouse back end to use quick blue +version: 0.0.1 +publish_to: none + +environment: + sdk: '>=2.18.6 <3.0.0' + flutter: ">=3.3.1" + +dependencies: + flutter: + sdk: flutter + quick_blue: ^0.5.0-dev.2 + mutex: ^3.0.0 + rxdart: ^0.27.5 + lighthouse_back_end: + path: ../../lighthouse_back_end + lighthouse_provider: + path: ../../lighthouse_provider + shared_platform: + path: ../../../shared/shared_platform + lighthouse_logger: + path: ../../lighthouse_logger + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 + +platforms: + android: + ios: + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + # This section identifies this Flutter project as a plugin project. + # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) + # which should be registered in the plugin registry. This is required for + # using method channels. + # The Android 'package' specifies package in which the registered class is. + # This is required for using method channels on Android. + # The 'ffiPlugin' specifies that native code should be built and bundled. + # This is required for using `dart:ffi`. + # All these are used by the tooling to maintain consistency when + # adding or updating assets for this project. + # This plugin project was generated without specifying any + # platforms with the `--platform` argument. If you see the `some_platform` map below, remove it and + # then add platforms following the instruction here: + # https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms + + # To add assets to your plugin package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # To add custom fonts to your plugin package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages