From 8d5267b5e6127d5e650bd1c1ed7df88113e4d567 Mon Sep 17 00:00:00 2001 From: tianyongbao Date: Wed, 21 Jan 2026 18:35:10 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=81=94=E8=B0=83=E6=B5=8B=E8=AF=95bug?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages.json | 14 + src/pages/bluetooth/bluetooth.vue | 147 +++-- src/pages/mixer/control.vue | 870 +++++++++++++++++++++++++++ src/pages/mixer/setting.vue | 568 +++++++++++++++++ src/pages/mixer/蓝牙电机协议1.2.xlsx | Bin 0 -> 10872 bytes 5 files changed, 1538 insertions(+), 61 deletions(-) create mode 100644 src/pages/mixer/control.vue create mode 100644 src/pages/mixer/setting.vue create mode 100644 src/pages/mixer/蓝牙电机协议1.2.xlsx diff --git a/src/pages.json b/src/pages.json index b37718a..08b6cc9 100644 --- a/src/pages.json +++ b/src/pages.json @@ -33,6 +33,20 @@ "navigationStyle": "custom" } }, + { + "path": "pages/mixer/setting", + "style": { + "navigationBarTitleText": "搅拌器设置", + "navigationStyle": "custom" + } + }, + { + "path": "pages/mixer/control", + "style": { + "navigationBarTitleText": "搅拌器控制", + "navigationStyle": "custom" + } + }, { "path": "pages/register", "style": { diff --git a/src/pages/bluetooth/bluetooth.vue b/src/pages/bluetooth/bluetooth.vue index 6b235df..12e20b2 100644 --- a/src/pages/bluetooth/bluetooth.vue +++ b/src/pages/bluetooth/bluetooth.vue @@ -507,6 +507,37 @@ const tryAutoReconnectLastDevice = async () => { connectedDeviceId.value = targetDevice.deviceId connectedDevice.value = targetDevice + // 设置蓝牙 MTU 为 500 (主要针对 Android) + // #ifdef APP-PLUS || MP-WEIXIN + if (uni.getSystemInfoSync().platform === 'android') { + try { + await new Promise((resolve, reject) => { + uni.setBLEMTU({ + deviceId: targetDevice.deviceId, + mtu: 500, + success: (mtuRes) => { + console.log('MTU 设置成功, 实际MTU:', mtuRes.mtu || 500) + uni.showToast({ + title: `MTU: ${mtuRes.mtu || 500}`, + icon: 'none', + duration: 2000 + }) + resolve(mtuRes) + }, + fail: (mtuErr) => { + console.error('MTU 设置失败:', mtuErr) + resolve(null) + } + }) + }) + // 等待MTU协商稳定 + await new Promise(resolve => setTimeout(resolve, 500)) + } catch (e) { + console.error('MTU 设置异常:', e) + } + } + // #endif + // 停止搜索 uni.stopBluetoothDevicesDiscovery() @@ -751,6 +782,34 @@ const doConnect = (device) => { timeout: 10000, // 10 seconds timeout success: async (res) => { console.log('Connection successful', res) + + // 设置蓝牙 MTU 为 500 (主要针对 Android) + // #ifdef APP-PLUS || MP-WEIXIN + if (uni.getSystemInfoSync().platform === 'android') { + try { + await new Promise((resolve, reject) => { + uni.setBLEMTU({ + deviceId: device.deviceId, + mtu: 500, + success: (mtuRes) => { + console.log('MTU 设置成功, 实际MTU:', mtuRes.mtu || 500) + resolve(mtuRes) + }, + fail: (mtuErr) => { + console.error('MTU 设置失败:', mtuErr) + // MTU设置失败不阻塞后续流程 + resolve(null) + } + }) + }) + // 等待MTU协商稳定 + await new Promise(resolve => setTimeout(resolve, 500)) + } catch (e) { + console.error('MTU 设置异常:', e) + } + } + // #endif + connectingDeviceId.value = '' connectedDeviceId.value = device.deviceId connectedDevice.value = device @@ -900,14 +959,11 @@ const getBLEDeviceServices = async (deviceId) => { let notifyCharacteristicId = '' // 通用可监听特征值 let mainServiceId = '' // 主服务ID - // 🔧 收集所有协议特征值的128位UUID(用于mixer.vue) + // 🔧 收集新协议1.2的特征值UUID const protocolCharacteristics = { - status: '', // 0xFF01 - 电机状态 - speed: '', // 0xFF02 - 电机速度 - direction: '', // 0xFF03 - 运行方向 - timer: '', // 0xFF04 - 定时设置 - remaining: '', // 0xFF05 - 剩余时间 - allProps: '' // 0xFF06 - 所有属性 + setting: '', // 0xFF01 - 设置参数 + status: '', // 0xFF02 - 运行状态 + control: '' // 0xFF03 - 控制指令 } // 查找协议规定的服务ID (0x00FF) @@ -935,25 +991,16 @@ const getBLEDeviceServices = async (deviceId) => { serviceChars.forEach(characteristic => { const charUUID = characteristic.uuid.toUpperCase() - // 🔧 识别协议规定的特征值(通过包含匹配128位UUID) + // 🔧 识别新协议1.2的特征值 if (charUUID.includes('FF01') || charUUID.includes('0XFF01')) { - protocolCharacteristics.status = characteristic.uuid - console.log('✅ 找到电机状态特征值(0xFF01):', characteristic.uuid) + protocolCharacteristics.setting = characteristic.uuid + console.log('✅ 找到设置参数特征值(0xFF01):', characteristic.uuid) } else if (charUUID.includes('FF02') || charUUID.includes('0XFF02')) { - protocolCharacteristics.speed = characteristic.uuid - console.log('✅ 找到电机速度特征值(0xFF02):', characteristic.uuid) + protocolCharacteristics.status = characteristic.uuid + console.log('✅ 找到运行状态特征值(0xFF02):', characteristic.uuid) } else if (charUUID.includes('FF03') || charUUID.includes('0XFF03')) { - protocolCharacteristics.direction = characteristic.uuid - console.log('✅ 找到运行方向特征值(0xFF03):', characteristic.uuid) - } else if (charUUID.includes('FF04') || charUUID.includes('0XFF04')) { - protocolCharacteristics.timer = characteristic.uuid - console.log('✅ 找到定时设置特征值(0xFF04):', characteristic.uuid) - } else if (charUUID.includes('FF05') || charUUID.includes('0XFF05')) { - protocolCharacteristics.remaining = characteristic.uuid - console.log('✅ 找到剩余时间特征值(0xFF05):', characteristic.uuid) - } else if (charUUID.includes('FF06') || charUUID.includes('0XFF06')) { - protocolCharacteristics.allProps = characteristic.uuid - console.log('✅ 找到所有属性特征值(0xFF06):', characteristic.uuid) + protocolCharacteristics.control = characteristic.uuid + console.log('✅ 找到控制指令特征值(0xFF03):', characteristic.uuid) } // 查找通用可写特征值(优先选择 write) @@ -989,28 +1036,22 @@ const getBLEDeviceServices = async (deviceId) => { totalCharacteristicsCount.value = totalCount console.log(`总共 ${totalCount} 个特征值`) - // 🔧 打印所有协议特征值 - console.log('📋 协议特征值UUID汇总:') - console.log(' 0xFF01 (状态):', protocolCharacteristics.status || '未找到') - console.log(' 0xFF02 (速度):', protocolCharacteristics.speed || '未找到') - console.log(' 0xFF03 (方向):', protocolCharacteristics.direction || '未找到') - console.log(' 0xFF04 (定时):', protocolCharacteristics.timer || '未找到') - console.log(' 0xFF05 (剩余):', protocolCharacteristics.remaining || '未找到') - console.log(' 0xFF06 (全部):', protocolCharacteristics.allProps || '未找到') + // 🔧 打印新协议1.2特征值 + console.log('📋 协议1.2特征值UUID汇总:') + console.log(' 0xFF01 (设置参数):', protocolCharacteristics.setting || '未找到') + console.log(' 0xFF02 (运行状态):', protocolCharacteristics.status || '未找到') + console.log(' 0xFF03 (控制指令):', protocolCharacteristics.control || '未找到') } - // 返回蓝牙信息(用于跳转),包含所有协议特征值 + // 返回蓝牙信息(用于跳转),包含新协议1.2特征值 return { serviceId: mainServiceId, characteristicId: writeCharacteristicId, notifyCharacteristicId: notifyCharacteristicId, - // 🔧 添加所有协议特征值的128位UUID + // 新协议1.2的特征值UUID + settingCharId: protocolCharacteristics.setting, statusCharId: protocolCharacteristics.status, - speedCharId: protocolCharacteristics.speed, - directionCharId: protocolCharacteristics.direction, - timerCharId: protocolCharacteristics.timer, - remainingCharId: protocolCharacteristics.remaining, - allPropsCharId: protocolCharacteristics.allProps + controlCharId: protocolCharacteristics.control } } catch (err) { console.error('获取服务列表失败', err) @@ -1054,24 +1095,15 @@ const buildMixerPageUrl = (device, bleInfo) => { params.notifyCharacteristicId = bleInfo.notifyCharacteristicId } - // 🔧 添加所有协议特征值的128位UUID + // 新协议1.2的特征值UUID + if (bleInfo && bleInfo.settingCharId) { + params.settingCharId = bleInfo.settingCharId + } if (bleInfo && bleInfo.statusCharId) { params.statusCharId = bleInfo.statusCharId } - if (bleInfo && bleInfo.speedCharId) { - params.speedCharId = bleInfo.speedCharId - } - if (bleInfo && bleInfo.directionCharId) { - params.directionCharId = bleInfo.directionCharId - } - if (bleInfo && bleInfo.timerCharId) { - params.timerCharId = bleInfo.timerCharId - } - if (bleInfo && bleInfo.remainingCharId) { - params.remainingCharId = bleInfo.remainingCharId - } - if (bleInfo && bleInfo.allPropsCharId) { - params.allPropsCharId = bleInfo.allPropsCharId + if (bleInfo && bleInfo.controlCharId) { + params.controlCharId = bleInfo.controlCharId } console.log('🔗 跳转参数:', params) @@ -1081,7 +1113,7 @@ const buildMixerPageUrl = (device, bleInfo) => { .map(key => `${key}=${params[key]}`) .join('&') - return `/pages/mixer/mixer?${queryString}` + return `/pages/mixer/setting?${queryString}` } // 启用特征值变化监听 @@ -1128,13 +1160,6 @@ const onBLECharacteristicValueChange = () => { // 添加到历史记录(包含UUID) addToHistory('receive', displayData, hexString, res.characteristicId) - - // 显示接收到的数据 - uni.showToast({ - title: `Received Data: ${displayData.slice(0, 20)}${displayData.length > 20 ? '...' : ''}`, - icon: 'none', - duration: 2000 - }) }) } diff --git a/src/pages/mixer/control.vue b/src/pages/mixer/control.vue new file mode 100644 index 0000000..b09ab7a --- /dev/null +++ b/src/pages/mixer/control.vue @@ -0,0 +1,870 @@ + + + + + diff --git a/src/pages/mixer/setting.vue b/src/pages/mixer/setting.vue new file mode 100644 index 0000000..3049c3e --- /dev/null +++ b/src/pages/mixer/setting.vue @@ -0,0 +1,568 @@ + + + + + diff --git a/src/pages/mixer/蓝牙电机协议1.2.xlsx b/src/pages/mixer/蓝牙电机协议1.2.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..470bbb3c1ef2d2119164f2fbd5fe3768ad52c0ed GIT binary patch literal 10872 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 WSxM+WCM)VQml5_Er$P22_x}LoYa;Rh literal 0 HcmV?d00001