From 1043e83bd37b0c8135195f91e84f5f229f241f21 Mon Sep 17 00:00:00 2001 From: chenzhihao <1798906853@qq.com> Date: Fri, 23 Jan 2026 10:14:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=AF=BB=E5=8F=96=E9=97=A8?= =?UTF-8?q?=E7=A3=81=E3=80=81=E5=8D=AB=E6=B5=B4=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Document/W13无卡取电设备 - 蓝牙通讯协议.md | 13 +- app.json | 4 +- .../BluetoothDebugging/B13page/B13page.js | 365 +++++++++++++++++- .../BluetoothDebugging/B13page/B13page.wxml | 178 +++++---- .../BluetoothDebugging/B13page/B13page.wxss | 63 ++- .../B13page/B13page_描述.md | 148 +++++++ .../BluetoothDebugging/BluetoothDebugging.js | 1 + .../EquipmentCaontrol/EquipmentCaontrol.js | 2 +- utils/w13Packet.js | 13 + 9 files changed, 671 insertions(+), 116 deletions(-) create mode 100644 pages/basics/BluetoothDebugging/B13page/B13page_描述.md diff --git a/Document/W13无卡取电设备 - 蓝牙通讯协议.md b/Document/W13无卡取电设备 - 蓝牙通讯协议.md index fa7fefe..b1fe2e0 100644 --- a/Document/W13无卡取电设备 - 蓝牙通讯协议.md +++ b/Document/W13无卡取电设备 - 蓝牙通讯协议.md @@ -190,8 +190,19 @@ MCU -> PC | PC→MCU | 0x16 | P0: 控制位
  bit0: 设置门磁开关廊灯事件
  bit1: 设置卫浴灯开关事件

门磁开关廊灯事件:
P1: 事件触发延迟时间数值
P2: 时间单位,1=秒 2=分 3=时
P3: 事件释放延迟时间
P4: 时间单位,1=秒 2=分 3=时

卫浴灯开关事件:
P5: 事件触发延迟时间数值
P6: 时间单位,1=秒 2=分 3=时
P7: 事件释放延迟时间
P8: 时间单位,1=秒 2=分 3=时 | 设置门磁与卫浴雷达的触发/释放时序参数 | | MCU→PC | 0x16 | P0:
  0x01: 参数正确
  0x02: 参数错误 | 返回设置结果 | -## 4. 命令交互流程图 + +### 3.9 读取门磁/卫浴事件触发/释放参数 +| 方向 | 命令字 | 参数 | 备注 | +|------|-------|------|------| +| PC→MCU | 0x17 | P0: 0x01 (读取参数) | 请求设备返回门磁与卫浴雷达的触发/释放延时参数(低地址在前) | +| MCU→PC | 0x17 | P0~P1: 门磁事件触发延迟时间(16-bit,单位:秒,低地址在前)
P2~P3: 门磁事件释放延迟时间(16-bit,低地址在前)
P4~P5: 卫浴雷达事件触发延迟时间(16-bit,低地址在前)
P6~P7: 卫浴雷达事件释放延迟时间(16-bit,低地址在前) | 设备返回各项时序参数,均为 16-bit 小端格式,单位为秒。 | + +说明: +- 请求示例(PC→MCU):Frame_Type=0x17,P0=0x01。 +- 响应示例(MCU→PC):Frame_Type=0x17,参数区域例如 P0~P7 = [0x0A,0x00, 0x14,0x00, 0x05,0x00, 0x08,0x00] 表示:门磁触发延时 10s,门磁释放延时 20s,卫浴触发 5s,卫浴释放 8s(均为小端)。 + +## 4. 命令交互流程图 ### 4.1 读版本号流程 ```mermaid flowchart TD diff --git a/app.json b/app.json index 8c287fb..2458a29 100644 --- a/app.json +++ b/app.json @@ -1,8 +1,8 @@ { "pages": [ - "pages/autho/index", - "pages/basics/BluetoothDebugging/B13page/B13page", + "pages/autho/index", + "pages/basics/BluetoothDebugging/B13page/B13page", "pages/login/login", "pages/index/index", "pages/mycenter/index", diff --git a/pages/basics/BluetoothDebugging/B13page/B13page.js b/pages/basics/BluetoothDebugging/B13page/B13page.js index 9169852..d9b1aed 100644 --- a/pages/basics/BluetoothDebugging/B13page/B13page.js +++ b/pages/basics/BluetoothDebugging/B13page/B13page.js @@ -1,5 +1,5 @@ -const { buildCommand, buildReadVersion, buildSetDoorBathEvent, COMMANDS, verifyHexPacket } = require('../../../../utils/w13Packet.js') +const { buildCommand, buildReadVersion, buildSetDoorBathEvent, buildReadDoorBathEvent, COMMANDS, verifyHexPacket } = require('../../../../utils/w13Packet.js') const FIXED_CONNECT_CMD = new Uint8Array([0xCC, 0xC0, 0x0C, 0x00, 0x4F, 0xC0, 0x01, 0x00, 0x02, 0x00, 0x0C, 0x08]) // Optional encoding library for robust GBK/GB18030 decoding let EncodingLib = null @@ -38,6 +38,12 @@ Page({ txCharId: '', rxCharId: '', logList: [], + logScrollTo: '', + // 日志滚动区高度(px),由页面显示时计算并设置 + logListHeight: 200, + debugDeviceInfoLogs: false, + isReconnecting: false, + showLastKnown: true, timeUnits: ['秒', '分', '时'], hourValues: Array.from({ length: 24 }, (_, i) => i + 1), msValues: Array.from({ length: 60 }, (_, i) => i + 1), @@ -128,6 +134,25 @@ Page({ addDialogSelectedGroupIndex: 0, }, + // 动态计算日志区域高度(像素) + // 在页面显示或切换到日志 Tab 时调用,计算公式:高度 = 窗口高度 - 日志卡片顶部 + // 若计算结果过小则使用最小值保障可见性 + + + // 中间层:在执行测试按键动作前检查连接状态 + maybeOnTestKeyTap(e) { + try { + if (!this.data.isConnected) { + wx.showToast({ title: '未连接设备', icon: 'none' }) + this.appendLog('UI', '尝试操作测试按键但设备未连接') + return + } + if (typeof this.onTestKeyTap === 'function') return this.onTestKeyTap(e) + } catch (err) { + // swallow + } + }, + onLoad(options) { const raw = options && (options.DevName || options.name) || '' // 处理通过 URL 传递的编码,避免中文显示为乱码 @@ -167,50 +192,94 @@ Page({ // 更新当前设备的 RSSI / signal / 连接状态(基于 deviceId) updateDeviceInfo() { + //console.log('开始获取信号值') const deviceId = this.data.deviceId if (!deviceId) { this.setData({ bleSignal: '-', bleRSSI: '-', isConnected: false }) return } - const setUnknown = () => this.setData({ bleSignal: '-', bleRSSI: '-', isConnected: false }) + const setUnknown = () => { + this.setData({ bleSignal: '-', bleRSSI: '-', isConnected: false }) + } try { - // 优先使用 getConnectedBluetoothDevices 查询当前已连接设备 + + // 优先使用 getBLEDeviceRSSI 查询当前已连接设备 const svc = this.data.serviceId - if (typeof wx.getConnectedBluetoothDevices === 'function' && svc) { - wx.getConnectedBluetoothDevices({ services: [svc], success: (res) => { - const devices = (res && res.devices) || [] - const found = devices.find(d => d.deviceId === deviceId) - if (found) { - const rssi = (typeof found.RSSI === 'number') ? found.RSSI : (found.RSSI ? Number(found.RSSI) : 0) + //console.log('开始获取信号值1') + if (typeof wx.getBLEDeviceRSSI === 'function' && svc) { + //console.log('开始获取信号值2') + wx.getBLEDeviceRSSI({ deviceId: deviceId, success: (res) => { + //console.log('开始获取信号值3') + ////console.log(res) + + + if (res) { + //console.log('开始获取信号值4') + //console.log(res.RSSI) + + const rssi = (typeof res.RSSI === 'number') ? res.RSSI : (found.RSSI ? Number(res.RSSI) : 0) + const sigText = isNaN(rssi) ? '-' : `${rssi} dBm` + // 记录最后已知 RSSI + try { this._lastKnownRSSI = isNaN(rssi) ? null : rssi; this._lastKnownAt = Date.now() } catch (e) { /* ignore */ } this.setData({ bleRSSI: isNaN(rssi) ? '-' : rssi, bleSignal: sigText, isConnected: true }) return } // 未连接 + + // 若存在最后已知RSSI则展示最后已知值,否则展示未知 + if (this._lastKnownRSSI != null) { + //console.log('开始获取信号值5') + const age = Math.floor((Date.now() - (this._lastKnownAt || 0)) / 1000) + const sigText = `${this._lastKnownRSSI} dBm (最后已知 ${age}s)` + this.setData({ bleRSSI: this._lastKnownRSSI, bleSignal: sigText, isConnected: false }) + } else { + //console.log('开始获取信号值6') + setUnknown() + } + }, fail: () => { + //console.log('开始获取信号值7') setUnknown() - }, fail: () => setUnknown() }) + } }) return } - + //console.log('开始获取信号值8') // 兜底使用 getBluetoothDevices 查询缓存设备 if (typeof wx.getBluetoothDevices === 'function') { + //console.log('开始获取信号值9') wx.getBluetoothDevices({ success: (res) => { + //console.log('开始获取信号值10') const devices = (res && res.devices) || [] const found = devices.find(d => d.deviceId === deviceId) if (found) { + //console.log('开始获取信号值11') const rssi = (typeof found.RSSI === 'number') ? found.RSSI : (found.RSSI ? Number(found.RSSI) : 0) const sigText = isNaN(rssi) ? '-' : `${rssi} dBm` // connected 字段在缓存中可能为 true/false - this.setData({ bleRSSI: isNaN(rssi) ? '-' : rssi, bleSignal: sigText, isConnected: !!found.connected }) + try { this._lastKnownRSSI = isNaN(rssi) ? null : rssi; this._lastKnownAt = Date.now() } catch (e) { /* ignore */ } + + this.setData({ bleRSSI: isNaN(rssi) ? '-' : rssi, bleSignal: sigText, isConnected: !!found.connected }) return } - setUnknown() - }, fail: () => setUnknown() }) + //console.log('开始获取信号值12') + if (this._lastKnownRSSI != null) { + //console.log('开始获取信号值13') + const age = Math.floor((Date.now() - (this._lastKnownAt || 0)) / 1000) + const sigText = `${this._lastKnownRSSI} dBm (最后已知 ${age}s)` + this.setData({ bleRSSI: this._lastKnownRSSI, bleSignal: sigText, isConnected: false }) + } else { + //console.log('开始获取信号值14') + setUnknown() + } + }, fail: () =>{ + //console.log('开始获取信号值15') + setUnknown() + } }) return } - + //console.log('开始获取信号值16') setUnknown() } catch (e) { setUnknown() @@ -322,6 +391,41 @@ Page({ }, 250) } catch (e) { /* ignore */ } try { this.updateDeviceInfo && this.updateDeviceInfo() } catch (e) {} + + // 启动周期性刷新设备信息(信号/连接状态) + try { this.startDeviceInfoTimer && this.startDeviceInfoTimer() } catch (e) { /* ignore */ } + // 延迟计算日志区域高度,确保布局完成后获取正确位置 + try { setTimeout(() => { try { this.updateLogListHeight && this.updateLogListHeight() } catch (e) {} }, 250) } catch (e) {} + }, + + onHide() { + // 页面隐藏时不停止设备信息轮询,保留以便断开后继续刷新(如需可在此处暂停) + }, + + updateLogListHeight() { + // 1. 拿到屏幕可用高度(px) + const sys = wx.getWindowInfo(); + const screenHeight = sys.windowHeight; // px + + // 2. 拿到 scroll-view 的 top(px) + + wx.createSelectorQuery() + .in(this) + .select('#cnmdgdx') + .boundingClientRect(rect => { + if (rect) { + const topPx = rect.top; // px + const bottomPx = 10 / 2; // 10rpx → 5px(2倍屏) + const heightPx = screenHeight - topPx - bottomPx; + + // 3. 转 rpx 并写入 + this.setData({ + logListHeight: heightPx * 2 // px→rpx + }); + } + }) + .exec(); + }, onUnload() { @@ -334,6 +438,7 @@ Page({ } catch (e) { /* ignore */ } this._onBleConnChange = null try { this.stopReconnectTimer && this.stopReconnectTimer() } catch (e) {} + try { this.stopDeviceInfoTimer && this.stopDeviceInfoTimer() } catch (e) { /* ignore */ } }, // 顶部标签切换 @@ -351,6 +456,10 @@ Page({ // this.onStartOta() // }, 200) } + if (id === 4) { + // 切换到通信日志页时计算日志区域高度 + try { setTimeout(() => { try { this.updateLogListHeight && this.updateLogListHeight() } catch (e) {} }, 120) } catch (e) {} + } }, onOpenDelayChange(e) { @@ -479,6 +588,77 @@ Page({ } }, + // 发送读取门磁/卫浴事件参数请求 + sendReadDoorBathEvent() { + try { + const pkt = buildReadDoorBathEvent() + // 设置一个短期的 pendingResponse,若收到匹配类型则由 handleIncomingPacket 解析并回调 + const self = this + // 清理旧的 pending + try { if (this._pendingResponse && this._pendingResponse._timeout) clearTimeout(this._pendingResponse._timeout) } catch (e) {} + this._pendingResponse = { + expectedType: COMMANDS.READ_DOOR_BATH_EVENT & 0xFF, + resolve(params) { + try { + // params 应为至少 8 字节:P0..P7 四个 16-bit 小端数(单位:秒) + if (!params || params.length < 8) { + self.appendLog('PARSE', '读取门卫事件返回长度不足') + wx.showToast({ title: '读取返回长度异常', icon: 'none' }) + return + } + const toU16 = (off) => (params[off] & 0xFF) | ((params[off + 1] & 0xFF) << 8) + const doorTriggerSec = toU16(0) + const doorReleaseSec = toU16(2) + const bathTriggerSec = toU16(4) + const bathReleaseSec = toU16(6) + + const conv = (sec) => { + const n = Number(sec || 0) + if (n <= 60) return { val: n, unitIdx: 0 } + const mins = Math.max(1, Math.round(n / 60)) + return { val: Math.min(mins, 30), unitIdx: 1 } + } + + const dTrig = conv(doorTriggerSec) + const dRel = conv(doorReleaseSec) + const bTrig = conv(bathTriggerSec) + const bRel = conv(bathReleaseSec) + + self.setData({ + doorTriggerDelay: dTrig.val, + doorTriggerUnitIndex: dTrig.unitIdx, + doorReleaseDelay: dRel.val, + doorReleaseUnitIndex: dRel.unitIdx, + bathTriggerDelay: bTrig.val, + bathTriggerUnitIndex: bTrig.unitIdx, + bathReleaseDelay: bRel.val, + bathReleaseUnitIndex: bRel.unitIdx + }) + self.appendLog('PARSE', `读取门卫事件: 门触发=${doorTriggerSec}s, 门释放=${doorReleaseSec}s, 卫触发=${bathTriggerSec}s, 卫释放=${bathReleaseSec}s`) + wx.showToast({ title: '已更新事件参数', icon: 'success' }) + } catch (ex) { + self.appendLog('WARN', `解析门卫事件返回异常 ${ex && (ex.message||ex)}`) + } + } + } + // 设置超时,3s后清理 pending + this._pendingResponse._timeout = setTimeout(() => { try { this._pendingResponse = null } catch (e) {} }, 3000) + this.transmitPacket(pkt, '读取门卫事件') + } catch (err) { + wx.showToast({ title: '构包失败', icon: 'none' }) + } + }, + + onReadDoorEvent() { + if (!this.data.isConnected) { wx.showToast({ title: '未连接设备', icon: 'none' }); return } + this.sendReadDoorBathEvent() + }, + + onReadBathEvent() { + if (!this.data.isConnected) { wx.showToast({ title: '未连接设备', icon: 'none' }); return } + this.sendReadDoorBathEvent() + }, + // 切换雷达读取状态:开始/停止 toggleRadarRead() { const reading = !!this.data.radarReading @@ -1250,6 +1430,7 @@ Page({ // 移除旧监听,防止重复触发(页面重复进入或多次初始化的场景) this.teardownBleListener() + try { if (this.data.debugDeviceInfoLogs) this.appendLog('DBG', 'setupBleListener: re-registering listeners') } catch (e) {} // 运行环境不支持通知回调则直接返回(避免报错) if (typeof wx.onBLECharacteristicValueChange !== 'function') return // 定义并缓存通知回调,便于后续 off 解绑 @@ -1312,12 +1493,20 @@ Page({ if (connected) { // 连接成功,停止重连计时并启用发送按钮 this.setData({ isConnected: true }) + try { if (this.data.debugDeviceInfoLogs) this.appendLog('DBG', 'onBLEConnectionStateChange: connected') } catch (e) {} + this.setData({ isReconnecting: false }) try { this.stopReconnectTimer && this.stopReconnectTimer() } catch (e) {} try { this.ensureBleChannels(() => {}) } catch (e) {} + try { this.updateDeviceInfo && this.updateDeviceInfo() } catch (e) { /* ignore */ } + try { this.startDeviceInfoTimer && this.startDeviceInfoTimer() } catch (e) { /* ignore */ } } else { // 断开,禁用发送并启动重连计时 this.setData({ isConnected: false }) + try { if (this.data.debugDeviceInfoLogs) this.appendLog('DBG', 'onBLEConnectionStateChange: disconnected') } catch (e) {} + this.setData({ isReconnecting: true }) try { this.startReconnectTimer && this.startReconnectTimer() } catch (e) {} + try { this.updateDeviceInfo && this.updateDeviceInfo() } catch (e) { /* ignore */ } + try { this.startDeviceInfoTimer && this.startDeviceInfoTimer() } catch (e) { /* ignore */ } } } catch (e) { /* ignore */ } } @@ -1330,6 +1519,7 @@ Page({ if (this._reconnectTimer) return const deviceId = this.data.deviceId if (!deviceId) return + try { this.setData({ isReconnecting: true }) } catch (e) { /* ignore */ } this._reconnectTimer = setInterval(() => { try { if (typeof wx.createBLEConnection === 'function') { @@ -1337,7 +1527,14 @@ Page({ // createBLEConnection 成功即认为已连接 this.setData({ isConnected: true }) try { this.stopReconnectTimer() } catch (e) {} - try { this.ensureBleChannels(() => {}) } catch (e) {} + try { this.setData({ isReconnecting: false }) } catch (e) { /* ignore */ } + try { + this.ensureBleChannels(() => { + try { this.setupBleListener() } catch (e) { /* ignore */ } + }) + } catch (e) { /* ignore */ } + try { this.updateDeviceInfo && this.updateDeviceInfo() } catch (e) { /* ignore */ } + try { this.startDeviceInfoTimer && this.startDeviceInfoTimer() } catch (e) { /* ignore */ } }, fail: () => { // ignore failure, will retry } }) @@ -1351,6 +1548,29 @@ Page({ clearInterval(this._reconnectTimer) this._reconnectTimer = null } + try { this.setData({ isReconnecting: false }) } catch (e) { /* ignore */ } + }, + // 设备信息轮询管理:每 intervalMs 刷新一次设备信息(幂等) + startDeviceInfoTimer(intervalMs = 1000) { + try { + if (this._deviceInfoTimer) return + const ms = Number(intervalMs) || 1000 + this._deviceInfoTimer = setInterval(() => { + try { + if (this.data.debugDeviceInfoLogs) this.appendLog('DBG', 'deviceInfoTimer tick') + this.updateDeviceInfo && this.updateDeviceInfo() + } catch (e) { /* ignore */ } + }, ms) + } catch (e) { /* ignore */ } + }, + + stopDeviceInfoTimer() { + try { + if (this._deviceInfoTimer) { + clearInterval(this._deviceInfoTimer) + this._deviceInfoTimer = null + } + } catch (e) { /* ignore */ } }, onDownloadOtaTool() { const url = 'https://www.baidu.com/'; @@ -1410,10 +1630,20 @@ Page({ } catch (e) { return '' } }, teardownBleListener() { - if (this._onBleChange && typeof wx.offBLECharacteristicValueChange === 'function') { - wx.offBLECharacteristicValueChange(this._onBleChange) - } + try { + if (this._onBleChange && typeof wx.offBLECharacteristicValueChange === 'function') { + try { if (this.data.debugDeviceInfoLogs) this.appendLog('DBG', 'teardownBleListener: offBLECharacteristicValueChange') } catch (e) {} + wx.offBLECharacteristicValueChange(this._onBleChange) + } + } catch (e) { /* ignore */ } this._onBleChange = null + try { + if (this._onBleConnChange && typeof wx.offBLEConnectionStateChange === 'function') { + try { if (this.data.debugDeviceInfoLogs) this.appendLog('DBG', 'teardownBleListener: offBLEConnectionStateChange') } catch (e) {} + try { wx.offBLEConnectionStateChange(this._onBleConnChange) } catch (e) { /* ignore */ } + } + } catch (e) { /* ignore */ } + this._onBleConnChange = null }, handleIncomingPacket(u8) { @@ -1458,6 +1688,53 @@ Page({ this.appendLog('WARN', '解析读版本响应失败') } } + // 读取门磁/卫浴事件参数响应 (Frame_Type = 0x17) + if (frameType === (COMMANDS.READ_DOOR_BATH_EVENT & 0xFF)) { + try { + const params = u8.slice(11) || [] + if (params.length >= 8) { + const toU16 = (off) => (params[off] & 0xFF) | ((params[off + 1] & 0xFF) << 8) + const doorTriggerSec = toU16(0) + const doorReleaseSec = toU16(2) + const bathTriggerSec = toU16(4) + const bathReleaseSec = toU16(6) + const conv = (sec) => { + const n = Number(sec || 0) + if (n <= 60) return { val: n, unitIdx: 0 } + const mins = Math.max(1, Math.round(n / 60)) + return { val: Math.min(mins, 30), unitIdx: 1 } + } + const dTrig = conv(doorTriggerSec) + const dRel = conv(doorReleaseSec) + const bTrig = conv(bathTriggerSec) + const bRel = conv(bathReleaseSec) + this.setData({ + doorTriggerDelay: dTrig.val, + doorTriggerUnitIndex: dTrig.unitIdx, + doorReleaseDelay: dRel.val, + doorReleaseUnitIndex: dRel.unitIdx, + bathTriggerDelay: bTrig.val, + bathTriggerUnitIndex: bTrig.unitIdx, + bathReleaseDelay: bRel.val, + bathReleaseUnitIndex: bRel.unitIdx + }) + this.appendLog('PARSE', `读取门卫事件: 门触发=${doorTriggerSec}s, 门释放=${doorReleaseSec}s, 卫触发=${bathTriggerSec}s, 卫释放=${bathReleaseSec}s`) + } else { + this.appendLog('PARSE', '读取门卫事件:返回数据长度不足') + } + // 若存在 pendingResponse,交由其 resolve(avoid duplicate parsing) + try { + if (this._pendingResponse && this._pendingResponse.expectedType === (COMMANDS.READ_DOOR_BATH_EVENT & 0xFF)) { + const params = u8.slice(11) || [] + try { this._pendingResponse.resolve(params) } catch (e) { /* ignore */ } + try { if (this._pendingResponse._timeout) clearTimeout(this._pendingResponse._timeout) } catch (e) {} + this._pendingResponse = null + } + } catch (e) { /* ignore */ } + } catch (e) { + this.appendLog('WARN', '解析读取门卫事件响应异常') + } + } // 如果存在挂起的等待响应(onOneKeySend 使用),并且类型匹配,则回调并清理 try { if (this._pendingResponse && this._pendingResponse.expectedType != null) { @@ -2733,9 +3010,56 @@ Page({ const key = e.currentTarget.dataset.key if (!key) return const checked = (e.detail.value || []).includes(key) + // 合并逻辑:当是 hexShow 时,同时维护 showChineseLogs 并发送协议命令 + if (key === 'hexShow') { + // hexShow 为 true 时表示以 HEX 形式展示,需关闭中文日志;反之打开中文日志 + const showChinese = !checked + this.setData({ hexShow: checked, showChineseLogs: showChinese }) + try { this.sendChineseLogCommand(showChinese) } catch (err) { this.appendLog('WARN', `发送中文日志命令失败: ${err && (err.message || err)}`) } + return + } this.setData({ [key]: checked }) }, + // 发送“中文日志 开/关”命令:enable=true 表示开启中文日志(设备返回中文),false 表示关闭中文日志 + sendChineseLogCommand(enable) { + try { + const flag = enable ? 1 : 0 + const pkt = buildCommand(COMMANDS.ENABLE_BLE_LOG, [flag]) + // 记录发送日志 + try { this.appendLog('TX', `中文日志 ${enable ? '开' : '关'} -> ${this.toHex ? this.toHex(pkt) : ''}`) } catch (e) { /* ignore */ } + + // 优先使用已存在的写入接口 + if (typeof this.writeRawBytes === 'function') { + try { this.writeRawBytes(pkt, '中文日志开关') } catch (e) { /* ignore */ } + return + } + if (typeof this.writeBleBytes === 'function') { + try { this.writeBleBytes(pkt, '中文日志开关') } catch (e) { /* ignore */ } + return + } + + // 回退到原生 API(若页面保存了 deviceId/serviceId/txCharId) + const deviceId = this.data.deviceId || '' + const serviceId = this.data.serviceId || '' + const charId = this.data.txCharId || this.data.txChar || '' + if (deviceId && serviceId && charId && typeof wx.writeBLECharacteristicValue === 'function') { + const ab = new Uint8Array(pkt).buffer + try { + wx.writeBLECharacteristicValue({ deviceId, serviceId, characteristicId: charId, value: ab, success: () => { this.appendLog('UI', '中文日志命令写入成功') }, fail: (e) => { this.appendLog('WARN', `写入中文日志命令失败 ${e && e.errMsg}`) } }) + } catch (e) { + this.appendLog('WARN', `写入中文日志命令异常 ${e && (e.message || e)}`) + } + return + } + + // 无可用写入路径 + this.appendLog('WARN', '未找到可用的写入接口以发送中文日志命令') + } catch (err) { + this.appendLog('WARN', `构造中文日志命令失败: ${err && (err.message || err)}`) + } + }, + onInputChange(e) { this.setData({ sendText: e.detail.value }) }, @@ -2818,7 +3142,8 @@ Page({ const cur = Array.isArray(this.data.logList) ? this.data.logList : [] const next = [{ id, time: timeStr, text: finalText }, ...cur] if (next.length > maxLogs) next.length = maxLogs - this.setData({ logList: next }) + // 更新日志并触发滚动到最新项 + this.setData({ logList: next, logScrollTo: id }) } catch (e) { // 若 setData 出现异常,仍保证不抛到外层 try { console.warn('appendLog setData failed', e) } catch (xx) { /* ignore */ } diff --git a/pages/basics/BluetoothDebugging/B13page/B13page.wxml b/pages/basics/BluetoothDebugging/B13page/B13page.wxml index 32d86c2..7e866b9 100644 --- a/pages/basics/BluetoothDebugging/B13page/B13page.wxml +++ b/pages/basics/BluetoothDebugging/B13page/B13page.wxml @@ -19,7 +19,8 @@ - + + 蓝牙名称: {{bleName || '-'}} @@ -27,19 +28,30 @@ MAC: {{bleMac || '-'}} - 版本: - {{bleVersion || '-'}} - - - 信号: - {{bleSignal}} - RSSI: - {{bleRSSI}} - 状态: - {{isConnected ? '已连接' : '未连接'}} - + + - 读取蓝牙信息 + + + + + + + 信号: + {{bleSignal}} + + + 版本: + {{bleVersion || '-'}} + + + 状态: + {{isConnected ? '已连接' : '未连接'}} + + + + + @@ -52,19 +64,17 @@ --> - + - - {{ + {{ item.key === 'door' ? (item.triggered ? '门磁(开门)' : '门磁(关门)') : item.key === 'bath' ? (item.triggered ? '卫浴(触发)' : '卫浴(释放)') : item.key === 'bed' ? (item.triggered ? '卧室(触发)' : '卧室(释放)') : item.key === 'hall' ? (item.triggered ? '走廊(触发)' : '走廊(释放)') : item.label - }} - + }} @@ -73,38 +83,38 @@ - + 房间有人 - + 房间无人 - + 门开 - + 门关 - + 卫浴有人 - + @@ -116,8 +126,9 @@ 门磁开廊灯事件设置 - - + + + @@ -142,7 +153,8 @@ 卫浴雷达开卫浴灯事件设置 - + + @@ -163,22 +175,32 @@ - - - - 通讯日志 - - - + + + + + + + 通信日志 + + + + + + + + + + - + @@ -192,41 +214,18 @@