更新100j蓝牙
This commit is contained in:
@ -277,6 +277,7 @@ class HBY100JProtocol {
|
||||
// 网络 URL:优先用 uni.request 直接拉取 ArrayBuffer(类似 100 设备,无文件 IO),失败再走 downloadFile
|
||||
let fetchUrl = fileUrlOrLocalPath;
|
||||
if (fetchUrl.startsWith('http://')) fetchUrl = 'https://' + fetchUrl.slice(7);
|
||||
if (onProgress) onProgress(2);
|
||||
uni.request({
|
||||
url: fetchUrl,
|
||||
method: 'GET',
|
||||
@ -317,49 +318,42 @@ class HBY100JProtocol {
|
||||
_sendVoiceChunks(bytes, fileType, chunkSize, onProgress) {
|
||||
const total = bytes.length;
|
||||
const ft = (fileType & 0xFF) || 1;
|
||||
const DELAY_AFTER_START = 200; // 开始包后、等设备响应后再发的缓冲(ms)
|
||||
const DELAY_PACKET = 200; // 数据包间延时(ms),设备收不全时适当加大
|
||||
const toHex = (arr) => Array.from(arr).map(b => b.toString(16).padStart(2, '0').toUpperCase()).join(' ');
|
||||
console.log('[100J-蓝牙] 语音文件总大小:', total, '字节, fileType=', ft);
|
||||
if (onProgress) onProgress(0);
|
||||
const DELAY_AFTER_START = 80; // 开始包后、等设备响应后再发的缓冲(ms)
|
||||
const DELAY_PACKET = 80; // 数据包间延时(ms),参考6155
|
||||
if (onProgress) onProgress(1);
|
||||
const bleToolPromise = import('@/utils/BleHelper.js').then(m => m.default.getBleTool());
|
||||
const send = (dataBytes, label = '') => {
|
||||
const send = (dataBytes) => {
|
||||
const buf = new ArrayBuffer(dataBytes.length + 3);
|
||||
const v = new Uint8Array(buf);
|
||||
v[0] = 0xFA;
|
||||
v[1] = 0x05;
|
||||
for (let i = 0; i < dataBytes.length; i++) v[2 + i] = dataBytes[i];
|
||||
v[v.length - 1] = 0xFF;
|
||||
const hex = toHex(v);
|
||||
const preview = v.length <= 32 ? hex : hex.slice(0, 96) + '...';
|
||||
console.log(`[100J-蓝牙] 发送${label} 共${v.length}字节:`, preview);
|
||||
return bleToolPromise.then(ble => ble.sendData(this.bleDeviceId, buf, this.SERVICE_UUID, this.WRITE_UUID));
|
||||
};
|
||||
const delay = (ms) => new Promise(r => setTimeout(r, ms));
|
||||
// 开始包: FA 05 [fileType] [phase=0] [size 4B LE] FF
|
||||
const startData = [ft, 0, total & 0xFF, (total >> 8) & 0xFF, (total >> 16) & 0xFF, (total >> 24) & 0xFF];
|
||||
const waitPromise = this.waitForFileResponse(1000);
|
||||
return send(startData, ' 开始包')
|
||||
.then(() => { if (onProgress) onProgress(1); return waitPromise; })
|
||||
.then(() => { if (onProgress) onProgress(2); return delay(DELAY_AFTER_START); })
|
||||
return send(startData)
|
||||
.then(() => { if (onProgress) onProgress(3); return waitPromise; })
|
||||
.then(() => { if (onProgress) onProgress(5); return delay(DELAY_AFTER_START); })
|
||||
.then(() => {
|
||||
let seq = 0;
|
||||
const sendNext = (offset) => {
|
||||
if (offset >= total) {
|
||||
return delay(DELAY_PACKET).then(() => send([ft, 2], ' 结束包'));
|
||||
return delay(DELAY_PACKET).then(() => send([ft, 2]));
|
||||
}
|
||||
const chunk = bytes.slice(offset, Math.min(offset + chunkSize, total));
|
||||
const chunkData = [ft, 1, seq & 0xFF, (seq >> 8) & 0xFF, ...chunk];
|
||||
return send(chunkData, ` #${seq} 数据包`).then(() => {
|
||||
return send(chunkData).then(() => {
|
||||
seq++;
|
||||
const pct = Math.round((offset + chunk.length) / total * 100);
|
||||
if (onProgress) onProgress(Math.min(99, Math.max(3, pct)));
|
||||
if (onProgress) onProgress(Math.min(100, Math.floor((offset + chunk.length) / total * 100)));
|
||||
return delay(DELAY_PACKET).then(() => sendNext(offset + chunk.length));
|
||||
});
|
||||
};
|
||||
return sendNext(0);
|
||||
})
|
||||
.then(() => delay(DELAY_PACKET))
|
||||
.then(() => {
|
||||
if (onProgress) onProgress(100);
|
||||
return { code: 200, msg: '语音文件已通过蓝牙上传' };
|
||||
@ -377,6 +371,11 @@ export function updateBleStatus(isConnected, bleDeviceId, deviceId) {
|
||||
console.log('[100J] 蓝牙状态:', isConnected ? '已连接(后续指令走蓝牙)' : '已断开(后续指令走4G)', { bleDeviceId: bleDeviceId || '-', deviceId });
|
||||
}
|
||||
|
||||
// 暴露给页面:获取当前蓝牙连接状态(用于跨页面传递,确保语音管理等子页走蓝牙优先)
|
||||
export function getBleStatus() {
|
||||
return { isConnected: protocolInstance.isBleConnected, bleDeviceId: protocolInstance.bleDeviceId, deviceId: protocolInstance.deviceId };
|
||||
}
|
||||
|
||||
// 暴露给页面:解析蓝牙接收到的数据
|
||||
export function parseBleData(buffer) {
|
||||
return protocolInstance.parseBleData(buffer);
|
||||
@ -396,6 +395,29 @@ export function fetchBleLocation() {
|
||||
return protocolInstance.getLocation();
|
||||
}
|
||||
|
||||
// 等待蓝牙连接(扫描中时轮询,设备页可能在后台完成连接,100J 扫描约 15s)
|
||||
function waitForBleConnection(maxWaitMs = 12000, intervalMs = 500) {
|
||||
if (protocolInstance.isBleConnected && protocolInstance.bleDeviceId) return Promise.resolve(true);
|
||||
return new Promise((resolve) => {
|
||||
const start = Date.now();
|
||||
const tick = () => {
|
||||
if (protocolInstance.isBleConnected && protocolInstance.bleDeviceId) {
|
||||
console.log('[100J] 等待蓝牙连接成功');
|
||||
resolve(true);
|
||||
return;
|
||||
}
|
||||
if (Date.now() - start >= maxWaitMs) {
|
||||
console.log('[100J] 等待蓝牙连接超时,将走4G');
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
setTimeout(tick, intervalMs);
|
||||
};
|
||||
console.log('[100J] 蓝牙未连接,等待扫描/连接中...', maxWaitMs, 'ms');
|
||||
tick();
|
||||
});
|
||||
}
|
||||
|
||||
// 暴露给页面:尝试重连蓝牙(优先策略:断线后发指令前先尝试重连)
|
||||
export function tryReconnectBle(timeoutMs = 2500) {
|
||||
if (protocolInstance.isBleConnected) return Promise.resolve(true);
|
||||
@ -470,10 +492,12 @@ export function deviceUpdateVoice(data) {
|
||||
const hasFileUrl = fileUrl && typeof fileUrl === 'string' && fileUrl.length > 0;
|
||||
const fileSource = hasLocalPath ? localPath : (hasFileUrl ? fileUrl : null);
|
||||
if (!fileSource) {
|
||||
console.log('[100J] 语音上传:无 fileUrl/localPath,走 4G');
|
||||
return httpExec(); // 无文件源:直接 4G(原有逻辑)
|
||||
}
|
||||
console.log('[100J] 语音上传:有文件源,蓝牙优先', { isBleConnected: protocolInstance.isBleConnected, bleDeviceId: protocolInstance.bleDeviceId || '-' });
|
||||
const bleExec = () => protocolInstance.uploadVoiceFileBle(fileSource, 1, data.onProgress);
|
||||
return execWithBleFirst(bleExec, httpExec, '语音文件上传');
|
||||
return execWithBleFirst(bleExec, httpExec, '语音文件上传', data.onWaiting);
|
||||
}
|
||||
// 100J信息
|
||||
export function deviceDetail(id) {
|
||||
@ -483,13 +507,20 @@ export function deviceDetail(id) {
|
||||
})
|
||||
}
|
||||
|
||||
// 蓝牙优先、4G 兜底:未连接时尝试重连;蓝牙失败时回退 4G(保持原有 4G 通讯不变)
|
||||
function execWithBleFirst(bleExec, httpExec, logName) {
|
||||
// 蓝牙优先、4G 兜底:未连接时先等待扫描/连接,再尝试重连;蓝牙失败时回退 4G
|
||||
function execWithBleFirst(bleExec, httpExec, logName, onWaiting) {
|
||||
const doBle = () => bleExec().then(res => ({ ...(res || {}), _channel: 'ble' }));
|
||||
const do4G = () => httpExec().then(res => { res._channel = '4g'; return res; });
|
||||
if (protocolInstance.isBleConnected) {
|
||||
if (protocolInstance.isBleConnected && protocolInstance.bleDeviceId) {
|
||||
return doBle().catch(() => { console.log('[100J] 蓝牙失败,回退4G'); return do4G(); });
|
||||
}
|
||||
// 无 bleDeviceId 时:可能扫描中,先等待连接(设备页在后台可能完成连接)
|
||||
if (!protocolInstance.bleDeviceId) {
|
||||
if (typeof onWaiting === 'function') onWaiting();
|
||||
return waitForBleConnection(12000).then(connected => {
|
||||
return connected ? doBle().catch(() => { console.log('[100J] 蓝牙失败,回退4G'); return do4G(); }) : do4G();
|
||||
});
|
||||
}
|
||||
return tryReconnectBle(2500).then(reconnected => {
|
||||
return reconnected ? doBle().catch(() => { console.log('[100J] 蓝牙失败,回退4G'); return do4G(); }) : do4G();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user