一、創建 bluetoothUtil.js 工具文件
二、藍牙連接代碼如下
const util = require('util.js')
//初始化藍牙模塊。iOS 上開啓主機/叢機模式時需分別調用。
const openBluetoothAdapter = (mac) => {
wx.showLoading({
title: '藍牙連接中',
})
var timeOut = setTimeout(function () {
wx.hideLoading()
wx.showToast({
title: '藍牙連接超時',
icon: 'none',
duration: 3000
})
}, 60000)
let promise = new Promise((resolve, reject) => {
wx.openBluetoothAdapter({
success: (res) => {
console.log('openBluetoothAdapter success', res)
setTimeout(function () {
startBluetoothDevicesDiscovery().then(
success => {
var device = wx.getStorageSync('device')
if (mac) {
setTimeout(function () {
onBluetoothDeviceFound(mac).then(
success => {
wx.hideLoading()
clearTimeout(timeOut)
resolve()
}, fail => {
clearTimeout(timeOut)
reject()
}
)
}, 500)
} else if (device) {
createBLEConnection(device).then(
success => {
wx.hideLoading()
wx.showToast({
title: '連接成功',
duration: 2000
})
clearTimeout(timeOut)
resolve()
},
fail => {
wx.hideLoading()
console.log('藍牙連接失敗:' + JSON.stringify(fail))
wx.showToast({
title: '連接失敗',
icon: 'none',
duration: 2000
})
clearTimeout(timeOut)
reject()
}
)
} else {
wx.hideLoading()
clearTimeout(timeOut)
resolve()
}
},
fail => {
wx.hideLoading()
clearTimeout(timeOut)
reject()
}
)
}, 500)
},
fail: (res) => {
wx.hideLoading()
clearTimeout(timeOut)
reject()
}
})
})
return promise;
}
//開始搜尋附近的藍牙外圍設備。此操作比較耗費系統資源,請在搜索並連接到設備後調用 wx.stopBluetoothDevicesDiscovery 方法停止搜索
const startBluetoothDevicesDiscovery = () => {
let promise = new Promise((resolve, reject) => {
wx.startBluetoothDevicesDiscovery({
allowDuplicatesKey: true,
success: (res) => {
resolve()
},
fail: (res) => {
console.log("開始收搜藍牙失敗:" + JSON.stringify(res))
reject()
}
})
})
return promise;
}
//停止搜尋附近的藍牙外圍設備。若已經找到需要的藍牙設備並不需要繼續搜索時,建議調用該接口停止藍牙搜索
const stopBluetoothDevicesDiscovery = () => {
wx.stopBluetoothDevicesDiscovery({
success: () => {
console.log('停止收搜藍牙成功')
},
fail: () => {
console.log('停止收搜藍牙失敗')
}
})
}
//監聽收搜到的藍牙設備
const onBluetoothDeviceFound = (mac) => {
//是否在連接
var canConnection = false;
let promise = new Promise((resolve, reject) => {
wx.onBluetoothDeviceFound((res) => {
res.devices.forEach(device => {
if (!device.deviceId) {
return
}
if (!device.name && !device.localName) {
return
}
if (!device.advertisServiceUUIDs || device.advertisServiceUUIDs.length == 0) {
return
}
var advertisData = util.ab2hex(device.advertisData);
var MAC = advertisData.substring(4, 16)
if (!canConnection && MAC.replace(/:/g, "").toUpperCase() == mac.replace(/:/g, "").toUpperCase()) {
canConnection = true
device.manuId = advertisData.substring(0, 4)
device.advertisData = advertisData
device.serviceId = device.advertisServiceUUIDs[0]
wx.setStorageSync('device', device)
createBLEConnection(device).then(
success => {
console.log('藍牙連接成功')
wx.showToast({
title: '連接成功',
duration: 2000
})
resolve()
},
fail => {
console.log('藍牙連接失敗:' + fail)
wx.showToast({
title: '連接失敗',
icon: 'none',
duration: 2000
})
reject()
}
)
}
})
})
})
return promise;
}
//連接低功耗藍牙設備。
//若小程序在之前已有搜索過某個藍牙設備,併成功建立連接,可直接傳入之前搜索獲取的 deviceId 直接嘗試連接該設備,無需進行搜索操作
const createBLEConnection = (device) => {
stopBluetoothDevicesDiscovery()
//判斷是否開啓藍牙綁定
var advertisData = device.advertisData;
let promise = new Promise((resolve, reject) => {
if (wx.getStorageSync('bluetoothStatus') != 1) {
wx.onBLEConnectionStateChange(function (res) {
if (res.connected) {
wx.setStorageSync('bluetoothStatus', 1)
} else {
wx.showToast({
title: '藍牙已斷開',
icon: 'none'
})
closeBluetoothAdapter()
console.log("藍牙斷開:" + JSON.stringify(res))
wx.setStorageSync('bluetoothStatus', 0)
hintOpenBluetooth()
}
})
const deviceId = device.deviceId
wx.createBLEConnection({
deviceId,
success: (res) => {
device.blueBrdInfo = advertisData.toUpperCase().substring(4, advertisData.length - 4)
device.MAC = advertisData.substring(4, 16)
var sv_1 = util.sixToInt(advertisData.substring(18, 20));
var sv_2 = util.sixToInt(advertisData.substring(20, 22)) < 10 ? "0" + util.sixToInt(advertisData.substring(20, 22)) : util.sixToInt(advertisData.substring(20, 22));
var hv_1 = util.sixToInt(advertisData.substring(22, 24));
var hv_2 = util.sixToInt(advertisData.substring(24, 26)) < 10 ? "0" + util.sixToInt(advertisData.substring(24, 26)) : util.sixToInt(advertisData.substring(24, 26));
device.softwareVersion = sv_1 + "." + sv_2
device.hardwareVersion = hv_1 + "." + hv_2
wx.setStorageSync('device', device)
setTimeout(function () {
getBLEDeviceServices(device).then(
success => {
console.log('查詢所有服務成功')
resolve()
},
fail => {
console.log('查詢所有服務失敗:' + JSON.stringify(fail))
reject()
}
)
}, 500)
},
fail: (res) => {
console.log('創建連接失敗:' + JSON.stringify(res))
reject(res)
},
complete: () => {
console.log('創建連接完成')
}
})
}
})
return promise;
}
//關閉藍牙模塊。調用該方法將斷開所有已建立的連接並釋放系統資源。建議在使用藍牙流程後,與 wx.openBluetoothAdapter 成對調用。
const closeBluetoothAdapter = () => {
wx.closeBluetoothAdapter()
}
//斷開 當前連接的藍牙設備
const closeBLEConnection = () => {
var device = wx.getStorageSync('device')
if (device) {
wx.closeBLEConnection({
deviceId: device.deviceId,
success() {
console.log('斷開當前連接的藍牙設備成功')
},
fail() {
console.log('斷開當前連接的藍牙設備失敗')
}
})
}
closeBluetoothAdapter()
}
//刪除連接過的藍牙數據
const deleteBLEConnectionData = () => {
wx.removeStorageSync('device')
wx.removeStorageSync('characteristics')
wx.removeStorageSync('bluetoothStatus')
}
//獲取藍牙設備所有服務(service)
const getBLEDeviceServices = (device) => {
let promise = new Promise((resolve, reject) => {
var deviceId = device.deviceId
wx.getBLEDeviceServices({
deviceId,
success: (res) => {
console.log('所有服務:', res.services)
var serviceId = res.services[0].uuid
device.serviceId = serviceId
wx.setStorageSync('device', device)
getBLEDeviceCharacteristics(device, serviceId).then(
success => {
console.log('查詢特徵值成功')
resolve()
},
fail => {
console.log('查詢特徵值失敗:' + JSON.stringify(fail))
reject()
}
)
},
fail(res) {
console.log('查詢特徵值失敗:' + JSON.stringify(res))
reject()
},
complete() {
console.log('查詢特徵值完成')
}
})
})
return promise
}
//獲取藍牙設備某個服務中所有特徵值(characteristic)
const getBLEDeviceCharacteristics = (device, serviceId) => {
let promise = new Promise((resolve, reject) => {
var deviceId = device.deviceId
wx.getBLEDeviceCharacteristics({
deviceId,
serviceId,
success: (res) => {
console.log('getBLEDeviceCharacteristics success', res.characteristics)
var list = {}
for (let i = 0; i < res.characteristics.length; i++) {
let item = res.characteristics[i]
if (item.properties.notify || item.properties.indicate) {
var matchList = wx.getStorageSync('matchList')
var personType = wx.getStorageSync('personType')
if (personType == 2 && !(matchList.indexOf(device.MAC) > -1)) {
if (item.uuid.indexOf('FF0B') > -1) {
notifyBLECharacteristic(deviceId, serviceId, item.uuid)
}
} else {
notifyBLECharacteristic(deviceId, serviceId, item.uuid)
}
}
if (item.uuid.indexOf('FF01') > -1) {
list.FF01 = item.uuid
}
if (item.uuid.indexOf('FF02') > -1) {
list.FF02 = item.uuid
}
if (item.uuid.indexOf('FF03') > -1) {
list.FF03 = item.uuid
}
if (item.uuid.indexOf('FF04') > -1) {
list.FF04 = item.uuid
}
if (item.uuid.indexOf('FF05') > -1) {
list.FF05 = item.uuid
}
if (item.uuid.indexOf('FF06') > -1) {
list.FF06 = item.uuid
}
if (item.uuid.indexOf('FF07') > -1) {
list.FF07 = item.uuid
}
if (item.uuid.indexOf('FF08') > -1) {
list.FF08 = item.uuid
}
if (item.uuid.indexOf('FF09') > -1) {
list.FF09 = item.uuid
}
if (item.uuid.indexOf('FF0B') > -1) {
list.FF0B = item.uuid
}
}
wx.setStorageSync('characteristics', list)
resolve()
},
fail(res) {
reject()
console.log('getBLEDeviceCharacteristics', res)
}
})
})
return promise
}
/**啓動notify功能 */
const notifyBLECharacteristic = (deviceId, serviceId, characteristicId) => {
let promise = new Promise((resolve, reject) => {
wx.notifyBLECharacteristicValueChange({
deviceId,
serviceId,
characteristicId: characteristicId,
state: true,
success(res) {
console.log('啓用notify功能成功:' + characteristicId)
resolve()
},
fail(res) {
console.log('啓用notify功能失敗:' + JSON.stringify(res))
reject()
}
})
})
return promise
}
var sendCurrentIndex = 0;
/**
* 發送數據
* data:16進制數據
* deviceId:設備ID
* serviceId:服務ID
* characteristicId:特徵值ID
*/
const sendBluetoothData = (data, deviceId, serviceId, characteristicId) => {
sendCurrentIndex = 0
var list = []
for (var i = 0; i < data.length; i += 2) {
var it = data.substr(i, 2)
list.push(it)
}
var total = list.length
console.log("包的總長" + total)
subpackage(0, total, list, deviceId, serviceId, characteristicId)
}
/**
* 分包
* index: 當前發送的第幾個包
* list: 按照2個字符存在的數據數組
* deviceId:設備ID
* serviceId:服務ID
* characteristicId:特徵值ID
*/
const subpackage = (index, totle, list, deviceId, serviceId, characteristicId) => {
var maxLenght = 20
var maxIndex = Math.ceil(totle / maxLenght)
if (index < maxIndex - 1) {
//分包發送
var subBuffer = new ArrayBuffer(maxLenght)
var subDataView = new DataView(subBuffer)
for (var i = 0; i < maxLenght; i++) {
var item = list[i + index * maxLenght]
var itemF = util.sixToInt(item.substr(0, 1)) * 16
var itemS = util.sixToInt(item.substr(1, 1))
var itemInt = itemF + itemS
subDataView.setUint8(i, itemInt)
}
var dataStr = util.ab2hex(subBuffer)
console.log("subBuffer:" + dataStr)
sendBlueData(subBuffer, false, index, totle, list, deviceId, serviceId, characteristicId)
} else if (index == maxIndex - 1) {
//不需要分包發送
var count = totle - (parseInt(totle / maxLenght)) * maxLenght
let subbBuffer = new ArrayBuffer(count)
let subbDataView = new DataView(subbBuffer)
for (var i = 0; i < count; i++) {
var item = list[i + (parseInt(totle / maxLenght)) * maxLenght]
var itemF = util.sixToInt(item.substr(0, 1)) * 16
var itemS = util.sixToInt(item.substr(1, 1))
var itemInt = itemF + itemS
subbDataView.setUint8(i, itemInt)
}
var dataStr = util.ab2hex(subbBuffer)
console.log("subBuffer++++:" + dataStr) //發送數據
sendBlueData(subbBuffer, true, index, totle, list, deviceId, serviceId, characteristicId)
}
}
/**
* 向藍牙設備發送數據
* buffer:發送的二進制數據
* isLast:是否爲最後一個包,不是則繼續發送
* index:表示當前的第幾個包
* totle:list 數組的長度
* list:按照2個字符存在的數據數組
* deviceId:設備ID
* serviceId:服務ID
* characteristicId:特徵值ID
*/
const sendBlueData = (buffer, isLast, index, totle, list, deviceId, serviceId, characteristicId) => {
wx.writeBLECharacteristicValue({
deviceId: deviceId,
serviceId: serviceId,
characteristicId: characteristicId,
value: buffer,
success: function (res) {
console.log("發送發包數據成功" + JSON.stringify(res))
if (!isLast) {
sendCurrentIndex = index + 1
subpackage(sendCurrentIndex, totle, list, deviceId, serviceId, characteristicId)
} else {
console.log("數據指令發送成功")
// 當最後一個包的數據發送到門鎖裏面去了,那麼你也可以在監聽數據的返回函數----wx.onBLECharacteristicValueChange()這裏面去監聽數據的返回,根據協議看成功失敗
// wx.showToast({
// title: '操作成功',
// })
}
},
fail: function (res) {
hintOpenBluetooth()
wx.removeStorageSync('bluetoothStatus')
closeBLEConnection()
deleteBLEConnectionData()
closeBluetoothAdapter()
console.log("發送發包數據失敗" + JSON.stringify(res))
}
})
}
/**
* 提醒打開門鎖藍牙配對
*/
const hintOpenBluetooth = () => {
var device = wx.getStorageSync('device')
if (!device) {
return
}
if (wx.getStorageSync('closeHintOpenBluetooth')) {
return
}
//判斷門鎖是否被初始化
var advertisData = device.advertisData;
//電量的二進制數據
var binary = util.sixToBinary(advertisData.substring(16, 18))
if (binary.substring(0, 1) == "0") {
wx.showModal({
title: '提示',
content: '請確定門鎖上是否打開藍牙配對!',
confirmText: '確定',
showCancel: false,
confirmColor: "#23C16E",
success(res) {
if (res.confirm) {
wx.navigateBack()
} else if (res.cancel) {
console.log("取消")
}
}
})
}
}
module.exports = {
sendBluetoothData: sendBluetoothData,
openBluetoothAdapter: openBluetoothAdapter,
createBLEConnection: createBLEConnection,
closeBLEConnection: closeBLEConnection,
deleteBLEConnectionData: deleteBLEConnectionData,
notifyBLECharacteristic: notifyBLECharacteristic
}
三、如何引用工具類
const bluetoothUtil = require('../../utils/bluetoothUtil.js')
四、如何使用工具類
onLoad: function (options) {
var self = this;
bluetoothUtil.openBluetoothAdapter(lockInfo.mac).then(
success => {
var characteristicId = wx.getStorageSync('characteristics').FF07
dataView.setUint8(0, 0x0a)
self.writeBLECharacteristicValue(buffer, characteristicId)
},
fail => {
wx.showToast({
title: '藍牙初始化失敗,請確定藍牙是否打開',
icon: 'none',
duration: 3000
})
}
)
}
//向藍牙寫數據
writeBLECharacteristicValue(buffer, characteristicId) {
var self = this;
//監聽返回值
wx.onBLECharacteristicValueChange(function (res) {
//處理返回值
self.getResultInfo(res)
})
var device = wx.getStorageSync('device')
var deviceId = device.deviceId
var serviceId = device.serviceId
if (typeof (buffer) != "string") {
buffer = util.ab2hex(buffer)
}
bluetoothUtil.sendBluetoothData(buffer, deviceId, serviceId, characteristicId)
},