为了简化微信小程序环境下的蓝牙接入流程,通过线上正式我的项目一年的运行,发现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