程序功能: 微信小程序连接指定的蓝牙设备,给蓝牙设备发送数据,监听到蓝牙设备回复(需要硬件蓝牙模块处理)的数据后做相应的处理。
实现: 结合硬件设备给蓝牙模块发数据后 能实现控制电机开门动作
小程序和低功耗蓝牙通信数据格式转换的两个函数。
- 给蓝牙设备发送数据
/**
* send 将16进制转ArrayBufer发给设备
*/
function string2buffer(str) {
let val = ""
if (!str) return;
let length = str.length;
let index = 0;
let array = []
while (index < length) {
array.push(str.substring(index, index + 2));
index = index + 2;
}
val = array.join(",");
return new Uint8Array(val.match(/[\da-f]{2}/gi).map(function(h) {
return parseInt(h, 16)
})).buffer
}
- 蓝牙设备回复数据格式,接收后转16进制
/**
* revice ArrayBuffer转16进制字符
*/
function ab2hext(buffer) {
if (buffer == "") {
return "";
}
var hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function(bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('');
}
小程序搜索、连接设备、获取设备数据及开启监听(监听蓝牙回复的数据),该函数写在小程序的新建JS文件中,在index或其他页面可以直接调用函数,使得小程序页面代码简洁。连接过程及逻辑见代码注释。
/**
* 1.0 初始化
*/
function connectBLE() {
wx.openBluetoothAdapter({ // 初始化小程序蓝牙模块 到小程序销毁为止
success: function(res) {
startBluetoothDevicesDiscovery(); // 2.0
},
fail: function(res) {
wx.showToast({
title: '请开启蓝牙',
icon: 'none',
duration: 5000 // 显示5秒
})
}
})
}
/**
* 2.0 搜索特定设备
*/
function startBluetoothDevicesDiscovery() {
wx.showLoading({
title: '正在搜索设备',
})
wx.startBluetoothDevicesDiscovery({
success: function(res) {
console.log("搜索了外围设备:" + res);
wx.onBluetoothDeviceFound(function(res) { // 监听新设备事件
let devices = res.devices;
console.log("监听新设备事件:" + devices);
if (devices != null && devices != "") {
var mac = app.appData.mac; // 特定设备mac(实际为设备在广播中name字段的信息,唯一标识),我定在app.js中方便调用。
wx.setStorageSync('mac', mac)
for (var i = 0; i < devices.length; i++) {
if (devices[i].localName == mac || devices[i].name == mac) {
var deviceId = devices[i].deviceId; // 注意ios搜索的为设备id,不同的ios搜索同一个蓝牙设备的id可能不同。安卓搜索的id为设备mac地址。不可以使用id作为设备唯一标识!
wx.setStorageSync('deviceId', deviceId)
console.log("搜索到目标设备 缓存deviceId" + wx.getStorageSync('deviceId'));
connetBlue(deviceId); // 3.0
}
}
} else {
console.log("监听新设备为空!");
}
})
},
fail(res) {
console.log("搜索外围设备失败!", res);
}
})
}
/**
* 3.0 获取到设备之后连接蓝牙设备
*/
function connetBlue(deviceId) {
wx.hideLoading(); // 隐藏正在搜索提示
wx.showLoading({
title: '正在连接',
})
wx.createBLEConnection({ // 使用设备Id连接设备。
deviceId: wx.getStorageSync('deviceId'),
success: function(res) {
console.log("连接蓝牙成功!")
wx.stopBluetoothDevicesDiscovery({
success: function(res) {
console.log('连接蓝牙成功之后关闭蓝牙搜索!');
}
})
// 该方法回调中可以用于处理连接意外断开等异常情况
wx.onBLEConnectionStateChange(function(res)
console.log('设备:', res.deviceId, ' 连接状态改变, connected:', res.connected)
})
getServiceId() // 5.0
},
fail: function(res) {
console.log("连接失败,错误代码:" + res.errCode + ':' + res.errMsg);
}
})
}
/**
* 5.0 获取serviceId
*/
function getServiceId() {
wx.getBLEDeviceServices({
deviceId: wx.getStorageSync('deviceId'),
success: function(res) {
console.log("获取serviceId成功");
insertDeviceAndbindUser(); // 不绑定服务器的小伙伴可直接调用函数6.0; 调用服务器,绑定设备。将设备唯一标识和小程序用户唯一标识(openId)绑定。openId需要调用接口wx.login API,具体见小程序开发文档:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html
},
fail: function(res) {
wx.hideLoading();
console.log("获取serviceId失败!", res);
}
})
}
/**
* 5.1 将设备mac录入数据库,绑定用户
*/
function insertDeviceAndbindUser() {
wx.request({
url: app.appData.url + '/api/xxxx', // app.js定义服务器ip及端口
method: 'POST',
data: {
openId: openId
mac: app.appData.mac // 调试mac,实际为获取的设备唯一标识
},
header: {
'content-type': 'application/json; charset=UTF-8'
},
success: function(res) {
console.log("设备录入绑定-访问服务器成功!", res);
if (res.data.code == 206) { // 服务器自定义反码
wx.showToast({
title: '设备已被绑定',
icon: 'none',
duration: 4000
})
} else {
wx.showToast({
title: '绑定成功',
})
getCharacteId(); // 6.0
}
},
fail: function(res) {
console.log("用户绑定-服务器返回失败", res);
}
})
}
/**
* 6.0 获取特征值
*/
function getCharacteId() {
wx.getBLEDeviceCharacteristics({
deviceId: wx.getStorageSync('deviceId'),
serviceId: app.appData.serviceId,
success: function(res) {
console.log("获取特征值成功");
startNotice() //7.0
},
fail: function(res) {
console.log("获取特征值失败!", res);
}
})
}
/**
* 7.0 发送指令与监听数据
*/
function startNotice() {
//第一步 开启监听 notityid 第二步发送指令 write
wx.notifyBLECharacteristicValueChange({
state: true,
deviceId: wx.getStorageSync('deviceId'),
serviceId: app.appData.serviceId,
characteristicId: app.appData.notifyUUID,
success: function(res) {
console.log("监听成功");
sendData('1'); // 发送数据
wx.hideLoading();
// 此时可以拿到蓝牙设备返回来的数据是一个ArrayBuffer类型数据,所以需要通过一个方法转换成字符串
wx.onBLECharacteristicValueChange(function(res) {
console.log("监听设备回应:", res.value);
var nonceId = ab2hext(res.value);
console.log("设备回应:", nonceId); // 开门: ffff000404170120
// 回应标志位
var nonceFlag = nonceId.substring(8, 10);
if (nonceFlag === '04') {
wx.showToast({
title: '开箱成功',
})
}
analysisRevice(nonceId); // 9.0
setTimeout(function() {
wx.switchTab({
url: '../index/index'
});
}, 500) //延迟时间 这里是0.5秒
})
},
fail: function(res) {
console.log("监听开启失败:", res);
}
})
}
/**
* 8.0 写入数据,指令代号与数值
*/
function sendData(code) {
wx.request({
url: app.appData.url + '/api/xxxxxx',
method: 'POST',
data: {
num: code,
val: ""
},
header: {
'content-type': 'application/json; charset=UTF-8'
},
success: function(res) {
console.log("服务器访问成功", res);
var serverResData = res.data;
console.log("serverResData:", serverResData);
var buffer = string2buffer(serverResData);
wx.writeBLECharacteristicValue({
deviceId: wx.getStorageSync('deviceId'),
serviceId: app.appData.serviceId,
characteristicId: app.appData.writeUUID,
value: buffer, // 这里的value是ArrayBuffer类型
success: function(res) {
console.log("写入成功");
},
fail: function() {
console.log("写入失败,从新连接");
wx.showToast({
title: '设备已断开,正在重新连接...',
icon: 'none'
})
ReConnetBlue();
console.log("从新连接...");
}
})
},
fail: function(res) {
console.log("服务器访问失败", res);
}
})
}
/**
* 9.0 拿到设备返回的值后,去后台请求处理逻辑关系
*/
function analysisRevice(nonceId) {
wx.request({
url: app.appData.url + '/api/xxxxx',
method: 'POST',
data: {
mac: app.appData.mac,
hex: nonceId,
},
header: {
'content-type': 'application/json; charset=UTF-8'
},
success: function(res) {
console.log("解析数据-访问服务器成功", res);
var resultRes = res.data;
},
fail: function(res) {
console.log("解析数据-服务器返回openId失败", res);
}
})
}
连接成功和用户绑定后,如果需要删除设备需要关闭蓝牙适配器,才能重新搜索到当前的设备。
function closeBluetoothAdapter() {
wx.closeBluetoothAdapter({
success(res) {
console.log('关闭成功!', res)
},
fail: function() {
console.log('关闭失败!', res)
}
})
}
第一次写小程序控制低功耗蓝牙设备,欢迎大家一起讨论。