In order to simplify the Bluetooth access process under the WeChat small program environment, after one year’s operation of the online formal project, we found that BLE API has many holes and is difficult to transplant and reuse, so we encapsulated it to improve the maintainability and portability.

How to use

Install Eventenitter

npm install eventemitter2 --save

The introduction of

Js, blehandler.js, tools.js, error.js. After doing the above steps, you can use Bluetooth functionality directly in your applet. ✨

The sample

const emitter = new EventEmitter2(); Const ble = new ble (blename, Emitter) ble. Listen (res => {if (res.type == 'connect') {switch(res.data){case "adapter not open" : Break case "bluetooth connected" : break case "" break}}else if (res.type == "response") {console.log(' Recall device message response: ', res) //TODO } }) ble.init()

Implementation details

Use method as above, very simple, only need to maintain a global BLE instance, you can carry out the various functions of Bluetooth operation. What are the files introduced in Part 2 for? Generally, the Bluetooth connection, communication, maintenance process is divided into three layers according to the complexity of the function: BLE, BLEHandler, Tool, BLE is more inclined to the user layer, BLEHandler provides some flow control, Tool is completely encapsulated WeChat API, isolation of some complicated work, so that the code looks simpler.

The source code parsing

import BLEHandler from "./bleHandler" class BLE extends BLEHandler { constructor(blename, emitter) { super(blename, Emitter)} listen (the callback) {/ / bluetooth event registration, open channel enclosing emitter. RemoveAllListeners (" channel "). This emitter. On (" channel ", The callback)} removeListen () {/ / remove all this bluetooth events. The emitter. RemoveAllListeners (" channel ")} async init () {let flow = false / / Open the bluetooth adapter state to monitor this. OnBLEConnectionStateChange () / / bluetooth adapter initialization await this. OpenAdapter () / / search bluetooth await this. StartSearch () Await this.onBluetoothFound() // await this.stopSearchBluetooth() if (! Return // await this.connectBlue(); await this.connectBlue(); "Await this.getServices ()" // await this.getServices (); "await this.getServices ()"; / / subscribe eigenvalue await this. NotifyBLECharacteristicValueChange () / / open the deliver surveillance, Wait for equipment feedback data enclosing onBLECharacteristicValueChange ()} / / send instructions async send (mudata, cmd) { let flow = await this.sentOrder(mudata, cmd) return flow } async close() { await this.closeBLEConnection() await this.closeBLEAdapter() } } export { BLE };

BLEHandler (encapsulation of Promise, and control of EventEnitter communication)

import * as t from "./tools" import { HTTP } from ".. /server"; /** * class * Enables a small program to process a Bluetooth process */ class bleHandler {constructor(); 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: "adapter not open"}) 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. closeBleLeadapter () 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: }) // Unconnect this. closeBleConnection () this. closeBleLeadapter () wx.setStorageSync(" Bluestatus ", ""); return; } return true } async notifyBLECharacteristicValueChange() { let [err, res] = await t._notifyBLECharacteristicValueChange.call(this); if (err ! = null) {// Unconnect this.emitter.emit("channel", {type: "connect", data: }) this. closeBleConnection () this. closeBleLeadapter () wx.setStorageSync(" Bluestatus ", ""); return; } this. Emitter. Emit ("channel", {type: "connect", data: "bluetooth connected"}) 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("-- send data :", data) let arrayBuffer = new Uint8Array(data).buffer; let [err, res] = await t._writeBLECharacteristicValue.call(this, arrayBuffer) if (err ! = null) {return} return true} / / open the bluetooth adapter state monitor onBLEConnectionStateChange () {wx. OnBLEConnectionStateChange (res = > {/ / This method callback can be used to handle abnormal situations such as an unexpected disconnect if (! res.connected) { this.closeBLEAdapter() wx.setStorageSync("bluestatus", ""); this.emitter.emit("channel", { type: "connect", data: "Bluetooth disconnected"})}}, err => {console.log('err', Err)})} / / receiving equipment push notification onBLECharacteristicValueChange () {wx. OnBLECharacteristicValueChange (res = > {let arrbf = new Uint8Array(res.value) console.log(" Uint8Array(res.value) ") ",arrbf) console.log(" timestamp ",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('-- throttle 900ms,Lock! ') this.lastDate = nowDate this._uploadInfo(arrbf) this.emitter.emit("channel", { type: "response", data: Arrbf})}}}})} _uploadInfo(message) {console.log("-- ready for data synchronization!" , 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(" Configure data sync successfully!" - - Data synchronization failed)}, err = bb0 {consol. log(' Data synchronization failed ', 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] ! - - No match between frame heads and tails, Please resend ') to the console. The log (' frame head: 'arrbf [0]) to the console. The log (' frame head:' arrbf [1]) to the console. The log (' tail frame: ' Arrbf [arrbf.length-1]) console.log(' frame tail :', arrbf[arrbf.length-1]) console.log(' frame tail :', Arrbf [arrbf.length-2]) return false} let CRC = t._modbuscrc16 (arrbf, 2, arrbf[arrbf.length-2]) return false} arrbf.length - 5) if (arrbf[arrbf.length - 3] ! = crc & 0xff && arrbf[arrbf.length - 4] ! - CRC - Check an error - = (CRC >> 8) & 0xFF) {consol. log(' - CRC Check an error, ') return false} let time = new Date().tolocaleTimeString () console.log(' Configure CRC Data Check Successful! ${arrbf[3] == 0 ? ':' command code: '+ arrbf[3]}, time:${time}') return true}} export default BLEHandler

The flow chart

The address of the project: https://github.com/arsize/ble