在开发当中需要去和硬件交互,需要蓝牙去发送命令,发现蓝牙交互还是需要挺多的歪歪绕绕的,记录一下:
首先在微信小程序里我们需要几个变量:
const BluetoothDetail = {
inputValue: '',//想要链接的蓝牙设备id
deviceId: '',//设备ID
services: '',//蓝牙设备的uuid
notify: '',//支持notify的特征值
write: '',//支持write的特征值
returnValue:'',//返回的token
returnValue2:''//开锁后的返回
}
虽然在上面的几个值都是相同的但是微信还是让我们区分开来。
1.判断蓝牙是否打开
//1. 判断用户手机蓝牙是否打开
wx.openBluetoothAdapter({//调用微信小程序api 打开蓝牙适配器接口
success: function (res) {
wx.showToast({
title: '初始化成功',
icon: 'success',
duration: 800
})
},
fail: function (res) {//如果手机上的蓝牙没有打开,可以提醒用户
wx.showToast({
title: '请开启蓝牙',
icon: 'fails',
duration: 1000
})
}
})
2.搜索附近的蓝牙设备
//2.搜索附近蓝牙设备
wx.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false,
interval: 0,
success: function (res) {
wx.showLoading({
title: '正在搜索设备',
})
}
})
3.获取蓝牙信息
这里我们获取的蓝牙设备是集合,多个的,所以我们需要变量获取我们想要获取的那个蓝牙的id名称
//3.获取蓝牙设备信息
wx.getBluetoothDevices({
success: function (res) {
wx.hideLoading();
if (res.devices.length>0){
for (var i = 0; i < res.devices.length; i++) {
console.log(res.devices[i])
if (res.devices[i].deviceId == BluetoothDetail.inputValue ||
res.devices[i].localName == BluetoothDetail.inputValue) {
BluetoothDetail.deviceId = res.devices[i].deviceId
//进行连接的调用
break
}
if (res.devices.length-1==i){
//搜索附近蓝牙的回调
}
}
}else{
//搜索附近蓝牙的回调
}
},
fail: function () {
console.log("搜索蓝牙设备失败")
}
})
}
4.开始建立与蓝牙设备链接
//4.通过蓝牙设备的id进行蓝牙连接
wx.createBLEConnection({
deviceId: BluetoothDetail.deviceId,//设备id
success: function (res) {
wx.showToast({
title: '连接成功',
icon: 'fails',
duration: 800
})
wx.stopBluetoothDevicesDiscovery({
success: function (res) {
console.log('连接蓝牙成功之后关闭蓝牙搜索')
}
})
//获取服务uuid
}
})
5.获取服务的UUID
//5.获取服务的uuid
wx.getBLEDeviceServices({
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId: BluetoothDetail.deviceId,
success: function (res) {
var model = res.services[0]
BluetoothDetail.services=model.uuid
console.log("services: " + BluetoothDetail.services);
//判断蓝牙值的特性值
}
})
6.判断蓝牙设备的特性值
wx.getBLEDeviceCharacteristics({
deviceId: BluetoothDetail.deviceId,
serviceId: BluetoothDetail.services,
success: function (res) {
for (var i = 0; i < res.characteristics.length; i++) {//2个值
var model = res.characteristics[i]
if (model.properties.notify == true) {
BluetoothDetail.notifyId= model.uuid//监听的值
console.log("notifyId: " + BluetoothDetail.notifyId)
//notify
}
if (model.properties.write == true) {
BluetoothDetail.writeId=model.uuid//用来写入的值
console.log("writeId: " + BluetoothDetail.writeId)
}
}
}
})
7.启用 notify 功能,只有启用该功能才能进行读写、获取信息等操作。
wx.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
deviceId: BluetoothDetail.deviceId,
serviceId: BluetoothDetail.services,
characteristicId: BluetoothDetail.notifyId, //第一步 开启监听 notityid 第二步发送指令 write
success: function (res) {
var str1 = 'CAFB4AC988966A676339FE490705B1F9'
sendMy(string2buffer(str1))
}
})
8.向设备写入数据
// 8.写入蓝牙设备 内容
wx.writeBLECharacteristicValue({
deviceId: BluetoothDetail.deviceId,
serviceId: BluetoothDetail.services,
characteristicId: BluetoothDetail.writeId,//第二步写入的特征值
value: buffer,
success: function (res) {
console.log("写入成功")
wx.onBLECharacteristicValueChange(function (characteristic) {//回调用来接收蓝牙设备返回的信息,需要转为字符串
BluetoothDetail.returnValue=ab2hex(characteristic.value)//用来写入的值
console.log("returnValue: "+BluetoothDetail.returnValue)
})
},
fail: function () {
console.log('写入失败')
},
})
工具方法
这里微信小程序和蓝牙设备的交互需要进行加密解密, 发送需要进行ArrayBufer,接收需要转为字符串,所以需要下面两个工具方法进行转换
// 将字符串转换成ArrayBufer
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(",");
// 将16进制转化为ArrayBuffer
return new Uint8Array(val.match(/[\da-f]{2}/gi).map(function (h) {
return parseInt(h, 16)
})).buffer
},
/**
* 将ArrayBuffer转换成字符串
*/
ab2hex(buffer) {
var hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function (bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('');
},
后续还有几个交互的方法:
蓝牙连接断开
wx.closeBLEConnection({
deviceld: deviceld,
complete: function (res) {
//断开连接后一些参数逻辑的处理
}
wx.showToast({
ititle: '蓝牙连接断开',
icon: 'success',
duration: 2000})
})
释放蓝牙适配器
wx.closeBluetoothAdapter( {
success: function (res) {
//一些释放后的逻辑
wx.showToast({
title: '蓝牙适配器释放',
icon: 'success',
duration: 2000
})
}
fail: function (res) {।}
})
一般我蓝牙放在utlis下的一个js文件里:
const util = require('util.js')
const BluetoothDetail = {
inputValue: '',//想要链接的蓝牙设备id
deviceId: '',//设备ID
services: '',//蓝牙设备的uuid
notify: '',//支持notify的特征值
write: '',//支持write的特征值
returnValue:'',//返回的token
returnValue2:''//开锁后的返回
}
// 1.判断用户手机蓝牙是否打开
const bluetooth = inputValue => {
BluetoothDetail.inputValue=inputValue
wx.openBluetoothAdapter({//调用微信小程序api 打开蓝牙适配器接口
success: function (res) {
wx.showToast({
title: '初始化成功',
icon: 'success',
duration: 800
})
findBlue();//2.0
},
fail: function (res) {//如果手机上的蓝牙没有打开,可以提醒用户
wx.showToast({
title: '请开启蓝牙',
icon: 'fails',
duration: 1000
})
}
})
}
//2.搜索附近蓝牙设备
const findBlue = () => {
wx.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false,
interval: 0,
success: function (res) {
wx.showLoading({
title: '正在搜索设备',
})
getBlue()//3.0
}
})
}
//3.获取蓝牙设备信息
const getBlue = () => {
console.log("getBlue")
wx.getBluetoothDevices({
success: function (res) {
wx.hideLoading();
if (res.devices.length>0){
for (var i = 0; i < res.devices.length; i++) {
console.log(res.devices[i])
if (res.devices[i].deviceId == BluetoothDetail.inputValue ||
res.devices[i].localName == BluetoothDetail.inputValue) {
BluetoothDetail.deviceId = res.devices[i].deviceId
connetBlue();//4.0
break
}
if (res.devices.length-1==i){
findBlue()
}
}
}else{
findBlue()
}
},
fail: function () {
console.log("搜索蓝牙设备失败")
}
})
}
//4.通过蓝牙设备的id进行蓝牙连接
const connetBlue = () => {
wx.createBLEConnection({
deviceId: BluetoothDetail.deviceId,//设备id
success: function (res) {
wx.showToast({
title: '连接成功',
icon: 'fails',
duration: 800
})
wx.stopBluetoothDevicesDiscovery({
success: function (res) {
console.log('连接蓝牙成功之后关闭蓝牙搜索')
}
})
getServiceId()//5.0
}
})
}
//5.获取服务的uuid
const getServiceId = () => {
wx.getBLEDeviceServices({
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId: BluetoothDetail.deviceId,
success: function (res) {
var model = res.services[0]
BluetoothDetail.services=model.uuid
console.log("services: " + BluetoothDetail.services);
getCharacteId()//6.0
}
})
}
//6.判断蓝牙设备的特性值
const getCharacteId = () => {
wx.getBLEDeviceCharacteristics({
deviceId: BluetoothDetail.deviceId,
serviceId: BluetoothDetail.services,
success: function (res) {
for (var i = 0; i < res.characteristics.length; i++) {//2个值
var model = res.characteristics[i]
if (model.properties.notify == true) {
BluetoothDetail.notifyId= model.uuid//监听的值
console.log("notifyId: " + BluetoothDetail.notifyId)
startNotice(BluetoothDetail.notifyId)//7.0
}
if (model.properties.write == true) {
BluetoothDetail.writeId=model.uuid//用来写入的值
console.log("writeId: " + BluetoothDetail.writeId)
}
}
}
})
}
//7.notify
const startNotice = uuid => {
wx.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
deviceId: BluetoothDetail.deviceId,
serviceId: BluetoothDetail.services,
characteristicId: uuid, //第一步 开启监听 notityid 第二步发送指令 write
success: function (res) {
var str1 = 'CAFB4AC988966A6aasf0705B1F9' //想写入的16进制的16位的字符串
sendMy(string2buffer(str1))
}
})
}
// 8.写入蓝牙设备 内容获取token
const sendMy = buffer => {
wx.writeBLECharacteristicValue({
deviceId: BluetoothDetail.deviceId,
serviceId: BluetoothDetail.services,
characteristicId: BluetoothDetail.writeId,//第二步写入的特征值
value: buffer,
success: function (res) {
console.log("写入成功")
wx.onBLECharacteristicValueChange(function (characteristic) {
BluetoothDetail.returnValue=ab2hex(characteristic.value)//用来写入的值
console.log("returnValue: "+BluetoothDetail.returnValue)
var param = {
str: BluetoothDetail.returnValue
}
mutaul(param)
})
},
fail: function () {
console.log('写入失败')
},
})
}
// 与后端交互获取密码
const mutaul = param => {
util.postJson({
url: 'http://192.168.0.105:8089/api/device/encrypt',
data: { ...param },
success: function (resp) {
console.log("发送给后端成功")
pwd(string2buffer(resp.msg))
},
fail: function () {
console.log('发送给后端失败')
},
})
}
// 密码发送
const pwd = buffer => {
wx.writeBLECharacteristicValue({
deviceId: BluetoothDetail.deviceId,
serviceId: BluetoothDetail.services,
characteristicId: BluetoothDetail.writeId,//第二步写入的特征值
value: buffer,
success: function (res) {
console.log("写入成功")
wx.onBLECharacteristicValueChange(function (characteristic) {
BluetoothDetail.returnValue2=ab2hex(characteristic.value)//用来写入的值
console.log("returnValue2: "+BluetoothDetail.returnValue2)
})
},
fail: function () {
console.log('写入失败')
},
})
}
// 将字符串转换成ArrayBufer
const 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(",");
// 将16进制转化为ArrayBuffer
return new Uint8Array(val.match(/[\da-f]{2}/gi).map(function (h) {
return parseInt(h, 16)
})).buffer
}
const ab2hex = buffer => {
var hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function (bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('');
}
module.exports = {
bluetooth: bluetooth
};