需求背景
使用微信小程序,通过蓝牙与硬件设备产品进行交互
参考文档
开始
1.初始化蓝牙
initBlue: function () {
var that = this
wx.openBluetoothAdapter({
success: function (res) {
that.findBlue()
},
fail: function (res) {
wx.showToast({
title: '请打开手机蓝牙!',
icon: 'none',
duration: 2000
})
}
})
}
2.查找蓝牙
findBlue() {
var that = this
wx.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false,
interval: 0,
success: function (res) {
that.getBlue()
}
})
},
getBlue() {
var that = this
var searchResult = false
var index = 0
wx.showLoading({
title: '搜索设备...',
})
//定时搜索
var interval = setInterval(function () {
wx.getBluetoothDevices({
success: function (res) {
index = index + 1
if (!searchResult) {
for (var i = 0; i < res.devices.length; i++) {
//根据设备名称匹配 这里的meterId是需要匹配的设备名称
if ((res.devices[i].name + "").substr(0, 16) == that.data.meterId ||
(res.devices[i].localName + "").substr(0, 16) == that.data.meterId) {
that.setData({
//获取蓝牙设备的deviceId
deviceId: res.devices[i].deviceId,
})
searchResult = true
if (searchResult) {
clearInterval(interval)
}
//连接蓝牙
that.connetBlue(res.devices[i].deviceId)
return
}
}
}
if (index > 20) {
clearInterval(interval)
wx.hideLoading()
wx.showToast({
title: '未找到设备,请重试!',
icon: 'none',
duration: 2000
})
wx.stopBluetoothDevicesDiscovery() //关闭蓝牙搜索
}
}
})
}, 500)
}
3.连接蓝牙设备
connetBlue(deviceId) {
var that = this
wx.hideLoading()
wx.showLoading({
title: '连接设备...',
})
wx.createBLEConnection({
deviceId: deviceId,
success: function (res) {
wx.stopBluetoothDevicesDiscovery() //关闭蓝牙搜索
that.getServiceId() //获取服务ID
},
fail: function () {
wx.hideLoading()
wx.showToast({
title: '连接设备失败!',
icon: 'none',
duration: 2000
})
wx.stopBluetoothDevicesDiscovery() //关闭蓝牙搜索
}
})
},
getServiceId() {
var that = this
wx.getBLEDeviceServices({
deviceId: that.data.deviceId,
success: function (res) {
var model = res.services[0]
that.setData({
serviceId: model.uuid
})
that.getCharacteId()
}
})
},
getCharacteId() {
var that = this
wx.getBLEDeviceCharacteristics({
deviceId: that.data.deviceId,
serviceId: that.data.serviceId,
success: function (res) {
for (var i = 0; i < res.characteristics.length; i++) {
var model = res.characteristics[i]
if (model.properties.notify == true) {
that.setData({
notifyId: model.uuid
})
//重点:开启监听服务。监听设备数据变化
that.startNotice(model.uuid)
}
if (model.properties.write == true) {
that.setData({
writeId: model.uuid
})
}
}
//有可写权限
if (that.data.writeId != '') {
wx.hideLoading()
wx.showLoading({
title: '通讯中...',
})
//这里可以完成需要下发到设备上的指令的生成
that.sendCmd(value)
} else {
wx.showToast({
title: '失败: 设备无写入权限!',
icon: 'none',
duration: 2000
})
}
}
})
}
4.发送数据
sendCmd(cmdValue) {
var that = this
if (cmdValue != '' && cmdValue != null && cmdValue != undefined) {
that.writeCharacterToDevice(util.stringToArrayBuffer(cmdValue))
} else {
wx.showToast({
title: '获取设备指令失败',
icon: 'none',
duration: 2000
})
}
}
writeCharacterToDevice(buffer) {
var that = this
wx.writeBLECharacteristicValue({
deviceId: that.data.deviceId,
serviceId: that.data.serviceId,
characteristicId: that.data.writeId,
value: buffer,
fail: function () {
wx.showToast({
title: '写入设备数据失败!',
icon: 'none',
duration: 2000
})
},
success: function () {
wx.showLoading({
title: '指令发送成功',
duration: 2000
})
}
})
}
5.工具函数
function stringToArrayBuffer(str) {
var bytes = new Array();
var len, c;
len = str.length;
for (var i = 0; i < len; i++) {
c = str.charCodeAt(i);
if (c >= 0x010000 && c <= 0x10FFFF) {
bytes.push(((c >> 18) & 0x07) | 0xF0);
bytes.push(((c >> 12) & 0x3F) | 0x80);
bytes.push(((c >> 6) & 0x3F) | 0x80);
bytes.push((c & 0x3F) | 0x80);
} else if (c >= 0x000800 && c <= 0x00FFFF) {
bytes.push(((c >> 12) & 0x0F) | 0xE0);
bytes.push(((c >> 6) & 0x3F) | 0x80);
bytes.push((c & 0x3F) | 0x80);
} else if (c >= 0x000080 && c <= 0x0007FF) {
bytes.push(((c >> 6) & 0x1F) | 0xC0);
bytes.push((c & 0x3F) | 0x80);
} else {
bytes.push(c & 0xFF);
}
}
var array = new Int8Array(bytes.length);
for (var i in bytes) {
array[i] = bytes[i];
}
return array.buffer;
}
function arrayBufferToString(arr) {
if (typeof arr === 'string') {
return arr;
}
var dataview = new DataView(arr);
var ints = new Uint8Array(arr.byteLength);
for (var i = 0; i < ints.length; i++) {
ints[i] = dataview.getUint8(i);
}
arr = ints;
var str = '',
_arr = arr;
for (var i = 0; i < _arr.length; i++) {
var one = _arr[i].toString(2),
v = one.match(/^1+?(?=0)/);
if (v && one.length == 8) {
var bytesLength = v[0].length;
var store = _arr[i].toString(2).slice(7 - bytesLength);
for (var st = 1; st < bytesLength; st++) {
store += _arr[st + i].toString(2).slice(2);
}
str += String.fromCharCode(parseInt(store, 2));
i += bytesLength - 1;
} else {
str += String.fromCharCode(_arr[i]);
}
}
return str;
}
6.开启事件监听
/**
* 监听水表数据变化
* @param {水表ID} uuid
*/
startNotice(uuid) {
var that = this
wx.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
deviceId: that.data.deviceId,
serviceId: that.data.serviceId,
characteristicId: uuid,
success: function (res) {
var deviceResult = ''
//特征数据变化
wx.onBLECharacteristicValueChange(function (res) {
deviceResult = deviceResult + util.arrayBufferToString(res.value) //应答数据比较长,会触发多次
//如果应答帧总长度大于数据包长度,并且包含“16”,则说明是完整的应答帧
if (deviceResult.lastIndexOf('16') >= (deviceResult.length - 8) && deviceResult.indexOf('68') >= 0) {
//解析应答帧 这里开始对设备应答数据进行处理了
deviceResult = ''
}
})
}
})
},
设备应答数据也可以发送到后台服务进行处理,根据具体业务而定