uni-app使用低功耗藍牙自動連接售貨機


    最近在做一個藍牙售貨機的項目,放在酒店房間內,哈哈,里邊是什么自行腦補。

    因為需要適配微信小程序和支付寶小程序,所以最后選用uni-app來開發,省時省力更省錢。

    第一次對接藍牙,做一次記錄,話不多說,開始上代碼。

 
    *uni-app藍牙連接的整個流程 
    *1、初始化藍牙 uni.openBluetoothAdapter(OBJECT) 
    *2、開始搜索藍牙設備 uni.startBluetoothDevicesDiscovery(OBJECT) 
    *3、發現外圍設備 uni.onBluetoothDeviceFound(CALLBACK) 
    *4、停止搜尋附近的藍牙外圍設備 uni.stopBluetoothDevicesDiscovery(OBJECT) 
    *5、連接低功耗藍牙設備 uni.createBLEConnection(OBJECT) 
    *6、獲取藍牙設備所有服務 uni.getBLEDeviceServices(OBJECT) 
    *7、獲取藍牙特征 uni.getBLEDeviceCharacteristics(OBJECT) 
    *8、啟用藍牙設備特征值變化時的 notify 功能             uni.notifyBLECharacteristicValueChange(OBJECT) 
    *9、監聽低功耗藍牙設備的特征值變化 uni.onBLECharacteristicValueChange(CALLBACK) 
    *10、對需要操作的特征值進行讀、寫操作 
 
import store from '@/store/index.js'
let _self;
export default class deviceClass {
    constructor() {
        _self = this;
        _self.deviceId = "";
        _self.isConnect = false; //是否已連接
        _self.isStop = false; //是否停止搜所
        _self.UUID_SERVICE = '0000FEE0-0000-1000-8000-00805F9B34FB'; //服務UUID,設備方提供
        _self.UUID_CHAR = '0000FEE1-0000-1000-8000-00805F9B34FB'; //特征值UUID,設備方提供
    }
    /* 初始化並搜索藍牙操作 */
    initEventDevice() {
        uni.showLoading({
            title: "藍牙連接中"
        })
 
        /* 1、初始化藍牙 uni.openBluetoothAdapter(OBJECT) */
        uni.openBluetoothAdapter({
            complete: () => {
                /* 監聽藍牙是否開啟*/
                uni.onBluetoothAdapterStateChange(function(res) {
                    //res.available 藍牙適配器是否可用
                    //res.discovering 藍牙適配器是否處於搜索狀態
                    console.log('適配器狀態變化', res)
 
                    if(!res.available && !res.discovering){
                        _self.isStop = false;
                        uni.showToast({
                            duration: 2500,
                            title: "請打開手機藍牙",
                            icon: 'error',
                        })
                        store.commit('updateStatus', false);
                    } else if(_self.isStop==false && res.available && !res.discovering){
                        console.log("藍牙已開啟,可以執行搜索操作")
                        _self.initEventDevice();
                    } else if(res.available && res.discovering){
                        console.log("藍牙已開啟,並且正在搜索中")
                    }
                })
            },
            success: (res) => {
                /* 初始化藍牙成功 */
                /* 2、開始搜索藍牙設備 uni.startBluetoothDevicesDiscovery(OBJECT) */
                /* 監聽藍牙適配器狀態變化事件  可以檢測當前設備的藍牙的斷開或者連接的情況*/
                _self.startBluetoothDevicesDiscovery();
                _self.connectTimeout();
                
            },
            fail: (res) => {
                console.log("初始化藍牙失敗:" + JSON.stringify(res))
                uni.hideLoading();
                uni.showToast({
                    duration: 2500,
                    title: "請打開手機藍牙",
                    icon: 'error',
                })
            }
        })
    }
    /*搜索藍牙*/
    startBluetoothDevicesDiscovery() {
        uni.startBluetoothDevicesDiscovery({
            allowDuplicatesKey: false, //是否允許同一設備多次上報,但RSSI值會有所不同
            success: (res) => {
                console.log("搜索成功:" + JSON.stringify(res))
                _self.onBluetoothDeviceFound();
            },
            fail: (res) => {
                uni.showModal({
                    title: '藍牙連接失敗了哦',
                    content: `
                        1、請查看周圍是否有連接此設備的藍牙;
                        2、請先關閉手機藍牙在打開一次;
                        3、請檢查位置信息是否打開;
                        4、退出小程序重新掃碼進入。`,
                    showCancel: false,
                    confirmText: "我知道了",
                    success: () => {}
                })
                console.log("搜索失敗:" + JSON.stringify(res))
            }
        })
    }
    
    /* 搜索藍牙設備回調 */
    onBluetoothDeviceFound() {
        uni.onBluetoothDeviceFound(function(CALLBACK) {
            console.log('搜索藍牙設備回調===' + JSON.stringify(CALLBACK))
            /* 每次遍歷指定設備,一旦搜索到指定設備就結束搜索*/
            
            let bluename = JSON.parse(uni.getStorageSync('deviceInfo')).bluename; //需要搜索的設備名稱
            /* 搜索過程中如果搜索到需要的設備,就停止搜索 */
            CALLBACK.devices.forEach(device => {
                /* 篩選需要的deviceId */
                if (device.deviceId === bluename) {
                    //找到需要的設備之后,停止搜索
                    console.log("搜索到指定設備=="+device.deviceId)
                    _self.isConnect = true;
                    /*停止搜索*/
                    _self.stopBluetoothDevicesDiscovery();
                    /* 執行連接 */
                    _self.connectDevice(device.deviceId);
                }
            })
        })
    }
    
    /*設置藍牙搜索時間30秒, 如果超時沒有搜索到就停止搜索*/
    connectTimeout() {
        setTimeout(() => {
            if(!_self.isConnect) {
                uni.hideLoading();
                _self.stopBluetoothDevicesDiscovery();
                uni.showModal({
                    title: '藍牙連接失敗了哦',
                    content: `
                        1、請查看周圍是否有連接此設備的藍牙;
                        2、請先關閉手機藍牙在打開一次;
                        3、請檢查位置信息是否打開;
                        4、退出小程序重新掃碼進入。`,
                    showCancel: false,
                    confirmText: "我知道了",
                    success: () => {}
                })
            } 
        }, 30000)
    }
    
    /* 停止搜索 */
    stopBluetoothDevicesDiscovery() {
        uni.stopBluetoothDevicesDiscovery({
            complete: () => {
                _self.isStop = true;
            },
            success: (res) => {
                console.log("停止搜索成功")
            },
            fail: (res) => {
                console.log("停止失敗")
                uni.hideLoading();
            }
        })
    }
    
    /* 連接低功耗藍牙 */
    connectDevice(deviceId) {
        console.log("執行到這里了")
        uni.createBLEConnection({
            deviceId, //點擊的DeviceId
            timeout: 5000,
            success: (res) => {
                console.log("連接成功")
                _self.deviceId = deviceId;
                /* 這邊獲取全部的服務,並篩選出當前需要的*/
                _self.getBLEDeviceServices(deviceId)
    
            },
            fail: (error) => {
                /* 連接失敗 */
                uni.hideLoading();
                console.log("連接失敗")
                console.log(error);
                uni.showModal({
                    title: '藍牙連接失敗了哦',
                    content: `
                        1、請查看周圍是否有連接此設備的藍牙;
                        2、請先關閉手機藍牙在打開一次;
                        3、請檢查位置信息是否打開;
                        4、退出小程序重新掃碼進入。`,
                    showCancel: false,
                    confirmText: "我知道了",
                    success: () => {}
                })
            }
        })
        /* 監聽藍牙設備的連接狀態 */
        uni.onBLEConnectionStateChange(function(res) {
            console.log(res.deviceId + "連接狀態:" + res.connected)
        })
    }
    
    /* 獲取所有的服務*/
    getBLEDeviceServices(deviceId) {
        console.log("開始獲取服務")
        //連接成功之后需要延時,繼續操作才不會出問題,延時時間短一點都沒關系,我這邊用了1秒
        setTimeout(() => {
            uni.getBLEDeviceServices({
                // 這里的 deviceId 需要已經通過 createBLEConnection 與對應設備建立鏈接
                deviceId,
                success: (res) => {
                    console.log('device services:', res)
                    res.services.forEach((item) => {
                        //這里微信小程序獲取的服務ID是大寫,支付寶是小寫,所以統一轉換為大寫
                        let serviceId = item.uuid.toUpperCase();
 
                        if (serviceId == _self.UUID_SERVICE) {
                            console.log('serverId:', serviceId)
                            /* 進入特征值 */
                            _self.getBLEDeviceCharacteristics(deviceId, serviceId);
                        }
                    })
                },
                fail: (error) => {
                    console.log("獲取服務失敗")
                    console.log(error)
                    uni.hideLoading();
                }
            })
        }, 1000)
    }
 
    /* 獲取所有特征值 */
    getBLEDeviceCharacteristics(deviceId, serviceId) {
        console.log("開始獲取特征")
        setTimeout(() => {
            uni.getBLEDeviceCharacteristics({
                deviceId,
                serviceId,
                success: (res) => {
                    console.log(res)
                    res.characteristics.forEach((item) => {
                        console.log(item)
                        //這里跟服務ID一樣,支付寶需要轉換為大寫
                        //#ifdef MP-ALIPAY
                        let characterId = item.characteristicId.toUpperCase();
                        //#endif
                        //#ifdef MP-WEIXIN
                        let characterId = item.uuid;
                        //#endif
                        /* 只要用到的喚醒即可 */
                        if (characterId == _self.UUID_CHAR) {
                            console.log('characteristicId:', characterId)
                            _self.notifyBLECharacteristicValueChange(deviceId, serviceId, characterId)
                        }
                    })
                },
                fail: (res) => {
                    uni.hideLoading();
                    console.log(res)
                }
            })
        }, 1000)
    }
    /* 啟用藍牙設備特征值變化時的 notify 功能 */
    notifyBLECharacteristicValueChange(deviceId, serviceId, characteristicId) {
        console.log("開始喚醒")
        uni.notifyBLECharacteristicValueChange({
            state: true, // 啟用 notify 功能
            // 這里的 deviceId 需要已經通過 createBLEConnection 與對應設備建立鏈接
            deviceId,
            // 這里的 serviceId 需要在 getBLEDeviceServices 接口中獲取
            serviceId,
            // 這里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中獲取
            characteristicId,
            success: (res) => {
                uni.hideLoading();
                /* 連接成功 */
                uni.showToast({
                    title: "連接成功",
                    icon: 'success'
                });
                //儲存藍牙連接狀態
                store.commit('updateStatus', true);
                
                console.log('notifyBLECharacteristicValueChange success', res.errMsg)
                /* 連接成功以后,執行設置的操作,並且打開返回值的監聽開關並監聽 */
                //獲取設備信息
                let DeviceCommand = "01,02,03,04," + func("01020304") + ",1E";
                let DeviceArrayBuffer = string2buffer(DeviceCommand);
                _self.writeDevice(DeviceArrayBuffer);
                
                //出貨后關門延時設置
                let delayedCommand = "01,02,03,04,0A," + func("010203040A") + ",1E";
                let delayedArrayBuffer = string2buffer(delayedCommand);
                _self.writeDevice(delayedArrayBuffer);
 
                /* 監聽低功耗藍牙設備的特征值變化 */
                uni.onBLECharacteristicValueChange(function(CALLBACK) {
                    let result = blueTool.ab2hex(CALLBACK.value);
                    console.log("收到的數據值==", result);
                    // 這里做一些具體的業務邏輯
                    //我這里是監聽低功耗藍牙設備的特征值變化,然后調后台接口獲取設備的電量,展示在頁面
                    if ("73080182" === result.substring(0, 8)) {
                        var o = result.substring(8, 10);
                        o = parseInt(o, 16);
                        let dl = "";
                        if (o >= 41) {
                            dl = 100;
                        } else if (o <= 37) {
                            dl = 0;
                        } else {
                            dl = (o - 37) * 100 / (41 - 37);
                        }
                        //獲取設備電量
                        uni.request({
                            url:  baseUrl+"/api/*****",
                            method: "POST",
                            data: {
                                key: value
                            },
                            header: {
                                "Content-Type": "application/x-www-form-urlencoded"
                            },
                            success: function(t) {
                                store.commit('setDeviceBattery', t.data.data);
                                console.log("設備上傳回調" + JSON.stringify(t.data));
                            },
                            fail: function(t) {}
                        });
                    }
                })
            },
            fail: (res) => {
                uni.hideLoading();
                console.log('notifyBLECharacteristicValueChange success', res.errMsg)
            }
        })
    }
    /* 執行寫入命令操作 */
    writeDevice(_Buffer) {
            uni.writeBLECharacteristicValue({
                deviceId: _self.deviceId,
                serviceId: _self.UUID_SERVICE,
                characteristicId: _self.UUID_CHAR,
                value: _Buffer,
                success: (res) => {
                    /* 發送成功 */
                    console.log('最后一次寫入成功', res)
                },
                fail: (error) => {
                    /* 發送失敗 */
                    console.log('最后一次寫入失敗', error)
                }
            })
    }
    
    /* 獲取本機藍牙適配器狀態 */
    getBluetoothState() {
        uni.getBluetoothAdapterState({
            success: (res) => {
                console.log("狀態" + JSON.stringify(res))
            }
        })
    }
    
    /* 關閉藍牙適配器*/
    closeBlueAdapter() {
        uni.closeBluetoothAdapter({
            success() {
                console.log("關閉藍牙適配器成功")
            }
        })
    }
    
    /* 斷開低功耗藍牙的連接 */
    disconnectBle() {
        uni.closeBLEConnection({
            deviceId: _self.deviceId,
            success: (res) => {
                console.log("斷開成功" + res)
                store.commit('updateStatus', false);
                store.commit('setDeviceBattery', 0);
            }
        })
    }, 
 
    /* 具體的命令BCC校驗*/
    func(t) {
        for (var e = t, a = [], i = 0; i < e.length - 1; i += 2) a.push(e.substring(i, i + 2));
        for (var o = a[0], s = 0; s < a.length - 1; s++) o ^= a[s + 1];
        return o;
    },
 
    /* 字符串轉arraybuffer */
    string2buffer: function(str) {
        // 首先將字符串轉為16進制
        let val = str
        console.log(val)
        // 將16進制轉化為ArrayBuffer
        return new Uint8Array(val.match(/[\da-f]{2}/gi).map(function(h) {
            return parseInt(h, 16)
        })).buffer
    },
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM