微信小程序藍牙BLE開發實戰——案例(二)

微信小程序藍牙BLE開發實戰(二)

上篇主要介紹在開發過程中應用到相關API操作。接下來介紹個人在項目開發中應用藍牙BLE一些事情。

由於時間比較倉促, 有些註釋沒那麼詳細。請理解~寫的不好歡迎各位大神指點。

項目介紹

由於公司近階段開發的共享產品比較多,有共享充電寶、陪護牀等,這裏就不一一介紹哈。大部分產品通過藍牙通訊的。

快捷方便通過掃設備二維碼進入小程序使用設備

  • 這裏拿最近開發一個產品售賣機,生活中比較常見的一個,例如: 儲物櫃、格子櫃等。
  • 特點: 一個售賣機中有n個小格子(根據產品分類)

效果圖

在這裏插入圖片描述

掃碼使用格子櫃流程

售賣機上有設備的二維碼(自己生成普通二維碼),直接掃碼

ps: 有個別標註鏈接的,是個人在項目開發中應用總結知識點

  • 微信掃普通二維碼進入小程序授權獲取用戶信息 用戶授權成功後,檢測用戶是否打開藍牙
  • 未打開時彈窗提示用戶, 否則自動跳轉到售賣機頁面。
  • 售賣機頁面會展示售賣商品(比如8個,那麼就展示8個商品)
  • 選擇需要購買的商品, 點擊購買按鈕
  • 支付金額
  • 支付完成後, 調用執行藍牙方法開始搜索設備—>匹配設備—>連接設備...—>開鎖成功(櫃門打開)查看藍牙具體流程】如連接設備失敗,頁面顯示重連按鈕
  • 拿出商品,關好櫃門(可返回購買頁,繼續購買)。

藍牙通訊協議

主要通過與供應商提供的藍牙板子通訊協議和硬件對接,實現操控設備具備的功能。

  • 不同的供應商設備藍牙通訊協議有所不同。反之產品不同通訊流程也不同。

    有些文檔比較不規範,看起來會很茫然, 慢慢理解查資料

加密理解

基於數據安全性完整性等等,藍牙協議通過會在有加密的過程,抵禦攻擊者。

密碼之AES五種加密模式(CBC、ECB、CTR、OCF、CFB)

  • 下發某個指令時需要對數據進行加密,設備會返回數據,通過後再操作其他指令。
  • 下發指令加密, 得到設備返回數據後需要解密,如果驗證通過,纔可以繼續操作後面流程。

不管使用哪種加密模式,會標註在協議文檔或以其他方式說明

ps: 個人在項目中使用模式有 AES ECB 128CFB 128, 還有最近使用一種CRC(循環冗餘校驗)來校驗。
AES加解密案例


實例(藍牙操作功能)

說明:

  • 以下代碼直接copy.js中就可以使用。(這裏有分段說明下,按順序複製即可)
  • 因在項目中對接設備比較多, 把藍牙設備相關功能剝離到js文件中。
  • 注意: 開發工具上不支持調試藍牙功能的
  • 藍牙API詳情介紹請點擊

一. 新建js文件及使用時引入

在這裏插入圖片描述

1. 定義全局變量

根據個人需求適用

const app = getApp()
var utils = require('.././util.js');
var cryptoService = require('../bleFile/cryptoService.js'); //引入加密文件
var crc = require('../bleFile/crc.js'); //引入crc校驗


var serviceUUID = [] //主 service 的 uuid 列表
var writeUUID = ""; //寫讀 UUID
var notifyUUID = ""; //notify UUID
var delayUUID = ""; //護眼儀控制時長UUID
var filterServiceUUID = ""; //過濾獲取到的服務uuid(有些會返回多條數據)
var filterDeviceName = ""; //設備名稱

var macAddress = ""; //保存得到mac地址
var flagFromTypes = ''; //來源類型(根據不同產品執行藍牙協議)  例:1-->充電寶 2-->售賣機....
var _discoveryStarted = false;
var deviceId = ''; //用於區分設備的 id

var _deviceId = '';
var _serviceId = '';
var _characteristicId = '';
var status = false; //當前狀態
var action_type = ''; //操作類型
var code = -1;
var isnotExist = true //防止多次執行

var asddCallBack = null; //接收數據處理
var asddErrorCallback = null; //接收錯誤碼處理
var asddWriteErrors = null; //接收寫入錯誤處理

var tempStr = ''; //拼接設備返回數據
var rssiVal = ''; //RSSI值
var currentSerialVal = ''; //當前點擊格子櫃序號


//當前操作類型
var OptionEnum = {
    None: -1,
    Connection: 0, //連接
    Reconnection: 1, //重連
    CloseLock: 2, //關閉
    VendingOpenLock: 8, //打開售賣機
    ReadStatus: 9, //讀售賣機狀態
    ReadBattery: 10, //讀售賣機電量
};
//這個是變量, 存儲數據的變量
var action_type = OptionEnum.None;

2. 自定義方法

function inArray(arr, key, val) {
    for (let i = 0; i < arr.length; i++) {
        if (arr[i][key] === val) {
            return i;
        }
    }
    return -1;
}

// ArrayBuffer轉16進度字符串示例
function ab2hex(buffer) {
    var hexArr = Array.prototype.map.call(
        new Uint8Array(buffer),
        function(bit) {
            return ('00' + bit.toString(16)).slice(-2)
        }
    )
    return hexArr.join('');
}

/**
 * 去掉 冒號
 */
function clearSymbol(str) {
    str = str.replace(/:/g, ""); //取消字符串中出現的所有冒號
    return str;
}

/**
 *  匹配規則: 取名稱後面的mac
 */
function getNameMac(macAddress, len, name) {
    let clearColonMac = clearSymbol(macAddress);
    let lastFourMac = clearColonMac.substring(clearColonMac.length - len);
    let strName = name.toUpperCase();
    strName = strName + lastFourMac.toUpperCase(); //轉大寫
    console.log('拼接後的' + strName);
    return strName
}


/**
 * 區分不同類型的服務相關uuid
 * 1-->充電寶 2-->售賣機
 */
function flagServiceIDFun(serviceType) {
    console.log('方法中拿到type======>', serviceType);
    if (serviceType == 1) {
        serviceUUID[0] = "0000*E0-00*0-*0*0-*0*0-00**5F9**4*B"; //主 service的uuid 列表
        writeUUID = "00*0**E2-00*0-*0*0-*0*0-00**5F9**4*B"; //寫讀 UUID
        notifyUUID = "00*0**E1-00*0-*0*0-*0*0-00**5F9**4*B"; //notify UUID
        filterServiceUUID = "*E0";
    } else if (serviceType == 2) {
        serviceUUID[0] = "0000*E0-00*0-*0*0-*0*0-00**5F9**4*B"; //主 service的uuid 列表
        writeUUID = "00*0**E2-00*0-*0*0-*0*0-00**5F9**4*B"; //寫讀 UUID
        notifyUUID = "00*0**E1-00*0-*0*0-*0*0-00**5F9**4*B"; //notify UUID
        filterServiceUUID = "*E0";
        
        //這裏介紹用name匹配方法
        filterDeviceName = getNameMac(macAddress, 6, 'abc_'); //設備名稱
    } 
}

3. 初始化藍牙入口

注意: 在使用.js文件中, 只需要調用initBle()方法即可實現藍牙實現整個過程。【方法裏面每個步驟都有調用對應方法】


說明: 所有asddErrorCallback(res.errCode, "");處理錯誤碼回調, 在使用的頁面中接收並處理回調函數。

/**
* 初始化藍牙模塊
* 參數1: mac地址
* 參數2: 當前操作類型
* 參數3: 當前點擊格子的序號(第幾個格子)
*/
function initBle(fromMac, flagTypes, currentSerial) {
    tempStr = ''; //清空

    //斷開連接【每次初始化先斷開連接】
    closeBLEConnection();

    console.log("你獲取到mac地址了麼....", fromMac + '獲取到類型爲====》' + flagTypes);
    // macAddress = clearSymbol(fromMac);
    macAddress = fromMac; //保存mac
    flagFromTypes = flagTypes //類型來源

    //獲取RSSI值
    let getRssi = wx.getStorageSync('rssi');
    rssiVal = getRssi;

    //調用主服務id相關
    flagServiceIDFun(flagTypes);

    // 獲取當前點擊售賣機序號值
    currentSerialVal = currentSerial


    _discoveryStarted = false;

    //初始化藍牙模塊
    wx.openBluetoothAdapter({
        success: (res) => {
            console.log('openBluetoothAdapter 初始化藍牙模塊是否成功:', res)
			// 監聽尋找新設備事件
            onBluetoothDeviceFound();

            //開始搜尋附近的藍牙外圍設備
            startBluetoothDevicesDiscovery();
        },
        fail: (res) => {
            console.log('初始化藍牙失敗', res);
            asddErrorCallback(res.errCode, "");
			
            //監聽藍牙適配器狀態變化事件【根據需求是否執行】
            // wx.onBluetoothAdapterStateChange(function (res) {
            //     console.log('藍牙適配器狀態更改結果:  ', res)
            //     if (res.available) {
            //         console.log('藍牙可用,搜索設備:--》 ')
            //         onBluetoothDeviceFound();
            //         startBluetoothDevicesDiscovery();
            //     }
            // })
        }
    })
}

4. 應用到藍牙API方法

/**
 * 監聽尋找新設備事件
 * 注意咯: 這裏有展示三種不同方式來連接設備,請看備註【mac, name, 根據系統的】 各取所需吧。
 */
function onBluetoothDeviceFound() {
    wx.onBluetoothDeviceFound((res) => {
        console.log('廣播數據結果:', res);

        res.devices.forEach(device => {
            if (!device.name && !device.localName) {
                return
            }

            // 轉換後, 根據協議文檔取需要數據 (advertisData不一定有數據)
            if (device.advertisData != null) { //判斷對象是否爲null,advertisData不一定有
                var hexStr = ab2hex(device.advertisData);
                console.log("廣播數據中轉換後:advertisData---->" + hexStr);
            }
            

            // 充電寶 android用mac, ios用name匹配
            if (flagFromTypes == 1) {
                if (app.getPlatform() == 'android') {
                    if ((macAddress != "") && (macAddress == device.deviceId) && isnotExist) {
                        isnotExist = false;
                        deviceId = device.deviceId;

                        stopBluetoothDevicesDiscovery();
                        //連接設備
                        createBLEConnection();
                    }
                } else if (app.getPlatform() == 'ios') {
                    let deviceName = device.name.toUpperCase();
                    if ((deviceName.indexOf(filterDeviceName) != -1) && isnotExist) {
                        isnotExist = false;
                        deviceId = device.deviceId;
						
                        //停止搜尋附近的藍牙外圍設備
                        stopBluetoothDevicesDiscovery();
                        //連接設備
                        createBLEConnection();
                    }
                }
            } else if (flagFromTypes == 2) {
                // 格子櫃 Android IOS通過名稱匹配
                if (parseFloat(device.RSSI) > parseFloat(rssiVal)) {
                    let deviceName = device.name.toUpperCase();
                    if ((deviceName.indexOf(filterDeviceName) != -1) && isnotExist) {
                        isnotExist = false;
                        deviceId = device.deviceId;
						
                        //停止搜尋附近的藍牙外圍設備
                        stopBluetoothDevicesDiscovery();
                        //連接設備
                        createBLEConnection();
                    }
                }
            } 
        })
    })
}



/**
 * 執行連接藍牙設備
 */
function startBluetoothDevicesDiscovery() {
    if (_discoveryStarted) {
        return;
    }
    _discoveryStarted = true
    
    wx.startBluetoothDevicesDiscovery({
        services: serviceUUID,
        allowDuplicatesKey: false,
        success: (res) => {
            console.log('啓動搜索藍牙設備, 結果  :', res)
            //onBluetoothDeviceFound()  //先調用此方法再使用startBluetoothDevicesDiscovery
        },
        fail(res) {
            asddErrorCallback(res.errCode, "");
            console.log('startBluetoothDevicesDiscovery fail', res);
        }
    })
}


//停止搜尋附近的藍牙外圍設備。
function stopBluetoothDevicesDiscovery() {
    wx.stopBluetoothDevicesDiscovery()
}


/**
 * 連接藍牙設備
 */
function createBLEConnection() {
    var that = this;
    wx.createBLEConnection({
        deviceId: deviceId,
        success: (res) => {
            wx.showToast({
                title: '設備連接成功',
                duration: 2000
            })
            //獲取藍牙所有服務
            getBLEDeviceServices(deviceId)
        },
        fail: (res) => {
            console.log('createBLEConnection fail', res);
            asddErrorCallback(res.errCode, "");
        }
    })
    stopBluetoothDevicesDiscovery(); //停止搜索
}


/**
 * 斷開藍牙連接
 */
function closeBLEConnection() {
	//停止搜索
    stopBluetoothDevicesDiscovery();

    tempStr = ''; //清空

    if (deviceId) {
        wx.closeBLEConnection({
            deviceId: deviceId,
            success: function(res) {
                console.log("closeBLEConnection。success", res);

            },
            fail: function(res) {
                console.log("closeBLEConnection。fail", res);
            },
            complete: function() {
                status = false;
            }
        })

        wx.closeBluetoothAdapter({
            success: function(res) {
                console.log("closeBluetoothAdapter ==>res:", res);
            },
            fail: function(error) {
                console.log("closeBluetoothAdapter ==>error:", error);
            }
        })
    }

    _discoveryStarted = false;
    isnotExist = true;
    _deviceId = '';
    deviceId = '';
}


/**
 * 獲取藍牙所有服務
 */
function getBLEDeviceServices(deviceId) {
    wx.onBLEConnectionStateChange(function(res) {
        console.log("onBLEConnectionStateChange:", res);
        // 該方法回調中可以用於處理連接意外斷開等異常情況
        console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`)
        if (res.connected == false) {
            console.log("連接意外斷開等****", _deviceId);
            _deviceId = '';
            if (flagFromTypes == 1 && flagFromTypes == 2) {
                asddErrorCallback(1010, ""); //?
            }
        }
    });

    wx.getBLEDeviceServices({
        deviceId: deviceId,
        success: (res) => {
            // console.log("獲取藍牙設備所有服務(service)", res);
            for (let i = 0; i < res.services.length; i++) {
                let tmpUuid = res.services[i].uuid;
                if ((res.services[i].isPrimary) && (tmpUuid.indexOf(filterServiceUUID) != -1)) {
                    getBLEDeviceCharacteristics(deviceId, res.services[i].uuid)
                    return
                }
            }
        },
        fail: (res) => {
            console.log('getBLEDeviceServices fail', res);
            asddErrorCallback(res.errCode, "");
        }
    })
}


/**
 * 獲取藍牙特徵值
 */
function getBLEDeviceCharacteristics(deviceId, serviceId) {
    wx.getBLEDeviceCharacteristics({
        deviceId: deviceId,
        serviceId: serviceId,
        success: (res) => {
            // console.log('藍牙設備特徵值信息:', res);
            for (let i = 0; i < res.characteristics.length; i++) {
                let item = res.characteristics[i]
                var itemUUID = item.uuid.toUpperCase(); //轉大寫

                if (item.properties.read && itemUUID == writeUUID) {
                    wx.readBLECharacteristicValue({
                        deviceId: deviceId,
                        serviceId: serviceId,
                        characteristicId: item.uuid,
                    })
                }
                if (item.properties.write && itemUUID == writeUUID) {
                    _deviceId = deviceId
                    _serviceId = serviceId
                    _characteristicId = item.uuid

                    //發送指令【說明:如需連接設備後發相關指令可以在這裏調用】
              		if (flagFromTypes == 1) { //充電寶
                        powerBank.send(); //充電開機指令
                    } else if (flagFromTypes == 2) { //售賣機
                        vendingObj.checkEnKey(); //AES校驗
                    }
                }

                if (notifyUUID == itemUUID) {
                    if (item.properties.notify || item.properties.indicate) {
                        console.log('調用notifyBLECharacteristicValueChange前', item.uuid);
                        wx.notifyBLECharacteristicValueChange({
                            deviceId: deviceId,
                            serviceId: serviceId,
                            characteristicId: item.uuid,
                            state: true,
                            success(res) {
                                console.log('notification通知數據', res);
                                status = true;
                                // wx.hideLoading();
                            },
                            fail(res) {
                                console.log('notifyBLECharacteristicValueChange fali', res);
                            }
                        })
                    }
                }
            }
        },
        fail: (res) => {
            console.log('getBLEDeviceCharacteristics fail', res)
            asddErrorCallback(res.errCode, "");
        }
    })


    // 操作之前先監聽,保證第一時間獲取數據
    wx.onBLECharacteristicValueChange(function(res) {
        console.log(`characteristic ${res.characteristicId} has changed, now is ${res.value}`)
        console.log("操作類型:" + action_type);

        var resData = ab2hex(res.value);
        console.log("設備返回數據--->", resData); //5d0000000001be304d

        // 判斷不同類型處理數據
		if (flagFromTypes == 2) {
            console.log('開始調用 自動售賣機====> 處理返回的數據');
            vendingObj.handleResData(resData); //處理返回數據
        }
    })
}

/**
 * 寫入數據
 */
function writeData(hex, action = '') {
    if (!status) {
        return;
    }

    if (!_deviceId) {
        asddWriteErrors('w');
        return;
    }

    setTimeout(() => {
    	//向設備特徵值中寫入二進制數據
        //這裏使用`TypedArray視圖`中`Uint8Array(無符號 8 位整數)`操作
        var enDataBuf = new Uint8Array(hex);
        var buffer1 = enDataBuf.buffer

        wx.writeBLECharacteristicValue({
            deviceId: _deviceId,
            serviceId: _serviceId,
            characteristicId: _characteristicId,
            value: buffer1,
            success: (res) => {
                wx.hideLoading();
                console.log("寫數據返回結果", res.errMsg);
            },
            fail(res) {
                console.log("寫數據失敗..", res);
                asddErrorCallback(res.errCode, "");
            }
        })
    }, 1000)
}

5. 處理設備返回數據操作指令(如何發指令?)

售賣機爲例, 注意: 交互流程指令格式根據文檔說明

/**
 * 售賣機
 */
var vendingObj = {
    /**
     * 校驗AES密鑰
     * 字符、key文檔有說明
     */
    checkEnKey: function() {
        status = true;
        var strKey = [0xd0, 0xf0, 0xf0, 0x80, 0x50, 0xa0, 0x60, 0x10, 0x20, 0x50, 0xc0, 0xd0, 0x80, 0x80, 0x40, 0x90];
        var key = [0xd0, 0xf0, 0xf0, 0x80, 0x50, 0xa0, 0x60, 0x10, 0x20, 0x50, 0xc0, 0xd0, 0x80, 0x80, 0x40, 0x90];
        var cryptoKey = new Uint8Array(key);
        enKEY = cryptoKey;
        //得出加密後的指令, 十六進制的數據
        var enHEX = cryptoService.updateEncrypt(strKey, enKEY);
        writeData(enHEX);
    },
    
    /**
     * 查詢設備信息
     */
    queryDeviceInfo: function() {
        action_type = OptionEnum.ReadBattery; //改變操作類型
        let hex = [0x69, 0xf2, 0x00, 0x89];
        writeData(hex); //寫入數據
    },
    
     /**
     * 開鎖指令
     */
    openVendingLock: function(callBack) {
        status = true;
        action_type = OptionEnum.VendingOpenLock;
        asddCallBack = callBack;
        //獲取當前開鎖的編號及轉換
        let getCurrentVal = Number(currentSerialVal);
        getCurrentVal = getCurrentVal.toString(16);
        // let tempVal = '0x0' + getCurrentVal;
        let tempVal = parseInt(getCurrentVal, 16);
        console.log('====開鎖編號===》', tempVal);
        let hex = [0xfe, 0x4e, 0x30, 0x46, 0x4a, 0x00, tempVal, 0x00, 0x00, 0x3e];
        writeData(hex);
    },

    /**
     * 處理格子機查詢信息電量回調
     * 目的:獲取到相關數據,發送給後端(查看設備電量)
     */
    readBatteryCallBack: function(battery) {
        console.log("=======>>>電量:", battery);
        action_type = OptionEnum.None;

        //這裏獲取到電量, 返回給index.js頁面
        if (asddCallBack != null) {
            asddCallBack(battery, OptionEnum.ReadBattery);
        } else {
            console.log("是否爲空=======標籤 2");
        }
    },
    
 
    /**
     * 處理開鎖成功回調
     */
    openLockCallback: function(resData) {
        var isOpenLock = false;
        // 根據當前點擊的櫃子序號,截取對應的數據狀態
        var star = Number(currentSerialVal) * 2
        var subSerial = resData.substring(star, star + 2);
        if (subSerial.toUpperCase() == 'F0') {
            isOpenLock = true;
        }
        console.log("=======>>>開鎖:", isOpenLock ? "成功" : "失敗");
        action_type = OptionEnum.None;

        if (asddCallBack != null) {
            asddCallBack(isOpenLock, OptionEnum.VendingOpenLock);
        } else {
            console.log("是否爲空=======標籤 3");
        }
    },

    
    /**
     * 處理返回數據
     * 例如: 00f05d09000001be304d
     */
    handleResData: function (resData) {
        let checkStatus = resData.substring(2, 4);

        if (checkStatus.toUpperCase() == 'F0' && action_type == OptionEnum.Connection) { //校驗狀態
            vendingObj.queryDeviceInfo(); //查詢設備信息

        } else if (action_type == OptionEnum.ReadBattery) { //操作的是獲取設備電量

            let batteryVal = resData.substring(6, 8);
            batteryVal = parseInt(batteryVal, 16);
            vendingObj.readBatteryCallBack(batteryVal);

        } else if (action_type == OptionEnum.VendingOpenLock) { //操作的是 開鎖

            vendingObj.openLockCallback(resData);
        }
    }
}

6. 處理回調一些方法

//設置連接
function setConnectionActionType(callBack) {
    action_type = OptionEnum.Connection;
    asddCallBack = callBack;
}

//設置重連
function setReconnectionActionType() {
    action_type = OptionEnum.Reconnection;
}

// 設置錯誤
function setAsddErrorCallback(callBack) {
    asddErrorCallback = callBack;
}

//設置關閉
function setCloseActionType(callBack) {
    action_type = OptionEnum.CloseLock;
    asddCallBack = callBack;
}

//設置寫入錯誤
function setWriteError(callBack) {
    asddWriteErrors = callBack;
}

//清除
function clearCallBack() {
    asddCallBack = null;
}

/**
 * 清空loadding
 */
function hideLoading() {
    wx.hideLoading();
}


/**
 * 檢查是否打開藍牙
 * 未連接設備前檢測
 */
function checkIsOpenBluetooth(isEXec) {
    wx.openBluetoothAdapter({
        success: (res) => {
            // console.log('openBluetoothAdapter 初始化藍牙模塊是否成功:', res);
            isEXec(true);
        },
        fail: (res) => {
            // console.log('初始化藍牙失敗', res);
            wx.showModal({
                title: '提示',
                content: '請檢查手機藍牙是否打開',
                showCancel: false
            })

            isEXec(false);
        }
    })
}

7. 藍牙連接過程中錯誤碼

/**
 * 藍牙連接過程中錯誤碼
 * 10000 / 10006
 */
function bluetoothStatus(errorType) {
    switch (errorType) {
        case 10001:
            wx.showModal({
                title: '提示',
                content: '請檢查手機藍牙是否打開',
                showCancel: false
            })
            break;
        case 10002:
            wx.showToast({
                title: '沒有找到指定設備',
                icon: 'none'
            })
            break;
        case 10003:
            wx.showToast({
                title: '連接失敗',
                icon: 'none'
            })
            closeBLEConnection();
            break;
        case 10004:
            wx.showToast({
                title: '沒有找到指定服務',
                icon: 'none'
            })
            closeBLEConnection();
            break;
        case 10005:
            wx.showToast({
                title: '沒有找到指定特徵值',
                icon: 'none'
            })
            closeBLEConnection();
            break;
        case 10007:
        case 10008:
        case 10013:
            wx.showToast({
                title: '設備啓動失敗,請重試',
                icon: 'none'
            })
            break;
        case 10009:
            wx.showModal({
                title: '提示',
                content: '當前系統版本過低,請更新版本體驗',
                showCancel: false
            })
            break;
        case 10012:
            wx.showToast({
                title: '連接超時',
                icon: 'none'
            })
            break;
    }
}

8. 導出方法

外部需使用的方法,注意導出。否則無法使用

module.exports = {
    initBle: initBle,
    clearCallBack: clearCallBack,
    closeBLEConnection: closeBLEConnection,
    setConnectionActionType: setConnectionActionType,
    setReconnectionActionType: setReconnectionActionType,
    setAsddErrorCallback: setAsddErrorCallback,
    setCloseActionType: setCloseActionType,
    setWriteError: setWriteError,
    checkIsOpenBluetooth: checkIsOpenBluetooth,
    bluetoothStatus: bluetoothStatus,
    openVendingLock: vendingObj.openVendingLock,
}

二 、在需要頁面中調用藍牙

1. 引入文件

const app = getApp()
let commonBLE = require('../../../../../utils/fromCategory/commonBLE.js'); //公共BLE
let commonBLEDatas = null; //保存當前頁面對象

2. 全局中定義處理回調函數

全局方法中如何給data中屬性賦值
  • 定義一個全局變量,來保存當前頁面對象
  • onLoad()中給變量賦值, 即commonBLEDatas = this
  • 使用: 通過變量名.data.屬性,即commonBLEDatas.data.battery = obj
/**
 * 處理返回部分數據回調函數
 * obj: 傳過來的數據
 * types: 當前操作類型 【可在`commBLE.js`查看定義的】
 */
let callBack = function(obj, types) {
    console.log("index.js回調函數" + obj, types);
    // commonBLE.clearCallBack();
    if (commonBLEDatas.data.currentMeasureType == 4) { //售賣機
        if (types == 10) {
            //給電量賦值
            commonBLEDatas.data.battery = obj;
            
            //調用開鎖指令
            commonBLEDatas.successOpenLock();
        } 
    }
}

/**
 * 處理錯誤碼回調
 */
let errorCallBack = function(errorType, errorMessage) {
    // feedbackApi.hideTimerToast(); //清空loadding
    commonBLEDatas.deviceConnectFail(); //展示 設備連接失敗
    if (errorType == 10000 || errorType == 10006) {
        //連接藍牙
        commonBLE.setReconnectionActionType();
        commonBLE.setAsddErrorCallback(errorCallBack);
        commonBLE.setWriteError(writeError);
        if (commonBLEDatas.data.currentMeasureType == 4) {
            commonBLE.initBle(commonBLEDatas.data.macAdress, OptionEnumType.Vending, commonBLEDatas.data.currentSerial);
        } 
    } else {
        commonBLE.bluetoothStatus(errorType);
    }
}


/**
 * 寫入失敗回調
 */
let writeError = function(writeE) {
    console.log('寫入數據狀態', writeE);
    //寫入錯誤頁面展示狀態
    commonBLEDatas.setData({
        connectStatus: 1,
        isConnect: 2,
        clickFlags: false
    })

    if (writeE == 'w') {
        feedbackApi.hideTimerToast(); //清空loadding
        clearInterval(commonBLEDatas.downSecondId); //清空倒計時

        wx.showToast({
            title: '連接失敗,請再次嘗試(0)',
            icon: 'none'
        })
        commonBLE.closeBLEConnection();
    }
}

3. 調用執行藍牙方法

  • 點擊購買商品按鈕, 執行此方法。
  • 傳參: 當前設備的mac地址(後臺獲取的)操作的產品類型操作序號(操作幾號櫃子)

說明: 櫃子序號1,2,3,4…, 和頁面展示商品對應的。

Page({

     /**
     * 頁面的初始數據
     */
    data: {
        currentMeasureType: 2, //測試 當前類型售賣機
        macAdress: '3b3533115510', //mac地址(這裏後臺保存時沒有:號的,可自行處理)
        currentSerial: '', //當前操作格子序號
    },

    /**
     * 生命週期函數--監聽頁面加載
     */
    onLoad: function(options) {
        commonBLEDatas = this;
    },
    
   /**
    * 連接BLE
    */
	connectVendingBLE: function() {
	    let that = this;
	    commonBLE.setConnectionActionType(callBack); //連接後操作回調
	    commonBLE.setAsddErrorCallback(errorCallBack); //執行錯誤時錯誤碼回調
	    commonBLE.setWriteError(writeError); //寫入數據錯誤回調
	    if (that.data.currentMeasureType == 2) {
	        commonBLE.initBle(that.data.macAdress, OptionEnumType.Vending, that.data.currentSerial);
	    } 
	},
	
	/**
     * 設備連接失敗
     */
    deviceConnectFail: function () {
        // feedbackApi.hideTimerToast(); //清空loadding
        clearInterval(this.downSecondId); //清空倒計時
        this.setData({
            descTxt2: '設備連接失敗',
            connectStatus: 1,
            isConnect: 2,
            clickFlags: false
        })
    },
})

4. 執行開鎖

如獲取電量成功後, 執行開鎖指令,成功後頁面展示對應【具體流程根據需求來】

/**
* 售賣機開鎖成功後提交數據  並展示相關的ui
* 寫在 Page({})中的, 這裏爲了說明寫在外面
*/
successOpenLock: function() {
    let that = this;
    // 調用開鎖及處理回調數據
    commonBLE.openVendingLock(function(isOpenLock, obj) {
        console.log('處理開鎖指令回調====》' + isOpenLock);
        commonBLE.clearCallBack();
        
        var tempStr = "失敗";
        if (isOpenLock) {
            tempStr = "成功";
            // 提交數據並展示成功開鎖後Ui
            that.showSuccessBack();
        }else {
            wx.showToast({
                title: "開鎖" + tempStr,
                duration: 3000,
                image: '/page/common/libs/assets/images/error.png',
            })

            that.deviceConnectFail(); //展示 設備連接失敗
			//斷開藍牙連接
            commonBLE.closeBLEConnection();
        }
    });
},

BLE項目實戰下載

藍牙BLE項目實戰

關於下篇內容

  • BLE開發中遇到問題及踩坑
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章