import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:get_storage/get_storage.dart'; import 'package:get/get.dart'; import 'package:ble_service/ble_service.dart'; import 'package:agent_service/agent_service.dart'; import '../models/user_Info.dart' as userInfo; import '/data/models/appconfig_model.dart'; import '../../data/models/appconfig.dart'; import '../../core/translations/app_translations.dart'; import '../../core/utils/logger.dart'; import 'bluetooth_manager.dart'; import 'language_manager.dart'; import 'network/dio_manager.dart'; import '../../routes/app_routes.dart'; // 重新导出BLE连接状态常量,让外部可以通过BleManager访问 export 'package:ble_service/ble_service.dart' show BleConnectionState; /// 命令类型常量(与原生层保持一致) class BleCommands { static const int GET_VERSION = 0x01; static const int GET_PRODUCT_ID = 0x02; static const int GET_PRODUCT_COLOR = 0x03; static const int GET_BATTERY_INFO = 0x04; static const int CONTROL_CODEC = 0x05; static const int GET_WAKEUP_VERSION = 0x08; static const int GET_VOICE_WAKEUP_STATUS = 0x14; static const int SET_VOICE_WAKEUP_STATUS = 0x15; /// 设备上报开启通话翻译 0x16 (帧头0xCC, cmdLen=0x01, status=0xFF) static const int CALL_TRANSLATION_ON = 0x16; /// 设备上报关闭通话翻译 0x17 (帧头0xCC, cmdLen=0x01, status=0xFF) static const int CALL_TRANSLATION_OFF = 0x17; } /// 判断编解码控制指令是否成功 /// /// 根据 rawData 第二字节是否为非 0 来判断: /// - 成功:第二字节不为 0 /// - 失败或无法解析:返回 false bool _isCodecControlSuccess(Map data) { final dynamic raw = data['rawData']; if (raw == null) return false; int? secondByte; if (raw is List) { if (raw.length >= 2) { final s = raw[1]; if (s is int) { secondByte = s; } else if (s is num) { secondByte = s.toInt(); } else if (s is String) { final t = s.trim(); if (t.startsWith('0x') || t.startsWith('0X')) { secondByte = int.tryParse(t.substring(2), radix: 16); } else { secondByte = int.tryParse(t); } } } } else if (raw is String) { final normalized = raw.trim().replaceAll('[', '').replaceAll(']', ''); final parts = normalized.split(RegExp(r'[,\s]+')).where((e) => e.isNotEmpty).toList(); if (parts.length >= 2) { final t = parts[1].trim(); if (t.startsWith('0x') || t.startsWith('0X')) { secondByte = int.tryParse(t.substring(2), radix: 16); } else { secondByte = int.tryParse(t); } } } else if (raw is Map) { final dynamic s = raw['second'] ?? raw['status2'] ?? raw['result']; if (s is int) { secondByte = s; } else if (s is num) { secondByte = s.toInt(); } else if (s is String) { final t = s.trim(); if (t.startsWith('0x') || t.startsWith('0X')) { secondByte = int.tryParse(t.substring(2), radix: 16); } else { secondByte = int.tryParse(t); } } } else { // 无法解析的类型 return false; } return secondByte != null && secondByte != 0; } /// 蓝牙设备信息缓存模型 class DeviceInfo { final String address; final String name; // 整体电池电量 final int batteryLevel; // 详细电池信息 final int leftEarBattery; final int rightEarBattery; final int caseBattery; // 充电状态 final bool leftEarCharging; final bool rightEarCharging; final bool caseCharging; final String firmwareVersion; final String firmwareProductId; final String firmwareProductColor; final DateTime lastUpdated; //唤醒词版本 final String wakeupLeftVersion; final String wakeupRightVersion; DeviceInfo({ required this.address, required this.name, this.batteryLevel = 0, this.leftEarBattery = 0, this.rightEarBattery = 0, this.caseBattery = 0, this.leftEarCharging = false, this.rightEarCharging = false, this.caseCharging = false, this.firmwareVersion = '', this.firmwareProductId = '', this.firmwareProductColor = '', DateTime? lastUpdated, this.wakeupLeftVersion = '', this.wakeupRightVersion = '', }) : lastUpdated = lastUpdated ?? DateTime.now(); /// 创建更新后的设备信息副本 DeviceInfo copyWith({ String? address, String? name, int? batteryLevel, int? leftEarBattery, int? rightEarBattery, int? caseBattery, bool? leftEarCharging, bool? rightEarCharging, bool? caseCharging, String? firmwareVersion, String? firmwareProductId, String? firmwareProductColor, String? wakeupLeftVersion, String? wakeupRightVersion, }) { return DeviceInfo( address: address ?? this.address, name: name ?? this.name, batteryLevel: batteryLevel ?? this.batteryLevel, leftEarBattery: leftEarBattery ?? this.leftEarBattery, rightEarBattery: rightEarBattery ?? this.rightEarBattery, caseBattery: caseBattery ?? this.caseBattery, leftEarCharging: leftEarCharging ?? this.leftEarCharging, rightEarCharging: rightEarCharging ?? this.rightEarCharging, caseCharging: caseCharging ?? this.caseCharging, firmwareVersion: firmwareVersion ?? this.firmwareVersion, firmwareProductId: firmwareProductId ?? this.firmwareProductId, firmwareProductColor: firmwareProductColor ?? this.firmwareProductColor, lastUpdated: DateTime.now(), wakeupLeftVersion: wakeupLeftVersion ?? this.wakeupLeftVersion, wakeupRightVersion: wakeupRightVersion ?? this.wakeupRightVersion, ); } @override String toString() { return 'DeviceInfo(address: $address, name: $name, ' 'battery: $batteryLevel%, L: $leftEarBattery%, R: $rightEarBattery%, Case: $caseBattery%, ' 'charging: L:$leftEarCharging, R:$rightEarCharging, C:$caseCharging, ' 'version: $firmwareVersion, ' 'wakeupLeftVersion: $wakeupLeftVersion, ' 'wakeupRightVersion: $wakeupRightVersion)'; } } /// BLE管理器 - 专门处理BLE设备连接和信息管理 class BleManager extends GetxService { static BleManager get to => Get.find(); // BLE服务实例 final BleService _bleService = BleService(); // 经典蓝牙实例 // 当前连接的设备信息 String? currentDeviceAddress; String? _currentDeviceName; // BLE连接状态 final _connectionState = BleConnectionState.disconnected.obs; int get connectionState => _connectionState.value; // 公开的连接状态流,供外部监听 RxInt get connectionStateRx => _connectionState; // 连接状态监听 final _isCall = false.obs; final _isConnected = false.obs; bool get isConnected => _isConnected.value; bool get isCall => _isCall.value; // 设备信息缓存 final deviceInfo = Rx(null); // 使用 Rx 包装 //添加编码器状态跟踪 final _isCodecActive = false.obs; bool get isCodecActive => _isCodecActive.value; RxBool get isCodecActiveRx => _isCodecActive; bool _awaitingCodecOpen = false; //是否正在等待编码器打开的成功应答 bool _awaitingCodecClose = false; //是否正在等待编码器关闭的成功应答 // 语音唤醒状态 final _voiceWakeupEnabled = true.obs; // 唤醒开关状态,默认开启 bool get voiceWakeupEnabled => _voiceWakeupEnabled.value; RxBool get voiceWakeupEnabledRx => _voiceWakeupEnabled; final _voiceWakeupSupported = false.obs; // 耳机是否支持语音唤醒功能 bool get voiceWakeupSupported => _voiceWakeupSupported.value; RxBool get voiceWakeupSupportedRx => _voiceWakeupSupported; // 订阅 StreamSubscription? _statusSubscription; StreamSubscription? _dataSubscription; final GetStorage _storage = GetStorage(); final _wakeupVoiceUpgradeProgress = 0.obs; // 唤醒语音升级进度 RxInt get wakeupVoiceUpgradeProgress => _wakeupVoiceUpgradeProgress; final _wakeupVoiceUpgradeStatus = 0.obs; // 唤醒语音升级状态 0: 未升级 1: 升级中 2: 升级成功 3: 升级失败 RxInt get wakeupVoiceUpgradeStatus => _wakeupVoiceUpgradeStatus; /// 设备上报通话翻译开关信号流 /// true = 设备上报开启通话翻译 (0x16),false = 设备上报关闭通话翻译 (0x17) /// 外部(如 TranslationController)可监听该流,收到信号后启动/停止通话翻译功能。 final StreamController _callTranslationRequestController = StreamController.broadcast(); Stream get onCallTranslationRequest => _callTranslationRequestController.stream; /// 初始化 @override void onInit() { super.onInit(); Logger.info('BLE管理器初始化'); // 设置BLE事件监听 _setupBleListener(); } /// 释放资源 @override void onClose() { _statusSubscription?.cancel(); _dataSubscription?.cancel(); _callTranslationRequestController.close(); super.onClose(); } /// 设置BLE事件监听 void _setupBleListener() { _statusSubscription?.cancel(); _dataSubscription?.cancel(); try { _statusSubscription = _bleService.onStatusUpdated.listen( (event) { if (event is! Map) return; if (event['type'] == 'connectionStateChanged') { final state = event['state'] as int; final oldState = _connectionState.value; _connectionState.value = state; Logger.i('BleManager', 'BLE状态更新: $oldState → $state'); if (state == BleConnectionState.connected) { _isConnected.value = true; } else if (state == BleConnectionState.disconnected || state == BleConnectionState.error) { _isConnected.value = false; _awaitingCodecOpen = false; _awaitingCodecClose = false; _isCodecActive.value = false; _voiceWakeupSupported.value = false; _voiceWakeupEnabled.value = true; Logger.i('BleManager', '[VoiceWakeup] 断开连接,重置 supported=false, enabled=true'); _updateDeviceInfoIfNeeded( batteryLevel: 0, leftEarBattery: 0, rightEarBattery: 0, caseBattery: 0, leftEarCharging: false, rightEarCharging: false, caseCharging: false, firmwareVersion: '', firmwareProductId: '', firmwareProductColor: '', wakeupLeftVersion: '', wakeupRightVersion: '', ); } } if (event['type'] == 'wakeupVoiceUpgradeProgress') { _wakeupVoiceUpgradeProgress.value = event['progress'] as int? ?? 0; _wakeupVoiceUpgradeStatus.value = 1; } if (event['type'] == 'wakeupVoiceUpgradeSuccess') { _wakeupVoiceUpgradeStatus.value = 2; Logger.i('BleManager', '唤醒语音升级成功'); } if (event['type'] == 'wakeupVoiceUpgradeFailure') { _wakeupVoiceUpgradeStatus.value = 3; Logger.w('BleManager', '唤醒语音升级失败'); } _processDeviceInfo(event); }, onError: (error) { Logger.e('BleManager', 'BLE状态事件流错误: $error'); }, ); } catch (e) { Logger.e('BleManager', '设置BLE事件监听器失败: ${e.toString()}'); } } /// 处理来自原生层的设备信息 void _processDeviceInfo(Map event) { try { if (!event.containsKey('command') || !event.containsKey('success')) { return; } final bool success = event['success'] as bool; if (!success) { Logger.w('BleManager', '设备命令执行失败: ${event['command']}'); return; } final command = event['command']; if (command is int) { _processDeviceInfoByCommandId(command, event); } else if (command is String) { _processDeviceInfoByCommandName(command, event); } else { Logger.w('BleManager', '未知的命令类型: ${command.runtimeType}'); } } catch (e, s) { Logger.e('BleManager', '处理设备信息异常: $e', e, s); } } /// 根据命令ID处理设备信息 void _processDeviceInfoByCommandId( int commandId, Map data) { switch (commandId) { case BleCommands.GET_VERSION: _updateVersionInfoFromData(data); break; case BleCommands.GET_PRODUCT_ID: _updateProductIdFromData(data); break; case BleCommands.GET_PRODUCT_COLOR: break; case BleCommands.GET_BATTERY_INFO: _updateBatteryInfoFromData(data); break; case BleCommands.CONTROL_CODEC: final bool codecSuccess = _isCodecControlSuccess(data); if (_awaitingCodecOpen) { _isCodecActive.value = codecSuccess; _awaitingCodecOpen = false; } else if (_awaitingCodecClose) { if (codecSuccess) { _isCodecActive.value = false; } _awaitingCodecClose = false; } if (!codecSuccess) { Logger.w('BleManager', '编解码控制失败'); } break; case BleCommands.GET_WAKEUP_VERSION: _updateWakeupVersionFromData(data); break; case BleCommands.GET_VOICE_WAKEUP_STATUS: _updateVoiceWakeupStatusFromData(data); break; case BleCommands.SET_VOICE_WAKEUP_STATUS: _updateVoiceWakeupSetResultFromData(data); break; case BleCommands.CALL_TRANSLATION_ON: _handleCallTranslationRequest(true, data); break; case BleCommands.CALL_TRANSLATION_OFF: _handleCallTranslationRequest(false, data); break; default: Logger.w('BleManager', '未处理的命令ID: $commandId'); } } /// 处理设备上报的通话翻译开关指令 (0x16 / 0x17) /// - [enable] true=开启通话翻译, false=关闭 /// 行为: /// 1. 打印 [CALL_TRANS_CMD] 日志; /// 2. 向 [onCallTranslationRequest] 流广播信号(TranslationController 监听并启停); /// 3. 未在翻译页时,自动导航到 Routes.translation 并以 call 模式 + autoStart 进入。 void _handleCallTranslationRequest( bool enable, Map data) { final status = data['status']; Logger.i('BleManager', '[CALL_TRANS_CMD] 收到设备上报${enable ? "开启" : "关闭"}通话翻译 cmd=0x${(enable ? BleCommands.CALL_TRANSLATION_ON : BleCommands.CALL_TRANSLATION_OFF).toRadixString(16)} status=$status'); // 广播给监听者(如 TranslationController 已在 call 模式可直接启/停) if (!_callTranslationRequestController.isClosed) { _callTranslationRequestController.add(enable); } // 开启:若当前不在翻译页,则导航并请求自动开始 if (enable) { final currentRoute = Get.currentRoute; if (currentRoute != Routes.translation) { Logger.i('BleManager', '[CALL_TRANS_CMD] 当前路由=$currentRoute,导航到翻译页(call 模式, autoStart=true)'); Get.toNamed( Routes.translation, arguments: {'translationId': 'call', 'autoStart': true}, ); } else { Logger.i('BleManager', '[CALL_TRANS_CMD] 已在翻译页,由 TranslationController 监听信号自行启动'); } } } /// 根据命令名称处理设备信息 void _processDeviceInfoByCommandName( String commandName, Map data) { switch (commandName) { case 'batteryInfo': _updateBatteryInfoFromData(data); break; case 'versionInfo': _updateVersionInfoFromData(data); break; case 'productId': _updateProductIdFromData(data); break; case 'productColor': break; case 'Error': Logger.w('BleManager', '收到 Error 命令'); break; default: Logger.w('BleManager', '未处理的命令名称: $commandName'); } } /// 更新电池信息 void _updateBatteryInfoFromData(Map data) { try { if (!data.containsKey('leftEarBattery') || !data.containsKey('rightEarBattery') || !data.containsKey('caseBattery')) { Logger.w('BleManager', '电池信息数据不完整'); return; } final int leftBattery = (data['leftEarBattery'] as int? ?? 0) == 127 ? -1 : (data['leftEarBattery'] as int? ?? 0) > 100 ? 0 : (data['leftEarBattery'] as int? ?? 0); final int rightBattery = (data['rightEarBattery'] as int? ?? 0) == 127 ? -1 : (data['rightEarBattery'] as int? ?? 0) > 100 ? 0 : (data['rightEarBattery'] as int? ?? 0); final int caseBattery = (data['caseBattery'] as int? ?? 0) == 127 ? -1 : (data['caseBattery'] as int? ?? 0) > 100 ? 0 : (data['caseBattery'] as int? ?? 0); final bool leftCharging = data['leftEarCharging'] as bool? ?? false; final bool rightCharging = data['rightEarCharging'] as bool? ?? false; final bool caseCharging = data['caseCharging'] as bool? ?? false; final int overallBattery = data['batteryLevel'] as int? ?? leftBattery; _updateDeviceInfoIfNeeded( batteryLevel: overallBattery, leftEarBattery: leftBattery, rightEarBattery: rightBattery, caseBattery: caseBattery, leftEarCharging: leftCharging, rightEarCharging: rightCharging, caseCharging: caseCharging, ); } catch (e, s) { Logger.e('BleManager', '更新电池信息失败: $e', e, s); } } /// 更新版本信息 void _updateVersionInfoFromData(Map data) { try { // 确保数据中包含版本信息 if (!data.containsKey('version')) { Logger.warning('版本信息数据不完整'); return; } // 提取版本信息 final String version = data['version'] as String? ?? ''; // 更新设备信息 _updateDeviceInfoIfNeeded( firmwareVersion: version, ); Logger.info('设备版本信息已更新: 版本=$version'); } catch (e) { Logger.error('更新版本信息失败: ${e.toString()}'); } } /// 更新设备id,并检测是否为移动精灵设备 void _updateProductIdFromData(Map data) { try { if (!data.containsKey('productId')) { Logger.warning('版本信息数据不完整'); return; } final String productId = data['productId'] as String? ?? ''; _updateDeviceInfoIfNeeded(firmwareProductId: productId); Logger.info('设备设备id已更新: 设备id=$productId'); } catch (e) { Logger.error('更新设备id失败: ${e.toString()}'); } } /// 更新唤醒语音版本信息 void _updateWakeupVersionFromData(Map data) { try { // 确保数据中包含版本信息 if (!data.containsKey('leftVersionDec') || !data.containsKey('rightVersionDec')) { Logger.warning('唤醒语音版本信息数据不完整'); return; } // 提取版本信息 final String wakeupLeftVersion = data['leftVersionDec'] as String? ?? ''; final String wakeupRightVersion = data['rightVersionDec'] as String? ?? ''; // 更新设备信息 _updateDeviceInfoIfNeeded( wakeupLeftVersion: wakeupLeftVersion, wakeupRightVersion: wakeupRightVersion, ); Logger.info('设备唤醒语音版本信息已更新: 左=$wakeupLeftVersion, 右=$wakeupRightVersion'); } catch (e) { Logger.error('更新唤醒语音版本信息失败: ${e.toString()}'); } } /// 更新语音唤醒状态(0x14 查询响应) void _updateVoiceWakeupStatusFromData(Map data) { try { if (!data.containsKey('voiceWakeupEnabled')) { Logger.warning('[VoiceWakeup] 查询响应数据不完整,缺少 voiceWakeupEnabled'); return; } final bool enabled = data['voiceWakeupEnabled'] as bool? ?? true; _voiceWakeupEnabled.value = enabled; _voiceWakeupSupported.value = true; Logger.info('[VoiceWakeup] 查询成功 → supported=true, enabled=${enabled ? "开启" : "关闭"}'); } catch (e) { Logger.error('[VoiceWakeup] 解析查询响应异常: ${e.toString()}'); } } /// 处理设置语音唤醒的响应(0x15 设置响应) void _updateVoiceWakeupSetResultFromData(Map data) { try { final bool setSuccess = data['voiceWakeupSetSuccess'] as bool? ?? false; if (setSuccess) { Logger.info('[VoiceWakeup] 设置成功 → enabled=${_voiceWakeupEnabled.value ? "开启" : "关闭"}'); } else { Logger.warning('[VoiceWakeup] 设置失败 → supported=false,开关置灰'); _voiceWakeupSupported.value = false; } } catch (e) { Logger.error('[VoiceWakeup] 解析设置响应异常: ${e.toString()}'); } } /// 查询语音唤醒状态 Future queryVoiceWakeupStatus() async { Logger.info('[VoiceWakeup] 发送查询命令(0x14)...'); final result = await _bleService.getVoiceWakeupStatus(); if (!result) { _voiceWakeupSupported.value = false; Logger.warning('[VoiceWakeup] 查询命令发送失败 → supported=false,设备可能不支持'); } else { Logger.info('[VoiceWakeup] 查询命令发送成功,等待设备响应...'); } return result; } /// 设置语音唤醒状态 Future setVoiceWakeupStatus(bool enabled) async { Logger.info('[VoiceWakeup] 发送设置命令(0x15), enabled=${enabled ? "开启" : "关闭"}...'); _voiceWakeupEnabled.value = enabled; // 乐观更新 final result = await _bleService.setVoiceWakeupStatus(enabled); if (!result) { _voiceWakeupSupported.value = false; Logger.warning('[VoiceWakeup] 设置命令发送失败 → supported=false,开关置灰'); } else { Logger.info('[VoiceWakeup] 设置命令发送成功,等待设备响应...'); } return result; } /// 更新设备信息(如果已存在设备) void _updateDeviceInfoIfNeeded({ int? batteryLevel, int? leftEarBattery, int? rightEarBattery, int? caseBattery, bool? leftEarCharging, bool? rightEarCharging, bool? caseCharging, String? firmwareVersion, String? firmwareProductId, String? firmwareProductColor, String? wakeupLeftVersion, String? wakeupRightVersion, }) { // 如果设备信息已存在,则更新 if (deviceInfo.value != null) { deviceInfo.value = deviceInfo.value!.copyWith( batteryLevel: batteryLevel ?? deviceInfo.value?.batteryLevel, leftEarBattery: _getValidBatteryValue( leftEarBattery, deviceInfo.value?.leftEarBattery), rightEarBattery: _getValidBatteryValue( rightEarBattery, deviceInfo.value?.rightEarBattery), caseBattery: caseBattery ?? deviceInfo.value?.caseBattery, leftEarCharging: leftEarCharging ?? deviceInfo.value!.leftEarCharging, rightEarCharging: rightEarCharging ?? deviceInfo.value!.rightEarCharging, caseCharging: caseCharging ?? deviceInfo.value!.caseCharging, firmwareVersion: firmwareVersion ?? deviceInfo.value!.firmwareVersion, firmwareProductId: firmwareProductId ?? deviceInfo.value!.firmwareProductId, firmwareProductColor: firmwareProductColor ?? deviceInfo.value!.firmwareProductColor, wakeupLeftVersion: wakeupLeftVersion ?? deviceInfo.value!.wakeupLeftVersion, wakeupRightVersion: wakeupRightVersion ?? deviceInfo.value!.wakeupRightVersion, ); } // 创建设备信息 // 如果设备信息不存在,但有地址和名称,则创建新的设备信息 else if (deviceInfo.value == null && _isConnected.value && (firmwareVersion != null || batteryLevel != null)) { String deviceAddress = currentDeviceAddress ?? ""; String deviceName = _currentDeviceName ?? ""; Logger.i('BleManager', '创建新的设备信息对象: address=$deviceAddress, name=$deviceName'); deviceInfo.value = DeviceInfo( address: deviceAddress, name: deviceName, batteryLevel: batteryLevel ?? 0, leftEarBattery: leftEarBattery ?? 0, rightEarBattery: rightEarBattery ?? 0, caseBattery: caseBattery ?? 0, leftEarCharging: leftEarCharging ?? false, rightEarCharging: rightEarCharging ?? false, caseCharging: caseCharging ?? false, firmwareVersion: firmwareVersion ?? '', firmwareProductId: firmwareProductId ?? '', firmwareProductColor: firmwareProductColor ?? '', wakeupLeftVersion: wakeupLeftVersion ?? '', wakeupRightVersion: wakeupRightVersion ?? '', ); } } // 新增智能电池值选择方法 int? _getValidBatteryValue(int? newValue, int? currentValue) { // 如果新值为null,使用当前值 if (newValue == null) return currentValue; // 如果当前值为null或0,使用新值(即使新值为0) if (currentValue == null || currentValue == 0) return newValue; // 如果新值为0但当前值不为0,保持当前值(避免有效数据被0覆盖) if (newValue == 0 && currentValue > 0) { Logger.warning('检测到电池数据异常(新值为0),保持当前值: $currentValue'); return currentValue; } // 其他情况使用新值 return newValue; } /// 清除设备信息(用于完全断开连接或切换设备时) void clearDeviceInfo() { Logger.info('清除设备信息'); deviceInfo.value = null; currentDeviceAddress = null; _currentDeviceName = null; } /// 连接成功后获取设备信息 Future fetchDeviceInfo() async { Logger.info('开始获取BLE设备详细信息'); try { // 确保设备信息对象存在 if (deviceInfo.value == null && _isConnected.value) { // 创建初始设备信息对象 String deviceAddress = currentDeviceAddress ?? ""; String deviceName = _currentDeviceName ?? ""; Logger.info('初始化设备信息对象: address=$deviceAddress, name=$deviceName'); deviceInfo.value = DeviceInfo( address: deviceAddress, name: deviceName, batteryLevel: 0, leftEarBattery: 0, rightEarBattery: 0, caseBattery: 0, leftEarCharging: false, rightEarCharging: false, caseCharging: false, firmwareVersion: '', firmwareProductId: '', firmwareProductColor: '', wakeupLeftVersion: '', wakeupRightVersion: '', ); } // 并行获取所有设备信息,不使用延迟 final results = await Future.wait([ _bleService.getBatteryInfo(), _bleService.getDeviceVersion(), _bleService.getProductId(), _bleService.getVoiceWakeupStatus(), ]); Logger.info( '设备信息获取结果: 电池=${results[0]}, 版本=${results[1]}, 产品ID=${results[2]}, 唤醒状态=${results[3]}'); if (!results[0]) { Logger.warning('电池信息获取指令发送失败'); } if (!results[1]) { Logger.warning('版本信息获取指令发送失败'); } if (!results[2]) { Logger.warning('产品ID获取指令发送失败'); } if (!results[3]) { Logger.warning('语音唤醒状态获取指令发送失败'); _voiceWakeupSupported.value = false; } } catch (e) { Logger.error('获取BLE设备信息失败: ${e.toString()}'); } } /// 检查BLE连接状态 Future getConnectionState() async { try { final isConnected = await _bleService.isConnected(); _connectionState.value = isConnected ? BleConnectionState.connected : BleConnectionState.disconnected; _isConnected.value = isConnected; return _connectionState.value; } catch (e) { Logger.error('获取BLE连接状态失败: ${e.toString()}'); return BleConnectionState.error; } } String getDeviceName() { if (deviceInfo.value != null) { return deviceInfo.value!.name; } return ""; } // 加载TTS偏好设置 Future _loadTtsInterrupe() async { try { if (!_storage.hasData("agent_tts_interrupt")) { // 获取设备类型以确定检查策略 String deviceName = getDeviceName(); DBProduct? product = AppConfig.getproduct(deviceName); if (deviceName != "" && product != null) { // Logger.d('AgentController', // 'liwe----------product $deviceName ${product.toJson()}'); return !product.iscontinuouschat!; } else { return false; } } else { return _storage.read('agent_tts_interrupt') ?? false; } } catch (e) { return false; } } /// 启动BLE服务 Future startAgentService() async { try { // 从.env文件直接读取环境变量 var serverurl = DioManager().baseUrl; var jsonString = _storage.read("logintoken"); final azureSpeechKey = AppConfig.env('AZURE_SPEECH_KEY') ?? ''; final azureSpeechRegion = AppConfig.env('AZURE_SPEECH_REGION') ?? 'eastasia'; final openaiApiKey = AppConfig.env('OPENAI_API_KEY') ?? ''; final openaiBaseUrl = AppConfig.env('OPENAI_BASE_URL') ?? 'https://api.openai.com/v1'; final openaiModel = AppConfig.env('OPENAI_MODEL') ?? 'gpt-3.5-turbo'; final openaiModelMedia = AppConfig.env('OPENAI_API_VISION_MODEL') ?? 'doubao-1-5-vision-pro-32k-250115'; final openaiagentid = AppConfig.env('OPENAI_AGENT_ID') ?? 'personal_assistant'; final systemPrompt = AppConfig.agentsystemPrompt(openaiagentid); var musicServiceType = AppConfig.env('APP_ANDROID_MUSICSERVICE_TYPE') ?? 'AUTO'; if (Platform.isIOS) { musicServiceType = AppConfig.env('APP_IOS_MUSICSERVICE_TYPE') ?? 'AUTO'; } final navigationMode = AppConfig.env('APP_NAVIGATION_MODE') ?? 'external_auto'; final xunfeiAppId = AppConfig.env('XUNFEI_ASR_APP_ID') ?? ''; final xunfeiAccessKeyId = AppConfig.env('XUNFEI_ASR_ACCESS_KEY_ID') ?? ''; final xunfeiAccessKeySecret = AppConfig.env('XUNFEI_ASR_ACCESS_KEY_SECRET') ?? ''; // 从Flutter资源包中加载.mcp.json final jsonData = AppConfig.mcpConfig(); Logger.info('启动BLE服务,musicServiceType: $musicServiceType'); final isTtsInterruptEnabled = await _loadTtsInterrupe(); final vipExpiryTime = userInfo.User.instance.vipexptime; Logger.info('liwei------ vipexptime 1: $vipExpiryTime'); // 根据APP语言动态配置语音识别语言 List supportedLanguages = []; try { final storage = GetStorage(); final languageManager = Get.find(); // 从存储中读取用户设置的语言 String? savedLanguage = storage.read('language'); if (savedLanguage != null && savedLanguage != 'system') { // 用户设置了特定语言 final parts = savedLanguage.split('_'); if (parts.length == 2) { final lang = parts[0].toLowerCase(); final country = parts[1].toUpperCase(); if (lang == 'zh' && (country == 'HK' || country == 'TW' || country == 'CN')) { supportedLanguages.add('zh-$country'); } else if (lang == 'tl' && country == 'PH') { // 菲律宾语特殊处理,映射为azure语言码 supportedLanguages.add('fil-PH'); } else { supportedLanguages.add('$lang-$country'); } } } else { // 跟随系统语言或未设置 final appLocale = Get.locale ?? AppTranslations.deviceLocale(); if (appLocale != null) { final lang = appLocale.languageCode.toLowerCase(); final country = appLocale.countryCode; if (lang.toLowerCase() == 'zh' && country != null && country.isNotEmpty && (country.toUpperCase() == 'HK' || country.toUpperCase() == 'TW' || country.toUpperCase() == 'CN')) { supportedLanguages.add('zh-${country.toUpperCase()}'); } else { if (country != null && country.isNotEmpty) { final normalizedCountry = country.toUpperCase(); if (lang == 'tl' && normalizedCountry == 'PH') { supportedLanguages.add('fil-PH'); } else { supportedLanguages.add('$lang-$normalizedCountry'); } } else { final asrCode = languageManager.getAsrCodeByShortCode(lang); if (asrCode != null) { supportedLanguages.add(asrCode); } else { supportedLanguages.add('en-US'); } } } } } // 最终兜底 if (supportedLanguages.isEmpty) { supportedLanguages.add('en-US'); } // Logger.info('动态配置语音识别语言: ${supportedLanguages.join(', ')}'); } catch (e) { Logger.error('获取APP语言配置失败,使用默认语言: $e'); supportedLanguages = ['zh-CN', 'en-US']; } // STS 模式参数(移动精灵) // 优先使用设备检测结果(YIDONG_PID 匹配时写入),否则用服务端 AGENT_TYPE final agentType = _storage.read('device_agent_type') ?? AppConfig.env('AGENT_TYPE') ?? 'stt_llm_tts'; final agentMode = (agentType == 'yidong') ? 'sts' : 'stt_llm_tts'; final agentId = (agentType == 'yidong') ? (AppConfig.env('MOBILE_ELF_AGENT_ID') ?? 'mobile_elf') : 'default_agent'; final stsProductId = AppConfig.env('MOBILE_ELF_PRODUCT_ID') ?? ''; final stsProductKey = AppConfig.env('MOBILE_ELF_PRODUCT_KEY') ?? ''; // 使用当前连接设备的 SN(配对时写入),认证失败由原生层上报 credential_failed 事件 final stsDeviceNo = _storage.read('device_sts_code') ?? ''; final stsDeviceId = _storage.read('sts_device_id') ?? ''; final stsDeviceSecret = _storage.read('sts_device_secret') ?? ''; // 从 UserDevice 获取当前连接设备的 CMEI final mac = currentDeviceAddress?.toUpperCase() ?? ''; String stsCmei = ''; try { final matchedDevice = userInfo.User.instance.devices.firstWhere( (d) => d.devicemac.toUpperCase() == mac, ); stsCmei = matchedDevice.cmei; } catch (_) {} Logger.i('BleManager', '当前设备 CMEI: $stsCmei (MAC=$mac)'); final config = { // STS 模式路由 'agentMode': agentMode, 'agentId': agentId, 'stsProductId': stsProductId, 'stsProductKey': stsProductKey, 'stsDeviceNo': stsDeviceNo, 'stsDeviceId': stsDeviceId, 'stsDeviceSecret': stsDeviceSecret, 'stsCmei': stsCmei, // 语音代理配置参数 'azureSpeechKey': azureSpeechKey, 'azureSpeechRegion': azureSpeechRegion, 'xunfeiAppId': xunfeiAppId, 'xunfeiAccessKeyId': xunfeiAccessKeyId, 'xunfeiAccessKeySecret': xunfeiAccessKeySecret, 'openaiApiKey': openaiApiKey, 'openaiBaseUrl': openaiBaseUrl, 'openaiModel': openaiModel, 'openaivisionModel': openaiModelMedia, 'systemPrompt': systemPrompt, 'mcpServer': jsonEncode(jsonData), 'volcanoAppId': '2316081933', 'volcanoToken': 'mcJTh6OelBqU_L78lgGd77Nyrc_-5-En', 'serverurl': serverurl, 'usertoken': jsonString, 'supportedLanguages': supportedLanguages, 'musicServiceType': musicServiceType, "navigationMode": navigationMode, "isttsinterrupt": isTtsInterruptEnabled ? "true" : "false", "vipexptime": vipExpiryTime, //会员过期时间 "callingToolText": "callingTool".tr, "insufficientIntegralText": "insufficientIntegral".tr, }; Logger.info('启动BLE服务,配置参数键名: ${config.keys.toList()}'); if (xunfeiAppId.isEmpty || xunfeiAccessKeyId.isEmpty || xunfeiAccessKeySecret.isEmpty) { Logger.warning('XUNFEI_ASR_* 未完整配置,ASR 将不会切到讯飞'); } if (agentMode != 'sts' && (azureSpeechKey.isEmpty || openaiApiKey.isEmpty)) { Logger.warning('缺少必要的API密钥,请检查.env文件配置'); // 检查.env中相关密钥是否存在 if (azureSpeechKey.isEmpty) { Logger.warning('AZURE_SPEECH_KEY未配置在.env文件中'); } if (openaiApiKey.isEmpty) { Logger.warning('OPENAI_API_KEY未配置在.env文件中'); } } // 设置原生日志回调,将 Agent 底层日志写入文件 AgentService.nativeLogCallback ??= (level, message) { switch (level) { case 'ERROR': Logger.e('NativeAgent', message); break; case 'WARNING': Logger.w('NativeAgent', message); break; case 'DEBUG': Logger.d('NativeAgent', message); break; default: Logger.i('NativeAgent', message); } }; // STS 模式:监听凭证获取事件并缓存到 GetStorage if (agentMode == 'sts') { AgentService.events.where((e) => e.type == AgentServiceEventType.stsCredentials).listen((e) { final deviceId = e.data['deviceId']?.toString() ?? ''; final deviceSecret = e.data['deviceSecret']?.toString() ?? ''; final deviceNo = e.data['deviceNo']?.toString() ?? ''; if (deviceId.isNotEmpty) _storage.write('sts_device_id', deviceId); if (deviceSecret.isNotEmpty) _storage.write('sts_device_secret', deviceSecret); if (deviceNo.isNotEmpty) _storage.write('sts_device_no', deviceNo); Logger.info('STS 凭证已缓存: deviceId=$deviceId deviceNo=$deviceNo'); }); } final result = await AgentService.startAgentService(config); Logger.i('BleManager', 'AgentService.startAgentService 结果: $result'); if (result) { final isConnected = await _bleService.isConnected(); if (isConnected) { _isConnected.value = true; _connectionState.value = BleConnectionState.connected; } } else { Logger.e('BleManager', 'BLE服务启动失败'); } return result; } catch (e) { Logger.error('启动BLE服务失败: ${e.toString()}'); return false; } } /// 停止BLE服务 Future stopAgentService() async { try { final result = await AgentService.stopAgentService(); if (result) { Logger.info('BLE服务停止成功'); _isConnected.value = false; _connectionState.value = BleConnectionState.disconnected; // 停止服务时清除设备信息 clearDeviceInfo(); } else { Logger.error('BLE服务停止失败'); } return result; } catch (e) { Logger.error('停止BLE服务失败: ${e.toString()}'); return false; } } /// 获取电池电量 Future getBatteryLevel() async { try { return await _bleService.getBatteryLevel(); } catch (e) { Logger.error('获取电池电量失败: ${e.toString()}'); return 0; } } /// 主动获取电池信息 Future fetchBatteryInfo() async { try { //Logger.info('lxm--fetchBatteryInfo被调用,准备向设备发送获取电池信息指令'); final result = await _bleService.getBatteryInfo(); //Logger.info('lxm--getBatteryInfo指令发送结果: $result'); return result; } catch (e) { //Logger.error('lxm--获取电池信息失败: ${e.toString()}'); return false; } } /// 主动产品id Future getProductId() async { try { return await _bleService.getProductId(); } catch (e) { Logger.error('获取设备版本失败: ${e.toString()}'); return false; } } /// 主动获取设备版本信息 Future fetchDeviceVersion() async { try { return await _bleService.getDeviceVersion(); } catch (e) { Logger.error('获取设备版本失败: ${e.toString()}'); return false; } } /// 打开编码器 Future openEncoder() async { try { return await _bleService.openEncoder(); } catch (e) { Logger.error('打开编码器失败: ${e.toString()}'); return false; } } /// 打开解码器 Future openDecoder() async { try { _awaitingCodecOpen = true; _awaitingCodecClose = false; _isCodecActive.value = false; return await _bleService.openDecoder(); } catch (e) { Logger.error('打开解码器失败: ${e.toString()}'); _awaitingCodecOpen = false; return false; } } /// 打开A2DP解码器 Future openA2DPDecoder() async { try { _awaitingCodecOpen = true; _awaitingCodecClose = false; _isCodecActive.value = false; Logger.i('CALL_TRANS_CMD', '准备发送通话翻译指令 cmd=0x05 sub=0xA2(A2DP_PLAY) → openA2DPDecoder'); final ok = await _bleService.openA2DPDecoder(); Logger.i('CALL_TRANS_CMD', '通话翻译指令下发结果: ${ok ? "成功" : "失败"} (等待设备回包确认)'); return ok; } catch (e) { Logger.e('CALL_TRANS_CMD', '通话翻译指令异常: ${e.toString()}'); _awaitingCodecOpen = false; return false; } } /// 打开解码器 Future openCallRecordDecoder() async { try { return await _bleService.openCallRecordDecoder(); } catch (e) { Logger.error('打开解码器失败: ${e.toString()}'); return false; } } /// 关闭编解码器 Future closeCodec() async { try { _awaitingCodecOpen = false; _awaitingCodecClose = true; _isCodecActive.value = false; return await _bleService.closeCodec(); } catch (e) { Logger.error('关闭编解码器失败: ${e.toString()}'); _awaitingCodecClose = false; return false; } } /// 播放A2DP Future playA2DP() async { try { return await _bleService.playA2DP(); } catch (e) { Logger.error('播放A2DP失败: ${e.toString()}'); return false; } } // ==================== 配对相关方法 ==================== /// 检查设备是否支持Companion Device Manager Future isCompanionSupported() async { try { return await _bleService.isCompanionSupported(); } catch (e) { Logger.error('检查Companion支持失败: ${e.toString()}'); return false; } } /// 获取已配对的MAC地址 Future getPairedMacAddress() async { try { return await _bleService.getPairedMacAddress(); } catch (e) { Logger.error('获取已配对MAC地址失败: ${e.toString()}'); return null; } } /// 检查BLE连接状态 Future isBleConnected() async { try { return await _bleService.isBleConnected(); } catch (e) { Logger.error('检查BLE连接状态失败: ${e.toString()}'); return false; } } /// 设置是否是ota模式 Future setEnterOta(bool enterOta) async { try { await _bleService.setEnterOta(enterOta); } catch (e) { Logger.error('设置是否是ota模式失败: ${e.toString()}'); } } /// 断开连接 Future disconnect() async { try { await _bleService.disconnect(); } catch (e) { Logger.error('断开连接失败: ${e.toString()}'); } } /// 验证设备是否可以配对 Future startScan(List uuids) async { try { await _bleService.startScan(uuids); } catch (e) { Logger.error('开始扫描设备: ${e.toString()}'); } } /// 验证设备是否可以配对 Future stopScan() async { try { await _bleService.stopScan(); } catch (e) { Logger.error('停止扫描设备: ${e.toString()}'); } } Future?> getDeviceInfo(String deviceName) async { try { final result = _bleService.getDeviceInfo(deviceName); return result; } catch (e) { Logger.error('获取设备信息: ${e.toString()}'); return null; } } Future>?> getDeviceList(String deviceName) async { try { final result = _bleService.getDeviceList(deviceName); return result; } catch (e) { Logger.error('获取设备信息: ${e.toString()}'); return null; } } /// 验证设备是否可以配对 Future verifyDeviceCanPair(String macAddress) async { try { return true; } catch (e) { Logger.error('验证设备配对失败: ${e.toString()}'); return false; } } /// 启动设备关联 Future startDeviceAssociation({ required String deviceNamePattern, required String macAddress, }) async { try { return await _bleService.startDeviceAssociation( deviceNamePattern: deviceNamePattern, macAddress: macAddress, ); } catch (e) { Logger.error('启动设备关联失败: ${e.toString()}'); return false; } } /// 启动设备关联 Future connect() async { try { await _bleService.connect(); } catch (e) { Logger.error('连接设备失败: ${e.toString()}'); } } /// 注册后台扫描 Future registerBackgroundScan({ String? macAddress, List? uuids, }) async { try { // 在注册新设备前先清除旧设备信息 if (macAddress != null && macAddress != currentDeviceAddress) { clearDeviceInfo(); // 清除上一个设备的信息 } // 保存设备地址信息 if (macAddress != null) { currentDeviceAddress = macAddress; // 从蓝牙管理器获取设备名称 final bluetoothManager = Get.find(); _currentDeviceName = bluetoothManager.currentDevice?.name ?? ""; Logger.info( '保存设备信息: address=$currentDeviceAddress, name=$_currentDeviceName'); } return await _bleService.registerBackgroundScan( macAddress: macAddress, uuids: uuids, ); } catch (e) { Logger.error('注册后台扫描失败: ${e.toString()}'); return false; } } /// 注销后台扫描 Future unregisterBackgroundScan() async { try { return await _bleService.unregisterBackgroundScan(); } catch (e) { Logger.error('注销后台扫描失败: ${e.toString()}'); return false; } } /// 清除BLE配对设备 Future clearPairedDevices() async { try { return await _bleService.clearAssociations(); } catch (e) { Logger.error('清除BLE配对设备失败: ${e.toString()}'); return false; } } /// 注册服务 static Future init() async { if (!Get.isRegistered()) { Get.put(BleManager(), permanent: true); } return Future.value(Get.find()); } /// 请求蓝牙权限 Future requestBluetoothPermission() async { try { return await _bleService.requestBluetoothPermission(); } catch (e) { Logger.error('请求蓝牙权限失败: ${e.toString()}'); return false; } } /// 开始唤醒词升级 Future startWakeupVoicesUpgrade(List wakeupVoiceBytes) async { try { return await _bleService.startWakeupVoicesUpgrade(wakeupVoiceBytes); } catch (e) { Logger.error('开始唤醒词升级失败: ${e.toString()}'); return false; } } }