starwork_flutter/lib/ble/ble_service.dart

847 lines
31 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:async';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:starwork_flutter/base/app_logger.dart';
import 'package:starwork_flutter/ble/ble_config.dart';
import 'package:starwork_flutter/ble/command/base/base_ble_command.dart';
import 'package:starwork_flutter/ble/command/ble_command_manager.dart';
import 'package:starwork_flutter/ble/command/request/ble_cmd_get_private_key.dart';
import 'package:starwork_flutter/ble/command/request/ble_cmd_get_public_key.dart';
import 'package:starwork_flutter/ble/command/request/ble_cmd_read_lock_status.dart';
import 'package:starwork_flutter/ble/command/response/ble_cmd_get_private_key_parser.dart';
import 'package:starwork_flutter/ble/command/response/ble_cmd_get_public_key_parser.dart';
import 'package:starwork_flutter/ble/model/scan_device_info.dart';
import 'package:starwork_flutter/common/constant/device_type.dart';
/// ✨✨✨ 待发送命令类 ✨✨✨
class _PendingCommand<T> {
final BaseBleCommand<T> command;
final String targetDeviceId;
final String? targetDeviceName;
final Duration timeout;
final Completer<T?> completer;
final DateTime createdAt;
final int commandId; // 添加命令ID字段
_PendingCommand({
required this.command,
required this.targetDeviceId,
this.targetDeviceName,
required this.timeout,
required this.completer,
required this.commandId, // 添加命令ID参数
}) : createdAt = DateTime.now();
}
class BleService {
// 私有构造函数
BleService._() {
// ✅ 这里就是单例初始化的地方
// 只会执行一次(第一次获取实例时)
_initialize();
}
// 静态实例
static final BleService _instance = BleService._();
// 工厂构造函数,提供全局访问点
factory BleService() => _instance;
/// 用于存储最新的私钥避免在解密时需要异步读取SharedPreferences
static List<int>? _cachedPrivateKey;
/// 获取缓存的私钥
static List<int>? get cachedPrivateKey => _cachedPrivateKey;
/// 设置缓存的私钥
static void setCachedPrivateKey(List<int> privateKey) {
_cachedPrivateKey = List.from(privateKey);
}
/// 用来存储搜索到的设备,并用于去重和过滤
final Map<String, ScanResult> _discoveredDevices = {};
// 使用命令管理器处理数据包
final BleCommandManager bleCommandManager = BleCommandManager();
/// mtu大小
int _mtu = 23;
/// 用来监听蓝牙适配器状态的订阅流
StreamSubscription<BluetoothAdapterState>? _adapterStateSubscription;
/// 用来监听搜索到的设备的订阅流
StreamSubscription<List<ScanResult>>? _scanResultSubscription;
/// 用来监听连接设备时的连接状态
StreamSubscription<BluetoothConnectionState>? _connectionStateSubscription;
/// 用来监听mtu的变化
StreamSubscription<int>? _mtuChangeSubscription;
/// 用来监听订阅服务的数据
StreamSubscription<List<int>>? _characteristicDataSubscription;
/// 当前连接的设备
BluetoothDevice? _connectedDevice;
/// 当前的写入特征值
BluetoothCharacteristic? _writeCharacteristic;
/// 当前的订阅特征值
BluetoothCharacteristic? _subscriptionCharacteristic;
/// ✨✨✨ 命令响应等待器映射 ✨✨✨
final Map<String, Completer<dynamic>> _commandResponseWaiters = {};
/// ✨✨✨ 命令超时定时器映射 ✨✨✨
final Map<String, Timer> _commandTimeouts = {};
/// ✨✨✨ 命令ID到命令键的映射 ✨✨✨
final Map<int, String> _commandIdToKeyMap = {};
/// 待发送命令队列 (用于自动连接后发送)
final List<_PendingCommand<dynamic>> _pendingCommands = [];
/// 搜索状态监控定时器
Timer? _scanningMonitorTimer;
// 内部维护的蓝牙状态
BluetoothAdapterState _bluetoothAdapterState = BluetoothAdapterState.unknown;
// 内部维护的设备连接状态
BluetoothConnectionState _bluetoothConnectionState = BluetoothConnectionState.disconnected;
/// 提供外部获取蓝牙适配器方法
BluetoothAdapterState get bluetoothAdapterState => _bluetoothAdapterState;
/// 搜索状态
bool get isScanningNow => FlutterBluePlus.isScanningNow;
/// 获取当前连接的设备
BluetoothDevice? get connectedDevice => _connectedDevice;
/// 初始化服务时执行的
Future<void> _initialize() async {
AppLogger.highlight('🚀 BleService 正在初始化...');
/// 监听蓝牙适配器状态
_adapterStateSubscription = FlutterBluePlus.adapterState.listen((BluetoothAdapterState state) {
_bluetoothAdapterState = state;
AppLogger.highlight('蓝牙适配器状态发送变化:${state}');
});
AppLogger.highlight('✅ BleService 初始化完成');
}
/// 开启蓝牙搜索
void enableBluetoothSearch({
DeviceType deviceType = DeviceType.all,
Duration searchTime = const Duration(seconds: 15),
required void Function(ScanDeviceInfo device) onDeviceFound,
}) async {
// 检查蓝牙适配器状态
AppLogger.highlight('🔍 当前蓝牙适配器状态: $_bluetoothAdapterState');
// 如果状态是unknown等待一下状态更新
if (_bluetoothAdapterState == BluetoothAdapterState.unknown) {
AppLogger.highlight('⏳ 等待蓝牙适配器状态更新...');
await Future.delayed(const Duration(milliseconds: 500));
AppLogger.highlight('🔍 等待后蓝牙适配器状态: $_bluetoothAdapterState');
}
if (_bluetoothConnectionState == BluetoothConnectionState.connected) {
// 搜索时断开已有连接
List<BluetoothDevice> devs = FlutterBluePlus.connectedDevices;
for (var d in devs) {
d.disconnect();
}
}
if (_bluetoothAdapterState == BluetoothAdapterState.on) {
AppLogger.highlight('🚀 开始启动蓝牙扫描,搜索时长: ${searchTime.inSeconds}');
try {
FlutterBluePlus.startScan(timeout: searchTime);
/// 取消旧的订阅,防止重复
_scanResultSubscription?.cancel();
_discoveredDevices.clear();
/// 监听搜索到的设备
_scanResultSubscription = FlutterBluePlus.onScanResults.listen(
(List<ScanResult> results) {
for (var result in results) {
var device = result.device;
final deviceId = device.remoteId.toString();
final platformName = device.platformName;
var serviceUuids = result.advertisementData.serviceUuids;
// ✅ 只有新设备才回调
if (!_discoveredDevices.containsKey(deviceId) && platformName.isNotEmpty) {
_discoveredDevices[deviceId] = result;
bool pairStatus = false;
bool hasNewEvent = false;
for (var uuid in serviceUuids) {
String uuidStr = uuid.toString().replaceAll('-', '');
if (uuidStr.length == 8) {
var pairStatusStr = uuidStr.substring(4, 6);
var hasNewEventStr = uuidStr.substring(6, 8);
pairStatus = pairStatusStr == '01';
hasNewEvent = hasNewEventStr == '01';
var scanDeviceInfo = ScanDeviceInfo(
isBinding: pairStatus,
advName: device.platformName,
rawDeviceInfo: result,
hasNewEvent: hasNewEvent,
);
onDeviceFound.call(scanDeviceInfo);
} else if (uuidStr.length == 32) {
var pairStatusStr = uuidStr.substring(26, 28);
pairStatus = pairStatusStr == '00'; // 第4、5位索引3和4
int statusValue = int.parse(pairStatusStr, radix: 16);
// 提取 byte0配对状态第1位
int byte0 = (statusValue >> 0) & 0x01; // 取最低位
// 提取 byte1事件状态第2位
int byte1 = (statusValue >> 1) & 0x01; // 取次低位
// 判断是否未配对
pairStatus = (byte0 == 1);
// 判断是否有新事件
hasNewEvent = (byte1 == 1);
var scanDeviceInfo = ScanDeviceInfo(
isBinding: pairStatus,
advName: device.platformName,
rawDeviceInfo: result,
hasNewEvent: hasNewEvent,
);
onDeviceFound.call(scanDeviceInfo);
}
}
} else {
// 可选:更新 RSSI
_discoveredDevices[deviceId] = result;
}
}
},
onError: (e) => AppLogger.error('搜索设备时遇到错误:' + e),
);
AppLogger.highlight('✅ 蓝牙搜索已成功启动');
// 监听搜索状态变化
_monitorScanningState();
} catch (e, stackTrace) {
AppLogger.error('启动蓝牙搜索失败', error: e, stackTrace: stackTrace);
}
} else {
AppLogger.error('❌ 蓝牙适配器未开启,当前状态: $_bluetoothAdapterState');
}
}
/// 监控搜索状态变化
void _monitorScanningState() {
// 取消之前的定时器
_scanningMonitorTimer?.cancel();
_scanningMonitorTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
bool currentlyScanning = FlutterBluePlus.isScanningNow;
if (!currentlyScanning) {
AppLogger.highlight('🔍 搜索已停止 (监控器检测)');
timer.cancel();
_scanningMonitorTimer = null;
}
});
}
/// 停止扫描
void stopBluetoothSearch() async {
var isScanningNow = FlutterBluePlus.isScanningNow;
if (isScanningNow) {
FlutterBluePlus.stopScan();
}
// 取消搜索状态监控定时器
_scanningMonitorTimer?.cancel();
_scanningMonitorTimer = null;
/// 清空搜索到的设备
_discoveredDevices.clear();
AppLogger.highlight('🛑 蓝牙搜索已停止');
}
void seedData({
required BaseBleCommand command,
}) async {
// 搜索时断开已有连接
List<BluetoothDevice> devs = FlutterBluePlus.connectedDevices;
for (var d in devs) {
d.disconnect();
}
}
/// 监听连接设备时的状态
void _handleListenBluetoothConnectionState(BluetoothConnectionState state) {
_bluetoothConnectionState = state;
}
/// 监听mtu变化
void _handleListenMtuChange(int mtu) {
_mtu = mtu;
BaseBleCommand.MAX_PACKET_DATA_SIZE = mtu;
}
/// 用于存储分包接收的数据
final Map<int, List<int>> _pendingPackets = {};
/// 监听订阅值变化
void _handleListenCharacteristicData(List<int> data) {
AppLogger.highlight('✨✨✨ 📨 收到订阅数据:$data (长度: ${data.length}) ✨✨✨');
// 解析数据
if (data.isNotEmpty) {
// ✨✨✨ 处理分包数据重组 ✨✨✨
List<int>? completePacket = _reassemblePacket(data);
if (completePacket != null) {
// 如果有完整数据包,进行处理
dynamic result = bleCommandManager.handleResponse(completePacket);
if (result != null) {
// 触发命令响应等待器
_triggerCommandResponseWaiters(result);
} else {
AppLogger.warn('⚠️ 数据包解析失败或不匹配任何命令');
}
}
} else {
AppLogger.warn('✨✨✨ ⚠️ 收到空数据 ✨✨✨');
}
}
/// ✨✨✨ 重组分包数据 ✨✨✨
/// [data] 接收到的数据片段
/// 返回完整的数据包如果数据不完整则返回null
List<int>? _reassemblePacket(List<int> data) {
try {
// 1. 检查是否是包头开始的数据
if (data.length >= 4 &&
data[0] == BaseBleCommand.PACKET_HEADER[0] &&
data[1] == BaseBleCommand.PACKET_HEADER[1] &&
data[2] == BaseBleCommand.PACKET_HEADER[2] &&
data[3] == BaseBleCommand.PACKET_HEADER[3]) {
// 这是一个新包的开始
// 首先检查是否已有未完成的包,如果有则丢弃(超时处理)
if (_pendingPackets.isNotEmpty) {
AppLogger.warn('⚠️ 检测到新包开始,丢弃未完成的包');
_pendingPackets.clear();
}
// 解析包头信息以获取预期长度
if (data.length >= 12) {
// 解析包序号 (大端序)
int packetSequence = (data[5] << 8) | data[6];
// 解析数据长度 (大端序: 高16位加密后长度 + 低16位原始长度)
int combinedLength = (data[8] << 24) | (data[9] << 16) | (data[10] << 8) | data[11];
int encryptedDataLength = (combinedLength >> 16) & 0xFFFF;
int originalDataLength = combinedLength & 0xFFFF;
// 根据加密类型确定实际数据长度
int encryptType = data[7] & 0x0F;
int actualDataLength = (encryptType == BaseBleCommand.ENCRYPT_TYPE_PLAIN) ? originalDataLength : encryptedDataLength;
// 计算完整包的预期长度
int expectedTotalLength = 12 + actualDataLength + 2; // 包头到数据长度(12) + 数据块 + CRC(2)
AppLogger.debug('📦 新包开始: 序号=$packetSequence, 预期长度=$expectedTotalLength, 实际长度=${data.length}');
if (data.length == expectedTotalLength) {
// 数据完整,直接返回
AppLogger.debug('✅ 数据包完整,无需重组');
return data;
} else if (data.length < expectedTotalLength) {
// 数据不完整,存储到待处理队列
AppLogger.debug('📥 数据包不完整,开始重组: 已接收${data.length}/$expectedTotalLength字节');
_pendingPackets[packetSequence] = List.from(data);
return null;
} else {
// 数据长度超过预期,可能存在错误
AppLogger.warn('⚠️ 数据包长度异常: 实际${data.length}字节 > 预期$expectedTotalLength字节');
return data;
}
} else {
// 包头信息不完整
AppLogger.warn('⚠️ 包头信息不完整,无法解析包长度');
return data;
}
} else {
// 这是数据片段,尝试追加到现有未完成的包
if (_pendingPackets.isNotEmpty) {
// 获取第一个(也是唯一一个)未完成的包
int packetSequence = _pendingPackets.keys.first;
List<int> pendingData = _pendingPackets[packetSequence]!;
// 追加数据
pendingData.addAll(data);
_pendingPackets[packetSequence] = pendingData;
AppLogger.debug('📥 追加数据片段: 当前长度${pendingData.length}字节');
// 尝试解析包头信息以检查是否完整
if (pendingData.length >= 12) {
// 解析数据长度
int combinedLength = (pendingData[8] << 24) | (pendingData[9] << 16) | (pendingData[10] << 8) | pendingData[11];
int encryptedDataLength = (combinedLength >> 16) & 0xFFFF;
int originalDataLength = combinedLength & 0xFFFF;
// 根据加密类型确定实际数据长度
int encryptType = pendingData[7] & 0x0F;
int actualDataLength = (encryptType == BaseBleCommand.ENCRYPT_TYPE_PLAIN) ? originalDataLength : encryptedDataLength;
// 计算完整包的预期长度
int expectedTotalLength = 12 + actualDataLength + 2; // 包头到数据长度(12) + 数据块 + CRC(2)
if (pendingData.length == expectedTotalLength) {
// 数据完整,返回完整包并清理待处理队列
AppLogger.debug('✅ 数据包重组完成: 序号=$packetSequence, 长度=$expectedTotalLength字节');
List<int> completePacket = _pendingPackets.remove(packetSequence)!;
return completePacket;
} else if (pendingData.length > expectedTotalLength) {
// 数据长度超过预期,可能存在错误
AppLogger.warn('⚠️ 重组后数据包长度异常: 实际${pendingData.length}字节 > 预期$expectedTotalLength字节');
_pendingPackets.clear();
return pendingData;
}
// 如果长度还不够,继续等待更多数据
}
// 如果包头信息还不完整,继续等待更多数据
return null;
} else {
// 没有未完成的包,但收到的数据不是包头开始的数据
AppLogger.warn('⚠️ 收到无法关联的数据片段');
return data;
}
}
} catch (e, stackTrace) {
AppLogger.error('❌ 数据包重组异常', error: e, stackTrace: stackTrace);
_pendingPackets.clear(); // 清理异常状态
return data; // 返回原始数据让后续处理尝试解析
}
}
/// ✨✨✨ 触发命令响应等待器 ✨✨✨
void _triggerCommandResponseWaiters(dynamic response) {
// 遍历所有等待中的命令,找到匹配的进行响应
List<String> completedKeys = [];
int commandId = response.commandId;
String? commandKey = _commandIdToKeyMap[commandId];
if (commandKey != null) {
// 精确匹配到特定命令
Completer? completer = _commandResponseWaiters[commandKey];
if (completer != null && !completer.isCompleted) {
AppLogger.debug('🔔 精确匹配命令响应: 命令ID=0x${commandId.toRadixString(16).padLeft(4, '0')}, 键=$commandKey');
completer.complete(response);
completedKeys.add(commandKey);
// 清理已完成的等待器
_cleanupCommandWaiter(commandKey);
_commandIdToKeyMap.remove(commandId);
return;
}
}
// 如果没有精确匹配,回退到原来的逻辑(完成所有未完成的等待器)
_commandResponseWaiters.forEach((key, completer) {
if (!completer.isCompleted) {
AppLogger.debug('🔔 触发命令响应(回退模式): $key');
completer.complete(response);
completedKeys.add(key);
}
});
// 清理已完成的等待器
for (String key in completedKeys) {
_cleanupCommandWaiter(key);
}
}
/// ✨✨✨ 发送蓝牙命令 ✨✨✨
Future<T?> sendCommand<T>({
required BaseBleCommand<T> command,
String? targetDeviceId,
String? targetDeviceName,
Duration timeout = const Duration(seconds: 10),
bool autoConnectIfNeeded = true,
Duration searchTimeoutIfNeeded = const Duration(seconds: 15),
}) async {
AppLogger.highlight('✨✨✨ 🚀 开始发送蓝牙命令: ${command.runtimeType} ✨✨✨');
try {
// 1. 检查连接状态
bool isConnected = await _ensureDeviceConnected(
targetDeviceId: targetDeviceId,
targetDeviceName: targetDeviceName,
autoConnect: autoConnectIfNeeded,
searchTimeout: searchTimeoutIfNeeded,
);
if (!isConnected) {
throw Exception('设备未连接,无法发送命令');
}
// 2. 检查写入特征值
if (_writeCharacteristic == null) {
throw Exception('写入特征值未初始化');
}
// 3. 构建命令数据包
List<List<int>> packets = command.build();
AppLogger.info('📦 命令数据包数量: ${packets.length}');
// 4. 设置命令响应等待器
String commandKey = _generateCommandKey(command);
Completer<T?> responseCompleter = Completer<T?>();
_commandResponseWaiters[commandKey] = responseCompleter;
// 5. 如果命令有cmdId静态字段将其与命令键关联
_registerCommandId(command, commandKey);
// 6. 设置超时定时器
Timer timeoutTimer = Timer(timeout, () {
if (!responseCompleter.isCompleted) {
_cleanupCommandWaiter(commandKey);
responseCompleter.completeError(TimeoutException('命令响应超时', timeout));
}
});
_commandTimeouts[commandKey] = timeoutTimer;
// 7. 发送数据包
for (int i = 0; i < packets.length; i++) {
List<int> packet = packets[i];
AppLogger.debug('📤 发送第${i + 1}个数据包,数据包: (${packet.toString()},长度:${packet.length}字节)');
await _writeCharacteristic!.write(packet, withoutResponse: false);
// 在多包发送时稍微延迟
// if (i < packets.length - 1) {
// await Future.delayed(const Duration(milliseconds: 50));
// }
}
AppLogger.info('✅ 所有数据包发送完成,等待应答...');
// 8. 等待响应
T? response = await responseCompleter.future;
AppLogger.highlight('✨✨✨ ✅ 命令发送成功,收到应答: $response ✨✨✨');
return response;
} catch (e, stackTrace) {
AppLogger.error('❌ 发送蓝牙命令失败', error: e, stackTrace: stackTrace);
rethrow;
}
}
/// 将命令对象映射到 commandKey特定命令需手动注册 cmdId
void _registerCommandId(dynamic command, String commandKey) {
try {
final int? commandId = switch (command) {
BleCmdGetPublicKey() => BleCmdGetPublicKey.cmdId,
BleCmdGetPrivateKey() => BleCmdGetPrivateKey.cmdId,
BleCmdReadLockStatus() => BleCmdReadLockStatus.cmdId,
// 可在此添加更多命令类型
// BleCmdAnother() => BleCmdAnother.cmdId,
_ => null, // 默认情况:无法识别的命令类型
};
if (commandId != null) {
_commandIdToKeyMap[commandId] = commandKey;
AppLogger.debug(
'📝 命令ID映射: 0x${commandId.toRadixString(16).padLeft(4, '0')} -> $commandKey',
);
} else {
AppLogger.debug('❓ 未知命令类型,无法注册 commandId: $commandKey');
}
} catch (e) {
AppLogger.warn('⚠️ 无法获取命令ID: $e');
}
}
void cancel() {
/// 销毁蓝牙适配器监听
_adapterStateSubscription?.cancel();
_scanResultSubscription?.cancel();
_connectionStateSubscription?.cancel();
_mtuChangeSubscription?.cancel();
_characteristicDataSubscription?.cancel();
/// 取消搜索状态监控定时器
_scanningMonitorTimer?.cancel();
_scanningMonitorTimer = null;
/// 清理命令等待器
for (String key in _commandResponseWaiters.keys) {
_cleanupCommandWaiter(key);
}
_commandResponseWaiters.clear();
_commandTimeouts.clear();
_commandIdToKeyMap.clear(); // 清空命令ID映射
/// 清理待发送命令
for (_PendingCommand<dynamic> pendingCmd in _pendingCommands) {
if (!pendingCmd.completer.isCompleted) {
pendingCmd.completer.completeError(Exception('服务已关闭'));
}
}
_pendingCommands.clear();
/// 重置连接状态
_bluetoothAdapterState = BluetoothAdapterState.unknown;
_connectedDevice = null;
_writeCharacteristic = null;
_subscriptionCharacteristic = null;
AppLogger.highlight('🗑️ BleService 资源已清理');
}
/// ✨✨✨ 确保设备已连接 ✨✨✨
Future<bool> _ensureDeviceConnected({
String? targetDeviceId,
String? targetDeviceName,
bool autoConnect = true,
Duration searchTimeout = const Duration(seconds: 15),
}) async {
// 1. 检查当前连接状态
if (_connectedDevice != null && _bluetoothConnectionState == BluetoothConnectionState.connected) {
// 如果指定了目标设备ID检查是否匹配
if (targetDeviceId != null && _connectedDevice!.remoteId.toString() != targetDeviceId) {
AppLogger.info('🔄 当前连接的设备与目标不匹配,需要切换连接');
await _connectedDevice!.disconnect();
_connectedDevice = null;
_writeCharacteristic = null;
_subscriptionCharacteristic = null;
} else {
AppLogger.info('✅ 设备已连接,无需重新连接');
return true;
}
}
// 2. 如果不允许自动连接,直接返回失败
if (!autoConnect) {
AppLogger.warn('⚠️ 设备未连接且不允许自动连接');
return false;
}
// 3. 尝试查找已连接的设备
List<BluetoothDevice> connectedDevices = FlutterBluePlus.connectedDevices;
if (targetDeviceId != null) {
for (BluetoothDevice device in connectedDevices) {
if (device.remoteId.toString() == targetDeviceId) {
AppLogger.info('🔗 找到已连接的目标设备');
return await _setupDeviceConnection(device);
}
}
}
// 4. 需要搜索并连接设备
AppLogger.info('🔍 开始搜索目标设备...');
BluetoothDevice? foundDevice = await _searchForTargetDevice(
targetDeviceId: targetDeviceId,
targetDeviceName: targetDeviceName,
searchTimeout: searchTimeout,
);
if (foundDevice == null) {
AppLogger.error('❌ 未找到目标设备');
return false;
}
// 5. 连接设备
AppLogger.info('🔗 开始连接设备: ${foundDevice.platformName}');
return await _connectToDevice(foundDevice);
}
/// ✨✨✨ 搜索目标设备 ✨✨✨
Future<BluetoothDevice?> _searchForTargetDevice({
String? targetDeviceId,
String? targetDeviceName,
Duration searchTimeout = const Duration(seconds: 15),
}) async {
Completer<BluetoothDevice?> searchCompleter = Completer<BluetoothDevice?>();
// 启动搜索
enableBluetoothSearch(
searchTime: searchTimeout,
onDeviceFound: (ScanDeviceInfo deviceInfo) {
BluetoothDevice device = deviceInfo.rawDeviceInfo.device;
String deviceId = device.remoteId.toString();
String deviceName = device.platformName;
AppLogger.debug('🔍 发现设备: $deviceName ($deviceId)');
// 检查是否匹配目标设备
bool isTargetDevice = false;
if (targetDeviceId != null && deviceId == targetDeviceId) {
isTargetDevice = true;
AppLogger.info('🎯 通过ID匹配到目标设备: $deviceName');
} else if (targetDeviceName != null && deviceName.contains(targetDeviceName)) {
isTargetDevice = true;
AppLogger.info('🎯 通过名称匹配到目标设备: $deviceName');
}
if (isTargetDevice && !searchCompleter.isCompleted) {
searchCompleter.complete(device);
}
},
);
// 设置超时
Timer(searchTimeout, () {
if (!searchCompleter.isCompleted) {
searchCompleter.complete(null);
}
});
return await searchCompleter.future;
}
/// ✨✨✨ 连接到设备 ✨✨✨
Future<bool> _connectToDevice(BluetoothDevice device) async {
try {
AppLogger.info('🔗 正在连接设备: ${device.platformName}');
await device.connect(timeout: const Duration(seconds: 10));
// 设置连接设备
return await _setupDeviceConnection(device);
} catch (e) {
AppLogger.error('❌ 连接设备失败: ${device.platformName}', error: e);
return false;
}
}
/// ✨✨✨ 设置设备连接 ✨✨✨
Future<bool> _setupDeviceConnection(BluetoothDevice device) async {
try {
AppLogger.info('🔧 设置设备连接: ${device.platformName}');
// 更新内部状态
_connectedDevice = device;
// 监听连接状态
_connectionStateSubscription?.cancel();
_connectionStateSubscription = device.connectionState.listen(_handleListenBluetoothConnectionState);
// 监听MTU变化
_mtuChangeSubscription?.cancel();
_mtuChangeSubscription = device.mtu.listen(_handleListenMtuChange);
// 发现服务
List<BluetoothService> services = await device.discoverServices();
AppLogger.info('🔍 发现服务数量: ${services.length}');
// 查找目标服务
BluetoothService? targetService;
for (BluetoothService service in services) {
if (service.uuid == BleConfig.serviceId) {
targetService = service;
break;
}
}
if (targetService == null) {
throw Exception('未找到目标服务: ${BleConfig.serviceId}');
}
AppLogger.info('✅ 找到目标服务: ${targetService.uuid}');
// 查找特征值
BluetoothCharacteristic? writeChar;
BluetoothCharacteristic? subscribeChar;
for (BluetoothCharacteristic characteristic in targetService.characteristics) {
if (characteristic.uuid == BleConfig.characteristicIdWrite) {
writeChar = characteristic;
AppLogger.info('✅ 找到写入特征值: ${characteristic.uuid}');
} else if (characteristic.uuid == BleConfig.characteristicIdSubscription) {
subscribeChar = characteristic;
AppLogger.info('✅ 找到订阅特征值: ${characteristic.uuid}');
}
}
if (writeChar == null || subscribeChar == null) {
throw Exception('未找到所需的特征值');
}
// 设置特征值
_writeCharacteristic = writeChar;
_subscriptionCharacteristic = subscribeChar;
// 订阅通知
await subscribeChar.setNotifyValue(true);
AppLogger.info('✅ 已订阅通知');
// 监听数据
_characteristicDataSubscription?.cancel();
_characteristicDataSubscription = subscribeChar.onValueReceived.listen(_handleListenCharacteristicData);
AppLogger.highlight('✨✨✨ ✅ 设备连接设置完成 ✨✨✨');
// 处理待发送的命令
await _processPendingCommands();
return true;
} catch (e, stackTrace) {
AppLogger.error('❌ 设置设备连接失败', error: e, stackTrace: stackTrace);
_connectedDevice = null;
_writeCharacteristic = null;
_subscriptionCharacteristic = null;
return false;
}
}
/// ✨✨✨ 处理待发送的命令 ✨✨✨
Future<void> _processPendingCommands() async {
if (_pendingCommands.isEmpty) return;
AppLogger.info('📦 处理待发送命令: ${_pendingCommands.length}');
List<_PendingCommand<dynamic>> commandsToProcess = List.from(_pendingCommands);
_pendingCommands.clear();
for (_PendingCommand<dynamic> pendingCmd in commandsToProcess) {
try {
AppLogger.info('🚀 发送待处理命令: ${pendingCmd.commandId}');
dynamic result = await sendCommand(
command: pendingCmd.command,
targetDeviceId: pendingCmd.targetDeviceId,
targetDeviceName: pendingCmd.targetDeviceName,
timeout: pendingCmd.timeout,
);
pendingCmd.completer.complete(result);
} catch (e) {
pendingCmd.completer.completeError(e);
}
}
}
/// ✨✨✨ 生成命令唯一标识 ✨✨✨
String _generateCommandKey<T>(BaseBleCommand<T> command) {
return '${command.runtimeType}_${DateTime.now().millisecondsSinceEpoch}';
}
/// ✨✨✨ 清理命令等待器 ✨✨✨
void _cleanupCommandWaiter(String commandKey) {
// 从命令ID映射中移除
_commandIdToKeyMap.removeWhere((commandId, key) => key == commandKey);
_commandResponseWaiters.remove(commandKey);
Timer? timer = _commandTimeouts.remove(commandKey);
timer?.cancel();
}
}