小程序与蓝牙设备通讯,总结一下分为下面几点:
1.小程序初始化蓝牙模块
2.搜索设备
3.连接设备 获取蓝牙的所有服务以及服务对应的特征值,根据特征值进行读写和监听设备的数据返回
4. 写入数据
5. 读取蓝牙设备返回数据
下面我们看具体的实现步骤
初始化蓝牙模块
//初始化蓝牙
openBluetoothAdapter() {
var that = this;
//初始化蓝牙模块
wx.openBluetoothAdapter({
success: (res) => {
console.log('openBluetoothAdapter success', res)
that.startBluetoothDevicesDiscovery()
},
fail: (res) => {
console.log(res);
if (res.errCode === 10001) {
wx.onBluetoothAdapterStateChange(function (res) {
console.log('onBluetoothAdapterStateChange', res)
if (res.available) {
that.startBluetoothDevicesDiscovery()
}
})
}
}
})
},
搜索蓝牙设备
//开始搜寻附近的蓝牙外围设备
startBluetoothDevicesDiscovery() {
var that = this;
if (that._discoveryStarted) {
return
}
that._discoveryStarted = true
wx.startBluetoothDevicesDiscovery({
allowDuplicatesKey: true,
success: (res) => {
console.log('startBluetoothDevicesDiscovery success', res)
that.onBluetoothDeviceFound()
},
})
},
//停止搜寻附近的蓝牙外围设备
stopBluetoothDevicesDiscovery() {
wx.stopBluetoothDevicesDiscovery()
},
//监听寻找到新设备的事件
onBluetoothDeviceFound() {
var that = this;
wx.onBluetoothDeviceFound((res) => {
res.devices.forEach(device => {
console.log(device);
if (!device.name && !device.localName) {
return
}
const foundDevices = that.data.devices
const idx = inArray(foundDevices, 'deviceId', device.deviceId)
const data = {}
if (idx === -1) {
data[`devices[${foundDevices.length}]`] = device
} else {
data[`devices[${idx}]`] = device
}
that.setData(data)
})
})
},
连接对应的蓝牙设备,这一步可以手动去连接,也可以根据你获取到的设备列表,找到你对应的设备deviceId,主动去连接
//连接低功耗蓝牙设备
createBLEConnection(e) {
var that = this;
const ds = e.currentTarget.dataset
const deviceId = ds.deviceId
const name = ds.name
wx.createBLEConnection({
deviceId,
success: (res) => {
that.setData({
connected: true,
name,
deviceId,
})
that.getBLEDeviceServices(deviceId)
}
})
that.stopBluetoothDevicesDiscovery()
},
获取连接蓝牙设备的所有服务,然后找出isPrimary为true的服务,将这个服务的uuid记录下来,去为下一步获取服务的特征值做准备
//获取蓝牙设备所有服务(service)。
getBLEDeviceServices(deviceId) {
var that = this;
wx.getBLEDeviceServices({
deviceId,
success: (res) => {
//获取设备服务中isPrimary为true的服务
for (let i = 0; i < res.services.length; i++) {
if (res.services[i].isPrimary) {
//获取这个服务的特征值
that.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid)
return
}
}
},
fail(res) {
console.error('22', res)
}
})
},
获取到所需服务的所有特征值支持的操作类型,具体这些操作类型的支持情况要去跟硬件的情况去核实
我们经常用到的就是一个write 是否允许写入,如果允许,我们就可以通过 wx.writeBLECharacteristicValue 进行写入数据
本次测试的设备是通过notify 来接收设备返回的数据,所以我们notify为true的情况下我们就会去监听设备的数据返回,这一步要注意的就是
调用 wx.onBLECharacteristicValueChange
//获取蓝牙设备某个服务中所有特征值(characteristic)。
getBLEDeviceCharacteristics(deviceId, serviceId) {
var that = this;
wx.getBLEDeviceCharacteristics({
deviceId,
serviceId,
success: (res) => {
for (let i = 0; i < res.characteristics.length; i++) {
let item = res.characteristics[i]
if (item.properties.read) {
wx.readBLECharacteristicValue({ //读取低功耗蓝牙设备的特征值的二进制数据值
deviceId,
serviceId,
characteristicId: item.uuid,
})
}
if (item.properties.write) { //写入低功耗蓝牙设备的特征值的二进制数据值
that.setData({
canWrite: true,
writeDeviceId: deviceId,
writeServiceId: serviceId,
writeCharacteristicId: item.uuid
})
}
if (item.properties.notify || item.properties.indicate) {
wx.notifyBLECharacteristicValueChange({ //启用低功耗蓝牙设备特征值变化时的 notify 功能
deviceId,
serviceId,
characteristicId: item.uuid,
state: true,
success(res) {
console.log('notifyBLECharacteristicValueChange success', res);
// 操作之前先监听,保证第一时间获取数据
wx.onBLECharacteristicValueChange((characteristic) => {
//处理蓝牙返回的数据
that.parseReturnData(characteristic.value);
})
}
})
}
}
},
fail(res) {
console.error('getBLEDeviceCharacteristics', res)
}
})
},
小程序是建议单包数据不超过20字节,所以当数据量大的时候就需要进行分包写入,要注意的一点就是分包发送的时候需要一个间隔时间,如果没有间隔时间,有的设备可能就会接收不到
//分包写入蓝牙
writeBLECharacteristicValue(buffer) {
let pos = 0;
let bytes = buffer.byteLength;
var that = this;
let ArrayBuffer = buffer.buffer;
console.log("bytes", bytes)
while (bytes > 0) {
let tmpBuffer;
if (bytes > 20) {
tmpBuffer = ArrayBuffer.slice(pos, pos + 20);
pos += 20;
bytes -= 20;
wx.writeBLECharacteristicValue({
deviceId: that.data.writeDeviceId,
serviceId: that.data.writeServiceId,
characteristicId: that.data.writeCharacteristicId,
value: tmpBuffer,
success(res) {
console.log('第一次发送', res)
},
fail: function (res) {
if (res.errCode == '10006') {
that.clearConnectData(); //当前连接已断开,清空连接数据
}
console.log('发送失败', res)
}
})
// })
sleep(0.02)
} else {
tmpBuffer = ArrayBuffer.slice(pos, pos + bytes);
pos += bytes;
bytes -= bytes;
wx.writeBLECharacteristicValue({
deviceId: that.data.writeDeviceId,
serviceId: that.data.writeServiceId,
characteristicId: that.data.writeCharacteristicId,
value: tmpBuffer,
success(res) {
console.log('第二次发送', res)
},
fail: function (res) {
if (res.errCode == '10006') {
that.clearConnectData(); //清空连接数据
console.log('当前连接已断开');
}
console.log('发送失败', res)
}
})
sleep(0.02)
}
}
},
另外一块就是针对我们接受设备的数据进行组包的一个过程
//拼接硬件返回的分包数据
parseReturnData(buf) {
var that = this;
var buf = new Int8Array(buf);
//校验是不是首条包
var isFirstPackage = checkCode(buf);
var singleBag = Array.from(buf);
if (isFirstPackage) { //
that.data.cmd = singleBag[0];
that.data.statusCode = singleBag[1];
that.data.datalength = singleBag[2];
if (that.data.datalength == 0) { //数据长度为0,说明没有数据
that.data.checkSums = singleBag[singleBag.length - 1];
}
if (that.data.datalength > 0 && that.data.datalength <= 16) { //数据长度大于0,说明没有数据
that.data.checkSums = singleBag[singleBag.length - 1];
that.data.packData = singleBag.splice(3, singleBag.length - 4);
that.data.datalength = 0;
}
if (that.data.datalength > 17) { //数据长度大于17,说明数据分包了
that.data.packData = singleBag.splice(3, singleBag.length - 3);
that.data.datalength -= 17; //数据长度减17
}
} else {
if (that.data.datalength > 0) {
if (that.data.datalength <= 19) {
if (that.data.datalength == singleBag.length - 1) { //判断数据剩余长度与当前包的数据长度是否一致
that.data.checkSums = singleBag[singleBag.length - 1];
that.data.packData = that.data.packData.concat(singleBag.splice(0, singleBag.length - 1));
that.data.datalength = 0;
} else {
that.data.datalength = that.data.datalength - singleBag.length;
that.data.packData = that.data.packData.concat(singleBag.splice(0, singleBag.length));
}
} else {
that.data.datalength -= singleBag.length; //数据长度减17
that.data.packData = that.data.packData.concat(singleBag);
}
}
}
if (that.data.datalength == 0) {
var data = ab2str(that.data.packData);
console.log('返回值解析后:' + data);
//把收到的数据解析出来展示在页面,方便测试
that.showLog(that.data.cmd, that.data.statusCode, that.data.packData, that.data.checkSums);
that.setData({
packData: [], // 分包数据
cmd: null, // 命令码
statusCode: null, // 状态码
datalength: null, // 数据长度
checkSums: null, // 校验和
})
}
},
这样基本的通过小程序与蓝牙设备的数据传输就完成了,源码详见https://github.com/sunwanwan/MiniProgram_Bluetooth