增加W13设备设置蓝牙名称功能
This commit is contained in:
@@ -202,6 +202,16 @@ MCU -> PC
|
|||||||
- 请求示例(PC→MCU):Frame_Type=0x17,P0=0x01。
|
- 请求示例(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(均为小端)。
|
- 响应示例(MCU→PC):Frame_Type=0x17,参数区域例如 P0~P7 = [0x0A,0x00, 0x14,0x00, 0x05,0x00, 0x08,0x00] 表示:门磁触发延时 10s,门磁释放延时 20s,卫浴触发 5s,卫浴释放 8s(均为小端)。
|
||||||
|
|
||||||
|
### 3.10 设置蓝牙名
|
||||||
|
| 方向 | 命令字 | 参数 | 备注 |
|
||||||
|
|------|-------|------|------|
|
||||||
|
| PC→MCU | 0x20 | P0: 设置名称的有效长度<br> P1~P4: 当前只支持设置房号后面四个字符 | 当前蓝牙名称:BLW_W13_XXXX;注意:后四位为字符类型 |
|
||||||
|
| MCU→PC | 0x20 | P0:<br> 0x01: 参数正确<br> 0x02: 参数错误 | 返回设置结果 |
|
||||||
|
|
||||||
|
说明:
|
||||||
|
- 请求示例(PC→MCU):Frame_Type=0x20,P0=0x04,P1~P4 对应后四位字符(ASCII 小端/逐字节)。
|
||||||
|
- 响应示例(MCU→PC):Frame_Type=0x20,P0=0x01 表示设置成功,P0=0x02 表示参数错误。
|
||||||
|
|
||||||
## 4. 命令交互流程图
|
## 4. 命令交互流程图
|
||||||
### 4.1 读版本号流程
|
### 4.1 读版本号流程
|
||||||
```mermaid
|
```mermaid
|
||||||
|
|||||||
6
app.json
6
app.json
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"pages": [
|
"pages": [
|
||||||
|
|
||||||
"pages/autho/index",
|
"pages/autho/index",
|
||||||
"pages/basics/BluetoothDebugging/B13page/B13page",
|
"pages/basics/BluetoothDebugging/B13page/B13page",
|
||||||
"pages/login/login",
|
"pages/login/login",
|
||||||
"pages/index/index",
|
"pages/index/index",
|
||||||
"pages/mycenter/index",
|
"pages/mycenter/index",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
const { buildCommand, buildReadVersion, buildSetDoorBathEvent, buildReadDoorBathEvent, COMMANDS, verifyHexPacket } = require('../../../../utils/w13Packet.js')
|
const { buildCommand, buildReadVersion, buildSetDoorBathEvent, buildReadDoorBathEvent, buildSetBluetoothName, COMMANDS, verifyHexPacket } = require('../../../../utils/w13Packet.js')
|
||||||
const FIXED_CONNECT_CMD = new Uint8Array([0xCC, 0xC0, 0x0C, 0x00, 0x4F, 0xC0, 0x01, 0x00, 0x02, 0x00, 0x0C, 0x08])
|
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
|
// Optional encoding library for robust GBK/GB18030 decoding
|
||||||
let EncodingLib = null
|
let EncodingLib = null
|
||||||
@@ -19,6 +19,8 @@ Page({
|
|||||||
bleMac: '00:00:00:00:00:00',
|
bleMac: '00:00:00:00:00:00',
|
||||||
bleAMC: '-',
|
bleAMC: '-',
|
||||||
bleVersion: '-',
|
bleVersion: '-',
|
||||||
|
// 设置蓝牙名后四位输入
|
||||||
|
bleNameSuffix: '',
|
||||||
// 设备信号/RSSI/连接状态显示
|
// 设备信号/RSSI/连接状态显示
|
||||||
bleSignal: '-',
|
bleSignal: '-',
|
||||||
bleRSSI: '-',
|
bleRSSI: '-',
|
||||||
@@ -395,6 +397,53 @@ Page({
|
|||||||
try { setTimeout(() => { try { this.updateLogListHeight && this.updateLogListHeight() } catch (e) {} }, 250) } catch (e) {}
|
try { setTimeout(() => { try { this.updateLogListHeight && this.updateLogListHeight() } catch (e) {} }, 250) } catch (e) {}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onBleNameInput(e) {
|
||||||
|
const v = (e && e.detail && e.detail.value) ? String(e.detail.value) : ''
|
||||||
|
this.setData({ bleNameSuffix: v })
|
||||||
|
},
|
||||||
|
|
||||||
|
onSendBleName() {
|
||||||
|
if (!this.data.isConnected) { wx.showToast({ title: '未连接设备', icon: 'none' }); return }
|
||||||
|
const suffix = (this.data.bleNameSuffix || '').toString()
|
||||||
|
if (suffix.length === 0 || suffix.length > 4) {
|
||||||
|
wx.showToast({ title: '请输入 1 到 4 个字符', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 简单校验:仅允许可打印 ASCII(32..126)
|
||||||
|
for (let i = 0; i < suffix.length; i++) {
|
||||||
|
const c = suffix.charCodeAt(i)
|
||||||
|
if (c < 32 || c > 126) { wx.showToast({ title: '仅支持可打印字符', icon: 'none' }); return }
|
||||||
|
}
|
||||||
|
// 二次确认:提示设备将重启
|
||||||
|
wx.showModal({
|
||||||
|
title: '确认设置',
|
||||||
|
content: '设置蓝牙名称后设备将重启,是否继续?',
|
||||||
|
confirmText: '继续',
|
||||||
|
cancelText: '取消',
|
||||||
|
success: (res) => {
|
||||||
|
if (!res.confirm) return
|
||||||
|
try {
|
||||||
|
const pkt = buildSetBluetoothName(suffix)
|
||||||
|
wx.showLoading({ title: '正在设置...' })
|
||||||
|
this.transmitPacket(pkt, '设置蓝牙名')
|
||||||
|
// 乐观更新显示名称(可见性增强),但实际以设备返回为准
|
||||||
|
try {
|
||||||
|
const cur = this.data.bleName || ''
|
||||||
|
if (/BLW_W13_/.test(cur)) {
|
||||||
|
const base = cur.slice(0, Math.max(0, cur.length - 4))
|
||||||
|
const padded = suffix.padEnd(4, ' ')
|
||||||
|
this.setData({ bleName: base + padded })
|
||||||
|
} else {
|
||||||
|
this.setData({ bleName: (cur || '') + suffix })
|
||||||
|
}
|
||||||
|
} catch (e) { /* ignore */ }
|
||||||
|
} catch (err) {
|
||||||
|
wx.showToast({ title: '构包失败', icon: 'none' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
onHide() {
|
onHide() {
|
||||||
// 页面隐藏时不停止设备信息轮询,保留以便断开后继续刷新(如需可在此处暂停)
|
// 页面隐藏时不停止设备信息轮询,保留以便断开后继续刷新(如需可在此处暂停)
|
||||||
},
|
},
|
||||||
@@ -1673,6 +1722,37 @@ Page({
|
|||||||
this.appendLog('PARSE', `雷达状态: 有效端口${parsed.portCount} 有人标记=${parsed.human === 0x01 ? '有人' : '无人'} 位=0b${parsed.bits.toString(2).padStart(8, '0')}`)
|
this.appendLog('PARSE', `雷达状态: 有效端口${parsed.portCount} 有人标记=${parsed.human === 0x01 ? '有人' : '无人'} 位=0b${parsed.bits.toString(2).padStart(8, '0')}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 设置蓝牙名响应 (Frame_Type = 0x20)
|
||||||
|
if (frameType === (COMMANDS.SET_BLE_NAME & 0xFF)) {
|
||||||
|
try {
|
||||||
|
const params = u8.slice(11) || []
|
||||||
|
if (params.length >= 1) {
|
||||||
|
if (params[0] === 0x01) {
|
||||||
|
this.appendLog('PARSE', '设置蓝牙名:设备返回成功')
|
||||||
|
wx.hideLoading()
|
||||||
|
wx.showToast({ title: '设置蓝牙名成功,设备重启中...', icon: 'success' })
|
||||||
|
// 等待短暂时间后返回蓝牙搜索页(上一页)
|
||||||
|
setTimeout(() => {
|
||||||
|
try { wx.navigateBack() } catch (e) { /* ignore */ }
|
||||||
|
}, 900)
|
||||||
|
} else {
|
||||||
|
this.appendLog('PARSE', '设置蓝牙名:设备返回参数错误')
|
||||||
|
wx.hideLoading()
|
||||||
|
wx.showToast({ title: '设备返回参数错误', icon: 'none' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (this._pendingResponse && this._pendingResponse.expectedType === (COMMANDS.SET_BLE_NAME & 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', '解析设置蓝牙名响应异常')
|
||||||
|
}
|
||||||
|
}
|
||||||
// 读版本号响应
|
// 读版本号响应
|
||||||
if (frameType === (COMMANDS.READ_VERSION & 0xFF)) {
|
if (frameType === (COMMANDS.READ_VERSION & 0xFF)) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -65,6 +65,24 @@
|
|||||||
</view> -->
|
</view> -->
|
||||||
|
|
||||||
<!-- 雷达状态卡片(含读雷达按钮) -->
|
<!-- 雷达状态卡片(含读雷达按钮) -->
|
||||||
|
<!-- 设置蓝牙名卡片(位于雷达状态卡片前) -->
|
||||||
|
<view class="cfg-card">
|
||||||
|
<view class="cfg-head head-row">
|
||||||
|
<text>设置蓝牙名</text>
|
||||||
|
</view>
|
||||||
|
<view class="form-row">
|
||||||
|
<view class="form-inline">
|
||||||
|
<text class="label">后四位</text>
|
||||||
|
<input class="picker-text ble-suffix" placeholder="输入房号" value="{{bleNameSuffix}}" bindinput="onBleNameInput" />
|
||||||
|
<text class="label">当前:</text>
|
||||||
|
<text class="picker-text ble-suffix">{{bleName || '-'}}</text>
|
||||||
|
<view class="cfg-actions" style="margin-top:8rpx;">
|
||||||
|
<button size="mini" type="primary" bindtap="onSendBleName" disabled="{{!isConnected}}">设置</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
<view class="grid-and-actions">
|
<view class="grid-and-actions">
|
||||||
<view class="grid">
|
<view class="grid">
|
||||||
<view class="grid-item" wx:for="{{radarLights}}" wx:key="key">
|
<view class="grid-item" wx:for="{{radarLights}}" wx:key="key">
|
||||||
|
|||||||
@@ -286,6 +286,9 @@
|
|||||||
.inline-input { width: 110rpx; height: 44rpx; padding: 0 8rpx; border: 1rpx solid #e5e9f2; border-radius: 8rpx; font-size: 24rpx; box-sizing: border-box; }
|
.inline-input { width: 110rpx; height: 44rpx; padding: 0 8rpx; border: 1rpx solid #e5e9f2; border-radius: 8rpx; font-size: 24rpx; box-sizing: border-box; }
|
||||||
.inline-picker .picker-text { width: 90rpx; height: 44rpx; padding: 0 8rpx; border-radius: 8rpx; font-size: 22rpx; }
|
.inline-picker .picker-text { width: 90rpx; height: 44rpx; padding: 0 8rpx; border-radius: 8rpx; font-size: 22rpx; }
|
||||||
|
|
||||||
|
/* 专用:设置蓝牙名后四位输入,宽度减半显示 */
|
||||||
|
.ble-suffix { width: 30%; box-sizing: border-box; }
|
||||||
|
|
||||||
/* If screen too narrow, allow wrapping but keep label + control groups together */
|
/* If screen too narrow, allow wrapping but keep label + control groups together */
|
||||||
@media (max-width: 360px) {
|
@media (max-width: 360px) {
|
||||||
.form-inline { flex-wrap: wrap; }
|
.form-inline { flex-wrap: wrap; }
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ export const COMMANDS = {
|
|||||||
// 读取门磁/卫浴事件触发/释放参数
|
// 读取门磁/卫浴事件触发/释放参数
|
||||||
READ_DOOR_BATH_EVENT: 0x17,
|
READ_DOOR_BATH_EVENT: 0x17,
|
||||||
RADAR_STATUS: 0x11,
|
RADAR_STATUS: 0x11,
|
||||||
|
// 设置蓝牙名称(仅后四位)
|
||||||
|
SET_BLE_NAME: 0x20,
|
||||||
TEST_KEYS: 0x13,
|
TEST_KEYS: 0x13,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -238,6 +240,37 @@ export function buildReadDoorBathEvent(options = {}) {
|
|||||||
return buildCommand(COMMANDS.READ_DOOR_BATH_EVENT, [0x01], options);
|
return buildCommand(COMMANDS.READ_DOOR_BATH_EVENT, [0x01], options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造:设置蓝牙名(Frame_Type=0x20)
|
||||||
|
* 协议要求:P0 = 有效长度(1..4)
|
||||||
|
* P1~P4: 后四位字符(ASCII 字节),不足用 0x00 填充;若输入长度>4,取最后 4 个字符
|
||||||
|
* @param {string|number[]|Uint8Array} name 后四位字符串或字节数组
|
||||||
|
* @param {{frame?:number, framNum?:number, crcType?:('CCITT'|'MODBUS'), head?:number[]}} [options]
|
||||||
|
*/
|
||||||
|
export function buildSetBluetoothName(name, options = {}) {
|
||||||
|
// 接受字符串或字节数组
|
||||||
|
let arr = [];
|
||||||
|
if (typeof name === 'string') {
|
||||||
|
const s = name.slice(-4);
|
||||||
|
for (let i = 0; i < s.length; i++) arr.push(s.charCodeAt(i) & 0xFF);
|
||||||
|
} else if (name instanceof Uint8Array) {
|
||||||
|
for (let i = 0; i < Math.min(4, name.length); i++) arr.push(name[i] & 0xFF);
|
||||||
|
} else if (Array.isArray(name)) {
|
||||||
|
for (let i = 0; i < Math.min(4, name.length); i++) arr.push(name[i] & 0xFF);
|
||||||
|
} else if (name == null) {
|
||||||
|
arr = [];
|
||||||
|
} else {
|
||||||
|
// 尝试转换
|
||||||
|
const u = ensureUint8Array(name);
|
||||||
|
for (let i = 0; i < Math.min(4, u.length); i++) arr.push(u[i] & 0xFF);
|
||||||
|
}
|
||||||
|
const len = Math.min(4, Math.max(0, arr.length));
|
||||||
|
// P1~P4 必须有 4 字节位置,短则补 0
|
||||||
|
const p = [len];
|
||||||
|
for (let i = 0; i < 4; i++) p.push(i < arr.length ? (arr[i] & 0xFF) : 0x00);
|
||||||
|
return buildCommand(COMMANDS.SET_BLE_NAME, p, options);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证十六进制字符串包并计算/写入 CRC(默认 MODBUS),返回完整包与CRC值
|
* 验证十六进制字符串包并计算/写入 CRC(默认 MODBUS),返回完整包与CRC值
|
||||||
* @param {string} hexStr 如 'CC C0 0C 00 00 00 01 00 02 00 0C 08' 或连续hex
|
* @param {string} hexStr 如 'CC C0 0C 00 00 00 01 00 02 00 0C 08' 或连续hex
|
||||||
|
|||||||
Reference in New Issue
Block a user