蓝牙控制板底层通信协议V1版
蓝牙控制板相关协议
一.主服务
serviceId:0000fff0-0000-1000-8000-00805f9b34fb
蓝牙扫描时可通过指定serviceId过滤设备
二.广播数据
advertisData:0x010136630D040098
36630D040098为设备的mac地址,用于IOS系统识别设备的身份
三.应用服务
服务ID:00000001-0000-1000-8000-00805F9B34FB
characteristicId-write:000284CF-F7E3-55B4-6C4C-9FD140100A16
characteristicId-notify:000384CF-F7E3-55B4-6C4C-9FD140100A16
characteristicId-write:写指令及相关参数
characteristicId-notify:控制板响应通知
四.流程1-设备连接
- 扫描通过主服务过滤扫描设备
- mac地址/deviceId连接设备
- 发现应用服务
- 开启characteristicId-notify特征监听
当主机与设备连接成功后在开启监听characteristicId-notify的情况下会收到设备的认证参数
认证参数:0x31584d5f6c63685776363338314635434241
ASCII对照:31=字符1 58=字符X 依次类推可得结果:1XM_lock_v6381F5CBA
1
流程ID:连接成功
XM_lock_v6
10个字符长度的设备名称
381F5CBA
8个字符长度的随机串,每次连接和断开会重置
取XM_lock_v6381F5CBA
保存,用于后期交互验证【以下均称为认证串】
五.流程2-指令发送
指令集:
* id 响应次数 名称
* 20 2次 读配置
* 21 2次 开锁 V
* 24 1次 改密码 V
* 25 1次 改名字 V
* 26 1次 查状态 V
* 27 1次 写27 V
* 28 1次 写28 V
* 29 1次 读版本 V
* 2a 1次 带参数的开锁 V
* 2b 1次 带参数的关锁 V
8字符密码:默认00000000可通过指令更改
下述+均为字符串的拼接
读取锁的配置信息20:
指令id:20
密钥: 认证串+8字符密码(字符串拼接)通过hex_md5加密后toUpperCase().substring(0, 8)
写characteristicId-write:
// act 指令id
// md5p 密钥
const genValue = function (act, md5p) {
let sendresA = act + md5p;
let sendresB = params
let l = sendresA.length
let buffer = new ArrayBuffer(l)
let dataView = new DataView(buffer)
for (var i = 0; i < sendresA.length; i++) {
dataView.setUint8(i, sendresA.charAt(i).charCodeAt())
}
return buffer
}
第一次通知characteristicId-notify:3330xxxxxxxxxxxxxxxxxxxx
- 33 => 字符3
- 30 => 字符0
3330=>30 表示对20的回复
如果:xxxx....为0则密钥验证失败
结果解析
let res = "3330xxxxxxxxxxxxxxxxxxxx".substring(4, 24)
let a = res.substr(0, 2);
let b = res.substr(2, 4);
let c = res.substr(6, 2);
let d = res.substr(8, 2);
let e = res.substr(10, 4);
let f = res.substr(14, 4);
let g = res.substr(18, 2)
(图一)
各个结果对应内容如上图所示
第二次通知characteristicId-notify:3338xxxxxxxx
let res = "3330xxxxxxxx".substring(4, 12)
let a = res.substr(0, 2);
let b = res.substr(2, 2);
let c = res.substr(4, 2);
let d = res.substr(6, 2);
(图二)
开指令21
指令id:21
密钥: 认证串+8字符密码(字符串拼接)通过hex_md5加密后toUpperCase().substring(0, 8)
写characteristicId-write:
// act 指令id
// md5p 密钥
const genValue = function (act, md5p) {
let sendresA = act + md5p;
let sendresB = params
let l = sendresA.length
let buffer = new ArrayBuffer(l)
let dataView = new DataView(buffer)
for (var i = 0; i < sendresA.length; i++) {
dataView.setUint8(i, sendresA.charAt(i).charCodeAt())
}
return buffer
}
第一次通知characteristicId-notify:转换为ASCII字符串310d120003000300
- 31 对 21 指令的回复
- 0D12 16进制电压
- 0003 16进制开锁次数
- 0003 16进制总开锁次数
- 00 接收指令时的状态 [00关/10开]
第二次通知characteristicId-notify:转换为ASCII字符串310d120003000310
- 31 对 21 指令的回复
- 0D12 16进制电压
- 0003 16进制开锁次数
- 0003 16进制总开锁次数
- 11 之心指令后状态 [00关/10开]
对比两次回复
- 00->01 表示打开成功
- 00->00 表示打开失败
- 01->01 表示打开成功
改密码指令24
指令id:24
密钥:认证串+8字符密码(字符串拼接)通过hex_md5加密后toUpperCase().substring(0, 8)
参数:8字符新密码
写characteristicId-write
// act 指令
// sendresB 8字符新密码
// md5p 密钥
function getValue(act,md5p,sendresB){
let sendresA = act + md5p + sendresB;
let l = sendresA.length
let buffer = new ArrayBuffer(l)
let dataView = new DataView(buffer)
for (var i = 0; i < sendresA.length; i++) {
dataView.setUint8(i, sendresA.charAt(i).charCodeAt())
}
return buffer
}
通知characteristicId-notify:转换为ASCII字符串340d120003000310
如果为3400000000000000 表示旧密码验证错误
断开连接后重新连接生效
改名称25
指令id:24
密钥:认证串+8字符密码(字符串拼接)通过hex_md5加密后toUpperCase().substring(0, 8)
参数:10字符新名称
写characteristicId-write
// act 指令
// sendresB 10字符新名称
// md5p 密钥
function getValue(act,md5p,sendresB){
let sendresA = act + md5p + sendresB;
let l = sendresA.length
let buffer = new ArrayBuffer(l)
let dataView = new DataView(buffer)
for (var i = 0; i < sendresA.length; i++) {
dataView.setUint8(i, sendresA.charAt(i).charCodeAt())
}
return buffer
}
通知characteristicId-notify:转换为ASCII字符串350d120003000310
如果为3500000000000000 表示密码验证错误
断开连接后重新连接生效
查询当前状态26
指令id:26
密钥:(认证串)toUpperCase().substr(10,8) // 此处不需要密码和md5 直接切
写characteristicId-write
// act 指令
// unp 直接切的认证串
function getValue(act,unp){
let sendresA = act + unp;
let l = sendresA.length;
let buffer = new ArrayBuffer(l)
let dataView = new DataView(buffer)
for (var i = 0; i < sendresA.length; i++) {
dataView.setUint8(i, sendresA.charAt(i).charCodeAt())
}
return buffer
}
通知characteristicId-notify:360d120003000310
解析规则与21指令回复一致
写配置27【业务配置】
指令id:27
密钥:认证串+8字符密码(字符串拼接)通过hex_md5加密后toUpperCase().substring(0, 8)
参数:16进制的字符串规则为上述(图一)
写characteristicId-write
// act 指令id
// md5p 密钥
// params 参数
const genValue = function (act, md5p,params) {
let sendresA = act + md5p;
let sendresB = params
let l = sendresA.length + (sendresB.length / 2)
let buffer = new ArrayBuffer(l)
let dataView = new DataView(buffer)
for (var i = 0; i < sendresA.length; i++) {
dataView.setUint8(i, sendresA.charAt(i).charCodeAt())
}
let mlist = []
for (let index = 0; index < sendresB.length; index++) {
if (index % 2 == 0) {
mlist.push(sendresB.substr(index, 2))
}
}
for (let index = 0; index < mlist.length; index++) {
const element = parseInt(mlist[index], 16);
dataView.setUint8(10 + index, element)
}
return buffer
}
通知characteristicId-notify:转换为ASCII字符串370d120003000310
如果为3700000000000000 表示密码验证错误
断开连接后重新连接生效
写配置28【系统配置】
指令id:28
密钥:认证串+8字符密码(字符串拼接)通过hex_md5加密后toUpperCase().substring(0, 8)
参数:16进制的字符串规则为上述(图二)
写characteristicId-write
// act 指令id
// md5p 密钥
// params 参数
const genValue = function (act, md5p,params) {
let sendresA = act + md5p;
let sendresB = params
let l = sendresA.length + (sendresB.length / 2)
let buffer = new ArrayBuffer(l)
let dataView = new DataView(buffer)
for (var i = 0; i < sendresA.length; i++) {
dataView.setUint8(i, sendresA.charAt(i).charCodeAt())
}
let mlist = []
for (let index = 0; index < sendresB.length; index++) {
if (index % 2 == 0) {
mlist.push(sendresB.substr(index, 2))
}
}
for (let index = 0; index < mlist.length; index++) {
const element = parseInt(mlist[index], 16);
dataView.setUint8(10 + index, element)
}
return buffer
}
通知characteristicId-notify:转换为ASCII字符串380d120003000310
如果为3800000000000000 表示密码验证错误
断开连接后重新连接生效
读取版本29
指令id:29
密钥:认证串+8字符密码(字符串拼接)通过hex_md5加密后toUpperCase().substring(0, 8)
写characteristicId-write
// act 指令
// md5p 密钥
const genValue = function (act, md5p) {
let sendresA = act + md5p;
let l = sendresA.length
let buffer = new ArrayBuffer(l)
let dataView = new DataView(buffer)
for (var i = 0; i < sendresA.length; i++) {
dataView.setUint8(i, sendresA.charAt(i).charCodeAt())
}
return buffer
}
通知characteristicId-notify:转换为ASCII字符串39xxxx0003000310
res.substr(2, 4)
即为版本信息
如果为3900000000000000 表示密码验证错误
长时间开启2a
指令id:2a
密钥:认证串+8字符密码(字符串拼接)通过hex_md5加密后toUpperCase().substring(0, 8)
参数:00000000 [16进制字符串 ]
全0表示长开
最大ffffffff 单位:秒 表示开多长时间
写characteristicId-write
// act 指令id
// md5p 密钥
// params 参数
const genValue = function (act, md5p,params) {
let sendresA = act + md5p;
let sendresB = params
let l = sendresA.length + (sendresB.length / 2)
let buffer = new ArrayBuffer(l)
let dataView = new DataView(buffer)
for (var i = 0; i < sendresA.length; i++) {
dataView.setUint8(i, sendresA.charAt(i).charCodeAt())
}
let mlist = []
for (let index = 0; index < sendresB.length; index++) {
if (index % 2 == 0) {
mlist.push(sendresB.substr(index, 2))
}
}
for (let index = 0; index < mlist.length; index++) {
const element = parseInt(mlist[index], 16);
dataView.setUint8(10 + index, element)
}
return buffer
}
通知characteristicId-notify:转换为ASCII字符串3a0d120003000310
解析规则与21指令一致
关闭2b
指令id:2b
密钥:认证串+8字符密码(字符串拼接)通过hex_md5加密后toUpperCase().substring(0, 8)
写characteristicId-write
// act 指令id
// md5p 密钥
const genValue = function (act, md5p) {
let sendresA = act + md5p;
let sendresB = params
let l = sendresA.length
let buffer = new ArrayBuffer(l)
let dataView = new DataView(buffer)
for (var i = 0; i < sendresA.length; i++) {
dataView.setUint8(i, sendresA.charAt(i).charCodeAt())
}
return buffer
}
通知characteristicId-notify:转换为ASCII字符串3b0d120003000300
解析规则与21指令一致
六.Demo
以下为Uniapp Demo 仅供参考 [uniapp-android-demo.zip](https://www.showdoc.com.cn/server/api/attachment/visitfile/sign/55bb11d576a4632806fa3495ae2074f9 "[uniapp-android-demo.zip")