Files
universal_ble/lib/src/universal_ble.dart
T
Rohit Sangwan 2fe21962d2 Add queue per device (#48)
* Add queue per device

* Improve API and documentation

* Update lib/src/universal_ble.dart

* Update lib/src/ble_command_queue.dart

---------

Co-authored-by: Foti Dim <fdimanidis@gmail.com>
Co-authored-by: Foti Dim <foti@navideck.com>
2024-06-07 20:55:46 +05:30

250 lines
8.6 KiB
Dart

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:universal_ble/src/ble_command_queue.dart';
import 'package:universal_ble/src/universal_ble_linux/universal_ble_linux.dart';
import 'package:universal_ble/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart';
import 'package:universal_ble/src/universal_ble_web/universal_ble_web.dart';
import 'package:universal_ble/universal_ble.dart';
class UniversalBle {
/// Get platform specific implementation
static UniversalBlePlatform _platform = _defaultPlatform();
static final BleCommandQueue _bleCommandQueue = BleCommandQueue();
/// Set custom platform specific implementation (e.g. for testing)
static void setInstance(UniversalBlePlatform instance) =>
_platform = instance;
/// Set global timeout for all commands.
/// Default timeout is 10 seconds
static set timeout(Duration? duration) {
_bleCommandQueue.timeout = duration;
}
/// Set how commands will be executed. By default, all commands are executed in a global queue (`QueueType.global`),
/// with each command waiting for the previous one to finish.
///
/// [QueueType.global] will execute commands of all devices in a single queue
/// [QueueType.perDevice] will execute command of each device in separate queues
/// [QueueType.none] will execute all commands in parallel
static set queueType(QueueType queueType) {
_bleCommandQueue.queueType = queueType;
UniversalBlePlatform.logInfo('Queue ${queueType.name}');
}
/// Get Bluetooth availability state
/// To be notified of updates, set [onAvailabilityChange] listener
static Future<AvailabilityState> getBluetoothAvailabilityState() async {
return await _bleCommandQueue.executeCommand(
() => _platform.getBluetoothAvailabilityState(),
);
}
/// Start scan.
/// Scan results will arrive in [onScanResult] listener
/// It might throw errors if Bluetooth is not available
/// `webRequestOptions` is supported on Web only
static Future<void> startScan({
ScanFilter? scanFilter,
}) async {
return await _bleCommandQueue.executeCommand(
() => _platform.startScan(scanFilter: scanFilter),
withTimeout: false,
);
}
/// Stop scan.
/// Set [onScanResult] listener to `null` if you don't need it anymore
/// It might throw errors if Bluetooth is not available
static Future<void> stopScan() async {
return await _bleCommandQueue.executeCommand(
() => _platform.stopScan(),
withTimeout: false,
);
}
/// Connect to a device.
/// Get notified of connection state changes in [onConnectionChanged] listener
/// It is advised to stop scanning before connecting
/// It might throw errors if device is not connectable
/// `connectionTimeout` is supported on Web only
static Future<void> connect(
String deviceId, {
Duration? connectionTimeout,
}) async {
return await _bleCommandQueue.executeCommand(
() => _platform.connect(deviceId, connectionTimeout: connectionTimeout),
deviceId: deviceId,
);
}
/// Disconnect from a device.
/// Get notified of connection state changes in [onConnectionChanged] listener
static Future<void> disconnect(String deviceId) async {
return await _bleCommandQueue.executeCommand(
() => _platform.disconnect(deviceId),
deviceId: deviceId,
);
}
/// Discover services of a device
static Future<List<BleService>> discoverServices(String deviceId) async {
return await _bleCommandQueue.executeCommand(
() => _platform.discoverServices(deviceId),
deviceId: deviceId,
);
}
/// Set a characteristic notifiable.
/// Set `bleInputProperty` to [BleInputProperty.notification] or [BleInputProperty.indication]
/// Updates will arrive in [onValueChanged] listener
/// To stop listening to a characteristic, set `bleInputProperty` to [BleInputProperty.disabled]
static Future<void> setNotifiable(
String deviceId,
String service,
String characteristic,
BleInputProperty bleInputProperty,
) async {
return await _bleCommandQueue.executeCommand(
() => _platform.setNotifiable(
deviceId,
service,
characteristic,
bleInputProperty,
),
deviceId: deviceId,
);
}
/// Read a characteristic value
/// On iOS and MacOS this command will also trigger [onValueChanged] listener
static Future<Uint8List> readValue(
String deviceId,
String service,
String characteristic,
) async {
return await _bleCommandQueue.executeCommand(
() => _platform.readValue(deviceId, service, characteristic),
deviceId: deviceId,
);
}
/// Write a characteristic value
/// To write a characteristic value with response, set `bleOutputProperty` to [BleOutputProperty.withResponse]
static Future<void> writeValue(
String deviceId,
String service,
String characteristic,
Uint8List value,
BleOutputProperty bleOutputProperty,
) async {
await _bleCommandQueue.executeCommand(
() => _platform.writeValue(
deviceId,
service,
characteristic,
value,
bleOutputProperty,
),
deviceId: deviceId,
);
}
/// Request MTU value
/// `requestMtu` is not supported on `Linux` and `Web
static Future<int> requestMtu(String deviceId, int expectedMtu) async {
return await _bleCommandQueue.executeCommand(
() => _platform.requestMtu(deviceId, expectedMtu),
deviceId: deviceId,
);
}
/// Check if a device is paired
/// Pair commands are not supported on `Apple` and `Web`
static Future<bool> isPaired(String deviceId) async {
return await _bleCommandQueue.executeCommand(
() => _platform.isPaired(deviceId),
deviceId: deviceId,
);
}
/// Trigger pair request
/// It might throw an error if device is already paired
static Future<void> pair(String deviceId) async {
return await _bleCommandQueue.executeCommand(
() => _platform.pair(deviceId),
deviceId: deviceId,
);
}
/// Unpair a device
/// It might throw an error if device is not paired
static Future<void> unPair(String deviceId) async {
return await _bleCommandQueue.executeCommand(
() => _platform.unPair(deviceId),
deviceId: deviceId,
);
}
/// Get connected devices to the system (connected by any app)
/// Use [withServices] to filter devices by services
/// On `Apple`, [withServices] is required to get connected devices, else [1800] service will be used as default filter
/// On `Android`, `Linux` and `Windows`, if [withServices] is used, then internally all services will be discovered for each device first (either by connecting or by using cached services)
/// Not supported on `Web`
static Future<List<BleScanResult>> getConnectedDevices({
List<String>? withServices,
}) async {
return await _bleCommandQueue.executeCommand(
() => _platform.getConnectedDevices(withServices),
);
}
/// Enable Bluetooth
/// It might throw errors if Bluetooth is not available
/// Not supported on `Web` and `Apple`
static Future<bool> enableBluetooth() async {
return await _bleCommandQueue.executeCommand(
() => _platform.enableBluetooth(),
);
}
/// Get Bluetooth state availability
static set onAvailabilityChange(OnAvailabilityChange? onAvailabilityChange) {
_platform.onAvailabilityChange = onAvailabilityChange;
if (onAvailabilityChange != null) {
getBluetoothAvailabilityState().then((value) {
onAvailabilityChange(value);
}).onError((error, stackTrace) => null);
}
}
/// Get updates of remaining items of a queue
static set onQueueUpdate(OnQueueUpdate? onQueueUpdate) =>
_bleCommandQueue.onQueueUpdate = onQueueUpdate;
/// Get scan results
static set onScanResult(OnScanResult? onScanResult) =>
_platform.onScanResult = onScanResult;
/// Get connection state changes
static set onConnectionChanged(OnConnectionChanged? onConnectionChanged) =>
_platform.onConnectionChanged = onConnectionChanged;
/// Get characteristic value updates, set `bleInputProperty` in [setNotifiable] to [BleInputProperty.notification] or [BleInputProperty.indication]
static set onValueChanged(OnValueChanged? onValueChanged) =>
_platform.onValueChanged = onValueChanged;
/// Get pair state changes,
static set onPairingStateChange(OnPairingStateChange pairingStateChange) =>
_platform.onPairingStateChange = pairingStateChange;
static UniversalBlePlatform _defaultPlatform() {
if (kIsWeb) return UniversalBleWeb.instance;
if (defaultTargetPlatform == TargetPlatform.linux) {
return UniversalBleLinux.instance;
}
return UniversalBlePigeonChannel.instance;
}
}