我最近做了一個軟硬件結合的項目,通過小程序藍牙去連接設備,控制鎖的開門,總結了一下知識和坑點,希望對大家有點幫助。
首先說我做的這個項目的作用吧
我的項目是一個醫療陪護床,他做初衷是,給長期在醫院陪病人家屬的人準備的,當病人家屬累了,或者困了的時候,就可以關注我的小程序,進入小程序,點擊掃碼交押金,然后開鎖使用,把陪護床拉開,即可使用。
開始介紹我的藍牙代碼和坑點
開鎖使用流程代碼
1,進入小程序點擊開鎖,判斷手機藍牙是否開啟,這一步最開始的就是判斷小程序對手機藍牙的狀態查看。
wx.closeBluetoothAdapter({
? ? success: res => {
? ? ? wx.openBluetoothAdapter({ //初始化 藍牙模塊? 成功 和 失敗的回調
? ? ? ? success: res => {
? ? ? ? ? console.log('初始化藍牙成功' + res)
? ? ? ? ? this.context.setData({ bluetoothState: true })
? ? ? ? ? this.getBluetoothAdapterState()? //藍牙開啟成功,執行去查看藍牙適配情況
? ? ? ? },
? ? ? ? fail: err => {
? ? ? ? ? console.log(err);
? ? ? ? ? wx.hideLoading();
? ? ? ? ? this.context.setData({ bluetoothState: false })
? ? ? ? }
? ? ? })
? ? }
? })
2,手機藍牙開啟成功,進一步判斷藍牙適配是否可用
wx.getBluetoothAdapterState({ //獲取本機藍牙適配器狀態 判斷用戶是否開啟藍牙
? ? ? success: res => {
? ? ? ? console.log('藍牙狀態', res)
? ? ? ? //discovering 是否正在搜索設備? available 藍牙適配器是否可用
? ? ? ? if (res.available == false) {?
? ? ? ? ? wx.showToast({
? ? ? ? ? ? title: '設備無法開啟藍牙連接',
? ? ? ? ? ? icon: 'none'
? ? ? ? ? })
? ? ? ? } else if (res.discovering == false){
? ? ? ? ? ? this.startBluetoothDevicesDiscovery()
? ? ? ? } else if (res.available){
? ? ? ? ? this.startBluetoothDevicesDiscovery()? //藍牙適配器正常,去執行搜索外圍設備
? ? ? ? }
? ? ? }
? ? })
3,開始搜索外圍設備,(注意:執行該操作比較浪費資源,在搜索到mac地址成功后停止該操作)
wx.startBluetoothDevicesDiscovery({ //開始搜尋附近的藍牙外圍設備
? ? services: [this.serviceId], //搜索對應設備的id? 以微信硬件平臺的藍牙智能燈為例,主服務的 UUID 是 FEE7。傳入這個參數,只搜索主服務 UUID 為 FEE7 的設備
我這邊 因為固件底層代碼放設定了? serviceId = '0000FFF0-0000-1000-8000-00805F9B34FB'? ,所以只會所搜0000FFF0-0000-1000-8000-00805F9B34FB 的住服務,這邊的話類似一個過濾器
? ? allowDuplicatesKey:false,
? ? success:res =>{
? ? ? ? console.log(res);
? ? ? if (!res.isDiscovering) { //是否在搜索到了設備
? ? ? ? this.getBluetoothAdapterState()
? ? ? }else{
? ? ? ? console.log('1');
????????/ /當時成功時候,就去執行左邊監聽附近新設備的api
? ? ? ? this.onBluetoothDeviceFound()
? ? ? }
? ? },
? ? fail: err => {
? ? ? console.log(err)
? ? ? this.stopBluetoothDevicesDiscovery()
? ? }
? })
4,這一步是去執行監聽附近設備,獲取附近設備的devices 結構
? ?這邊是有兩個場景,一個位ios,一個安卓,安卓其實通過搜索到devices 里面的mac地直接配對通過,而ios所搜不到mac,只能得到devices 里面uuid,(uuid 可以通過小程序官方提供的一個方法去轉成十六進制的數據的mac地址),我這邊安卓和ios全部是通過uuid去轉為六十機制mac地址,去做配對的,這樣一來就不用區分ios和安卓兩個場景。
注意,這里設備的mac搜索到之后,一定要執行wx.stopBluetoothDevicesDiscovery() 函數,暫定搜索,不然后臺資源很消耗性能的。
functionab2hex(buffer){consthexArr =Array.prototype.map.call(newUint8Array(buffer),function(bit){return('00'+ bit.toString(16)).slice(-2) } )returnhexArr.join('')}
wx.onBluetoothDeviceFound((res) => {
? ? console.log('搜索到的設備沒配對成功有', res)
? ? res.devices.forEach(device => {
? ? ? console.log(device);
? ? ? let _advertisData = this.ab2hex(device.advertisData) //得到設備的mac地址
? ? ? if (_advertisData == that.advertisData){)
? ? ? ? this.context.connectCallBack('1'); 執行成功對應的回調函數
? ? ? ? wx.setStorageSync('device', device.deviceId)//第一搜索到設備 保存在本地,給關鎖的時候使用
? ? ? ? that.deviceId = device.deviceId;
? ? ? ? that.stopBluetoothDevicesDiscovery() //設備已經搜索到,停止搜索
? ? ? ? console.log('設備已經搜索到,停止搜索')
? ? ? ? that.createBLEConnection()
? ? ? }
? ? })
? })
4,獲取onBluetoothDeviceFound 通過的?devices 里面 deviceId去連接設備。
連接這邊安卓和ios 比較坑的,一次連接失敗的概率性特別大,所以為了用戶體驗上,必須的通過多次循環返回連接,直到連接成功之后,才跳出循環。
我這邊的小程序循環的
全局的openFlag=false 在點擊開鎖的第一個函數里面,執行到createBLEConnection函數的時候,調用openlock函數 里面判斷條件不成立就是一直循環值,直到? if (count == 6 && this.openFlag ==false) 時候,這個時候說明6次多連接失敗,那么全局openFlag=ftrue 就會?if (count == 6 && this.openFlag == true) 這個終止的條件,跳出界面,這是現階段最好解決方法,歡迎大家指點。
連接成功之后
createBLEConnection = function () {
? ? this.openlock(0);
}
openlock=function(count){
? ? //連接藍牙之后,就一直是true·
? if (count == 6 && this.openFlag ==false){
? ? //五次沒有連接上,重新卸載藍牙模塊,重新連接
? ? this.startConnect(this.context,true);
? ? return false;
? }
? //成立
? if (count == 6 && this.openFlag == true){
? ? //執行到這一步 一定是deviceId值錯誤
? ? ? wx.showToast({
? ? ? ? title: '連接中斷,請重試',
? ? ? ? icon:'none'
? ? ? })
? ? ? setTimeout(()=>{
? ? ? ? wx.navigateBack({
? ? ? ? ? data: 1,
? ? ? ? })
? ? ? },2000)
? ? ? ? return false;? ? ? ?
? ? }
? const self = this;
? //500毫秒連接一次,連接一次失敗,繼續連接,直到10次連接失敗,就讓他跳轉首頁
? setTimeout(() => {
? ? wx.createBLEConnection({
? ? ? deviceId: this.deviceId,
? ? //? deviceId:"a434f199651s",
? ? ? success: res => {
? ? ? ? console.log('連接', res)
? ? ? ? if (res.errCode == 0) {
? ? ? ? ? wx.hideLoading() //連接成功? 關閉提示狂
? ? ? ? ? self.funk = true //防止 連接點擊開鎖按鈕處理
? ? ? ? ? wx.showToast({
? ? ? ? ? ? title: '藍牙連接設備成功',
? ? ? ? ? ? icon: 'none'
? ? ? ? ? })
? ? ? ? ? this.getBLEDeviceServices(this.deviceId)
? ? ? ? }
? ? ? },
? ? ? fail: err => {
? ? ? ? console.log(err)
? ? ? ? console.log(count)
? ? ? ? self.openlock(count+1);
? ? ? }
? ? })
? }, 500)
}
5,連接藍牙成功之后,這里就是得獲取藍牙所有的服務,這一步為了與建立通訊而準備的
/注意:這里的 deviceId 需要已經通過 createBLEConnection 與對應設備建立鏈接
wx.getBLEDeviceServices({
? ? deviceId,
? ? success: (res) => {
? ? ? console.log('服務', res)
? ? ? this.getBLEDeviceCharacteristics(this.deviceId, this.serviceId)
? ? }
? })
6,獲取設備的特征值,這一步很重要
?判斷是否 write? boolean? 該特征值是否支持 write 操作?write?該操作是藍牙寫人二進制數據
??判斷是否 notifyboolean該特征值是否支持 notify 操作
??判斷是否? indicateboolean該特征值是否支持 indicate 操作
??判斷是否??readboolean該特征值是否支持 read 操作
上述判斷?notifyboolean?indicateboolean?readboolean 至少這三種通過,不然寫二進制數據的時候,回調失敗。
wx.getBLEDeviceCharacteristics({
? ? deviceId,
? ? serviceId,
? ? success: (res) => {
? ? ? console.log('特征值', res.characteristics)
? ? ? for (let i = 0; i < res.characteristics.length; i++) {
? ? ? ? let item = res.characteristics[i]
? ? ? ? if (item.uuid == this.characteristicId) {
? ? ? ? ? this.notifyBLECharacteristicValueChange(this.deviceId, this.serviceId, this.characteristicId)
? ? ? ? ? this.context.connectCallBack()
? ? ? ? }
? ? ? }
? ? },
? ? fail(res) {
? ? ? console.error('getBLEDeviceCharacteristics', res)
? ? }
? })
7.這個一步是比較重要,向設備藍牙進入十六進制數據,列表你想要設備做一些動作,比如開鎖關鎖,一些指令。
wx.writeBLECharacteristicValue({
? ? ? deviceId,//設備的 id
? ? ? serviceId, //0000FFF0-0000-1000-8000-00805F9B34FB
? ? ? characteristicId: this.characteristicId,//0000FFF6-0000-1000-8000-00805F9B34FB
? ? ? value: buffer,//藍牙設備特征值對應的二進制值
? ? ? success: res => { resolve(res) },
? ? ? fail: err => { reject(err) }
? ? })
? })
8,啟用低功耗藍牙設備特征值變化時的 notify 功能,訂閱特征值。注意:必須設備的特征值支持 notify 或者 indicate 才可以成功調用。
另外,必須先啟用?notifyBLECharacteristicValueChange?才能監聽到設備?characteristicValueChange?事件
wx.notifyBLECharacteristicValueChange({
? ? state: true,
? ? deviceId,
? ? serviceId,
? ? characteristicId,
? ? success: res => {
? ? ? console.log('監聽成功:', res)
? ? ? this.onBLECharacteristicValueChange()
? ? }
? })
9.監聽低功耗藍牙設備的特征值變化事件。必須先啟用?notifyBLECharacteristicValueChange?接口才能接收到設備推送的 notification。
wx.onBLECharacteristicValueChange(res => {
? ? console.log('123')
? ? console.log('監聽值', this.ab2hex(res.value))
? ? this.context.callBack(this.ab2hex(res.value))
? })、
10,當你所有功能pai執行完成之后,就去寶珠
wx.stopBluetoothDevicesDiscovery()