为了简化微信小程序环境下的蓝牙接入流程,通过线上正式我的项目一年的运行,发现BLE这块API许多坑,且难以移植复用,所以将它封装进去进步可维护性以及可移植性。

如何应用

装置Eventenitter

npm install eventemitter2 --save

引入

在我的项目根目录utils文件夹下增加如下文件:ble.js、bleHandler.js、tools.js、error.js
实现下面步骤,就能够间接在小程序中应用蓝牙性能了。✨

示例

const emitter = new EventEmitter2();const ble = new BLE(blename, emitter)ble.listen(res => {    if (res.type == 'connect') {    switch(res.data){        case "未关上适配器":        break      case "蓝牙已连贯":        break      case ""        break    }  }else if (res.type == "response") {     console.log('收到设施音讯响应:', res)    //TODO  }})ble.init()

实现细节

应用办法如上,很简略,只须要保护一个全局的ble实例,则能够进行蓝牙的各种性能操作。第二部引入的那几个文件是用来干嘛的呢?
大体上将蓝牙的连贯、通信、保护过程按性能的复杂程度分为三层:BLE、BLEHandler、Tool,ble更偏差用户层,blehandler提供一些流程性管制,tool则齐全是封装的微信API,隔离一些简约的工作,使代码看起来简洁一些。

源码解析

import BLEHandler from "./bleHandler"class BLE extends BLEHandler {    constructor(blename, emitter) {        super(blename, emitter)    }    listen(callback) {        // 蓝牙事件注册,关上channel        this.emitter.removeAllListeners("channel")        this.emitter.on("channel", callback)    }    removeListen() {        // 移除所有蓝牙事件        this.emitter.removeAllListeners("channel")    }    async init() {        let flow = false        // 关上蓝牙适配器状态监听        this.onBLEConnectionStateChange()        // 蓝牙适配器初始化        await this.openAdapter()        // 搜寻蓝牙设施        await this.startSearch()        // 获取设施ID        flow = await this.onBluetoothFound()        // 进行搜寻设施        await this.stopSearchBluetooth()        if (!flow) return        // 连贯蓝牙        await this.connectBlue();        // 获取serviceId        await this.getBLEServices()        // 设置特征值        await this.getCharacteristics();        // 订阅特征值        await this.notifyBLECharacteristicValueChange()        // 关上传输监听,期待设施反馈数据        this.onBLECharacteristicValueChange()    }    // 发送指令    async send(mudata, cmd) {        let flow = await this.sentOrder(mudata, cmd)        return flow    }    async close() {        await this.closeBLEConnection()        await this.closeBLEAdapter()    }}export { BLE };

BLEHandler(promise的封装,及Eventenitter通信管制)

import * as t from "./tools"import { HTTP } from "../server";/** * 蓝牙工具类 * 封装小程序蓝牙流程办法 * 处理事件通信 */class BLEHandler {    constructor(blename, emitter) {        this.blename = blename        this.emitter = emitter        this.readCharacteristicId = "";        this.writeCharacteristicId = "";        this.notifyCharacteristicId = "";        this.deviceId = "";        this.serviceId = "";        this.lastDate = new Date().getTime()    }    async openAdapter() {        let [err, res] = await t._openAdapter.call(this);        if (err != null) {            this.emitter.emit("channel", {                type: "connect",                data: "未关上适配器"            })            return;        }        return true    }    async startSearch() {        let [err, res] = await t._startSearch.call(this);        if (err != null) {            return;        }        this.emitter.emit("channel", {            type: "connect",            data: "蓝牙搜寻中"        })    }    async onBluetoothFound() {        let [err, res] = await t._onBluetoothFound.call(this);        if (err != null) {            this.emitter.emit("channel", {                type: "connect",                data: "未找到设施"            })            // 勾销适配器            this.closeBLEAdapter()            wx.setStorageSync("bluestatus", "");            return;        }        this.emitter.emit("channel", {            type: "connect",            data: "正在连接中"        })        return true    }    async stopSearchBluetooth() {        let [err, res] = await t._stopSearchBluetooth.call(this);        if (err != null) {            return;        }    }    async connectBlue() {        let [err, res] = await t._connectBlue.call(this);        if (err != null) {            return;        }    }    async getBLEServices() {        let [err, res] = await t._getBLEServices.call(this);        if (err != null) {            return;        }    }    async getCharacteristics() {        let [err, res] = await t._getCharacteristics.call(this);        if (err != null) {            this.emitter.emit("channel", {                type: "connect",                data: "无奈订阅特征值"            })            // 勾销连贯            this.closeBLEConnection()            this.closeBLEAdapter()            wx.setStorageSync("bluestatus", "");            return;        }        return true    }    async notifyBLECharacteristicValueChange() {        let [err, res] = await t._notifyBLECharacteristicValueChange.call(this);        if (err != null) {            // 勾销连贯            this.emitter.emit("channel", {                type: "connect",                data: "无奈订阅特征值"            })            this.closeBLEConnection()            this.closeBLEAdapter()            wx.setStorageSync("bluestatus", "");            return;        }        this.emitter.emit("channel", {            type: "connect",            data: "蓝牙已连贯"        })        wx.setStorageSync("bluestatus", "on");        return true    }    async closeBLEConnection() {        let [err, res] = await t._closeBLEConnection.call(this);        if (err != null) {            return;        }    }    async closeBLEAdapter() {        let [err, res] = await t._closeBLEAdapter.call(this);        if (err != null) {            return;        }    }    async sentOrder(mudata, cmd) {        let data = t._sentOrder(mudata, cmd)        console.log("-- 发送数据:", data)        let arrayBuffer = new Uint8Array(data).buffer;        let [err, res] = await t._writeBLECharacteristicValue.call(this, arrayBuffer)        if (err != null) {            return        }        return true    }    // 关上蓝牙适配器状态监听    onBLEConnectionStateChange() {        wx.onBLEConnectionStateChange(res => {            // 该办法回调中能够用于解决连贯意外断开等异常情况            if (!res.connected) {                this.closeBLEAdapter()                wx.setStorageSync("bluestatus", "");                this.emitter.emit("channel", {                    type: "connect",                    data: "蓝牙已断开"                })            }        }, err => {            console.log('err', err)        })    }    // 收到设施推送的notification    onBLECharacteristicValueChange() {        wx.onBLECharacteristicValueChange(res => {            let arrbf = new Uint8Array(res.value)            console.log("收到上传数据:",arrbf)            console.log("工夫戳",new Date().getTime())            arrbf.map(res=>{                console.log(res)            })            if (this._checkData(arrbf)) {                if (arrbf[3] != 0x00) {                    let nowDate = new Date().getTime()                    if ((nowDate - this.lastDate) > 900) {                        console.log('-- 节流900ms,Lock!')                        this.lastDate = nowDate                        this._uploadInfo(arrbf)                        this.emitter.emit("channel", {                            type: "response",                            data: arrbf                        })                    }                }            }        })    }    _uploadInfo(message) {        console.log("-- 筹备数据同步!", this._mapToArray(message))        let bleorder = wx.getStorageSync("bleorder");        let blecabinet = wx.getStorageSync("blecabinet")        HTTP({            url: "cabinet/uploadBlueData",            methods: "post",            data: {                cabinetQrCode: blecabinet,                order: bleorder,                message: this._mapToArray(message)            }        }).then(res => {            console.log("✔ 数据同步胜利!")        }, err => {            console.log('✘ 数据同步失败', err)        })    }    _mapToArray(arrbf) {        let arr = []        arrbf.map(item => {            arr.push(item)        })        return arr    }    // 校验数据正确性    _checkData(arrbf) {        // 校验帧头帧尾        if (arrbf[0] != 0xEE || arrbf[1] != 0xFA || arrbf[arrbf.length - 1] != 0xFF || arrbf[arrbf.length - 2] != 0xFC) {            console.log('✘ 帧头帧尾不匹配,请重发')            console.log('帧头:', arrbf[0])            console.log('帧头:', arrbf[1])            console.log('帧尾:', arrbf[arrbf.length - 1])            console.log('帧尾:', arrbf[arrbf.length - 2])            return false        }        // 校验CRC        let crc = t._modBusCRC16(arrbf, 2, arrbf.length - 5)        if (arrbf[arrbf.length - 3] != crc & 0xff && arrbf[arrbf.length - 4] != (crc >> 8) & 0xff) {            console.log('✘ crc校验谬误,请重发')            return false        }        let time = new Date().toLocaleTimeString()        console.log(`✔ CRC数据校验胜利!${arrbf[3] == 0 ? '❤' : '命令码:' + arrbf[3]},time:${time}`)        return true    }}export default BLEHandler

流程图

我的项目地址:https://github.com/arsize/ble