// 安卓平台上,在调用 notifyBLECharacteristicValueChange 成功后立即调用 writeBLECharacteristicValue 接口,在部分机型上会发生 10008 系统错误 var app = getApp() const cmd = { heartBeat: 'heart', // 心跳包 unlock: 'openBike', // 开锁命令 lock: 'lock', // 开锁命令 bell: 'bellBike', // 关锁命令 temporaryUnlockBike: 'temporaryUnlockBike', // 关锁命令 temporaryLockBike: 'temporaryLockBike', // 关锁命令 batteryUnlock: 'batteryUnlock', // 关锁命令 batteryLock: 'batteryLock', // 关锁命令 // login: 'login', // 关锁命令 status: 'status', // 关锁命令 } const errorCode = { no_connection: 10006, //失去连接 no_service: 10004, //没有找到指定服务 apdater_no_avilable: 10001, //当前蓝牙适配器不可用 discovery_timeOut: 1100, //扫描失败 connet_timeOut: 10003 //连接超时 } let util = require('../utils/bluUtil.js') let dataTransition = require('../utils/dataTransition.js') class BluetoothManager { constructor() { this._connectDeviceName = 'shanxiango' this._isFoundDevice = false this._deviceId = '' this._serviceId = '' this._bikeMainId = '' this._mac='', this._sequenceId = 10 this._characteristicId = '' this._characteristicId_write = '' this._discovering = false this.discoveryTimeOut = 10 * 1000 this.isConnecting = false this.isAuth = false this.connnectTimeOut = 5 * 1000 //连接超时时间 this.hardwareCallbackTimeOut = 5 * 1000 //硬件回调超时时间 this.adapterStateChangeCallBack = undefined this.onConnectionStateChange = undefined this.heartTimer = '' // 处理接受数据 this._receiveLength = 0 this._receiveData = '' // this.initialNotification() this.readyStopDiscovery = false //标记准备关闭扫描 } /*******初始化各种回调**********/ initialNotification() { console.log('initialNotification') // this.getConnectedBluetoothDevices() // 监听蓝牙适配器状态改变 wx.onBluetoothAdapterStateChange( res => { console.log('onBluetoothAdapterStateChange', res) if (this.adapterStateChangeCallBack) { this.adapterStateChangeCallBack(res) } if(res.available==false){ this.isConnecting = false } } ) // // 监听扫描到的设备 wx.onBluetoothDeviceFound( res => { console.log('监听扫描到的设备') if (this._isFoundDevice){ return } for (var i = 0; i < res.devices.length; i++) { const device = res.devices[i]; var name = device.name if (name === 'shanxiango') { if (device.localName != name) return; if (name != this._connectDeviceName) return; let bf = device.advertisData.slice(2, 10); var abc = util.ab2hex(bf) let contentArr = util.strAverage2Arr(abc, 2) contentArr.reverse(); var string = contentArr.join('').toUpperCase() //mac地址 console.log(string,'Mead===>',res.devices[i],this._mac) if (!this._isFoundDevice && name == this._connectDeviceName) { // 获取车辆中控编号 console.log(this._mac) if (string == this._mac) { console.log('-------found ---', device.name, string) this._isFoundDevice = true this._deviceId = device.deviceId if (this.deviceFoundBlock) { this.deviceFoundBlock(device.deviceId) } break return } } } } } ) // 监听蓝牙连接状态 wx.onBLEConnectionStateChange( res => { console.log(res) console.log('监听蓝牙连接状态', res, this._deviceId) this.isConnecting = res.connected if (res.deviceId == this._deviceId && res.connected == false) { console.log('onBLEConnectionStateChange fail', this._connectionFailBlock); if (this._connectionFailBlock) { // wx.showModal({ // title: '提示', // content: '蓝牙连接超时', // showCancel: false // }) wx.hideLoading() this._connectionFailBlock(res) this._connectionFailBlock = undefined } if (this.onConnectionStateChange) { this.onConnectionStateChange(res) } wx.closeBLEConnection({ deviceId: this._deviceId, success: function (res) { console.log('closeBLEConnection', res) }, }) } } ) // 监听特征值变化 wx.onBLECharacteristicValueChange( characteristic => { console.log('监听特征值变化', characteristic) if (characteristic.value) { let res = characteristic.value let resData = util.ab2hex(res.value); if (this._receiveLength == 0) { this._receiveLength = parseInt(resData.slice(8, 12), 16) } this._receiveData += resData if (this._receiveData.length === (this._receiveLength * 2 + 16)) { let _receiveData = this._receiveData console.log(_receiveData, '_receiveData') let flay = _receiveData.slice(0, 4) let crc16 = _receiveData.slice(12, 16); let systemState = _receiveData.slice(4, 6); //4c let sequenceId_16 = _receiveData.slice(6, 8); //0a let body = _receiveData.slice(16) let contentArr = util.addFlagBeforeArr(util.strAverage2Arr(body, 2)); //校检数据 if (parseInt(dataTransition.getCRC16(contentArr), 16) == parseInt(crc16, 16)) { let value = util.hexStringToArrayBuffer(`aa12${systemState}${sequenceId_16}00000000`); if (flay === 'aa10') { if (body.indexOf('aa10550b') > -1) { if (this.getRandomSuccessBlock) { this.getRandomSuccessBlock(body) this.getRandomSuccessBlock = undefined } } console.log('指令发送成功', body) } else if (flay === 'aa00') {} else if (flay === 'aa30') { console.log('校检错误') } else { // this.writeBLECharacteristicValue(value) // that.analysisBLEContent(body) } } // 返回ACK this._receiveLength = 0 this._receiveData = '' } } } ) } failToGetConnected() { var that = this; if (!that.getConnectedTimer) { clearTimeout(that.getConnectedTimer); that.getConnectedTimer = null; } that.getConnectedTimer = setTimeout(function () { wx.getBluetoothAdapterState({ success: function (res) { console.log(res); var available = res.available; if (!available) { wx.showLoading({ title: '请开蓝牙', icon: 'loading', duration: 2000 }) } else { if (!that.connectedDevice['state']) { that.getConnectedBluetoothDevices(); } } }, fail: function (err) { console.log(err); } }) }, 5000); } /***********初始化接口***************/ connectDeivece(bikeMainId, command = false) { console.log(this.isConnecting,this._bikeMainId,bikeMainId,cmd) if (this.isConnecting && bikeMainId == this._bikeMainId ){ if (command == cmd.unlock) { return this.unlockBike() } else if (command == cmd.lock) { return this.lockBike() } else if (command == cmd.bell) { return this.play_voice() } else if (command == cmd.batteryUnlock) { return this.diankai() } return } else{ if (this._deviceId) { this.closeConnection(this._deviceId) } } this._bikeMainId = bikeMainId //当前车辆编号 // 初始化蓝牙 this.initialNotification() return this.openAdapter().then(res=>{ return this.getSecretKey() }).then(res => { return this.startDiscovery() }).then( res => { console.log('startDiscovery---------') this._discovering = true // 等待发现设备 return this.waitForDeviceFound() }, reject => { console.log(reject) } ).then( res => { console.log('stopDiscovery---------') this.readyStopDiscovery = true //关闭扫描 return this.stopDiscovery() } ).then( res => { this.readyStopDiscovery = false this._discovering = false console.log('createConnection---------', res) //开始连接设备 console.log(this._deviceId) return this.createConnection(this._deviceId) } ).then( res => { console.log('getServices---------', res) // 获取服务 return this.getServices(this._deviceId) } ).then( res => { console.log('getCharacteristics---------', res) // 获取特征值 return this.getCharacteristics(this._deviceId, this._serviceId) } ).then( res => { console.log('openNotifyChsValueChange---------', res) // 开启notify通道 console.log('开启notify通道') console.log(this._deviceId, '=>', this._serviceId, '<++', this._characteristicId) return this.openNotifyChsValueChange(this._deviceId, this._serviceId, this._characteristicId) } ).then( res => { return this.onBLECharacteristicValueChange() } ).then( res => { if (command == cmd.unlock) { return this.unlockBike() } else if (command == cmd.lock) { return this.lockBike() } else if (command == cmd.bell) { return this.play_voice() } else if (command == cmd.batteryUnlock) { return this.diankai() } return } ) } // 监听特征值变化 onBLECharacteristicValueChange() { let that = this wx.onBLECharacteristicValueChange( characteristic => { console.log('onBLECharacteristicValueChange', characteristic) if (characteristic.value) { let res = characteristic.value let resData = util.ab2hex(res); if (this._receiveLength == 0) { this._receiveLength = parseInt(resData.slice(8, 12), 16) } this._receiveData += resData if (this._receiveData.length === (this._receiveLength * 2 + 16)) { let _receiveData = this._receiveData console.log(_receiveData) let flay = _receiveData.slice(0, 4) let crc16 = _receiveData.slice(12, 16); let systemState = _receiveData.slice(4, 6); //4c let sequenceId_16 = _receiveData.slice(6, 8); //0a let dcArr = []; let body = _receiveData.slice(16) let contentArr = util.addFlagBeforeArr(util.strAverage2Arr(body, 2)); //校检数据 if (parseInt(dataTransition.getCRC16(contentArr), 16) == parseInt(crc16, 16)) { let response = util.hexStringToArrayBuffer(`aa12${systemState}${sequenceId_16}00000000`); if (flay === 'aa10') { console.log(this.getRandomSuccessBlock, 'getRandomSuccessBlock') if (this.getRandomSuccessBlock) { this.getRandomSuccessBlock(body) this.getRandomSuccessBlock = undefined } console.log('指令发送成功', body) } else if (flay === 'aa00') {} else if (flay === 'aa30') { console.log('CRC校验失败', body); } else { //响应数据 // that.writeBLECharacteristicValue(response, undefined) // that.analysisBLEContent(body) } } this._receiveLength = 0 this._receiveData = '' } } } ) } //获取秘钥 getSecretKey(box_no) { if (!box_no) box_no = this._bikeMainId let that = this; if(box_no== wx.getStorageSync('box_no')) return; return new Promise(function (res, rej) { let param = { box_no: box_no, //我公司是通过设备编号获取的密钥 }; app.request('/blu/get-key',param,'GET').then(resp=>{ that._mac = resp.data.key res(resp.data.key); wx.setStorageSync('box_no', box_no) }) }); } waitForDeviceFound() { return new Promise( (resolve, reject) => { this.deviceFoundBlock = resolve console.log('waitForDeviceFound ----') console.log(this._discovering, '<==>', !this._isFoundDevice) setTimeout(() => { console.log('waitForDeviceFound ++++', this._discovering, this._isFoundDevice) // 全局断了,_discovering 变为false(发心跳包失败,closeApater引起) console.log(this._discovering, '==>', !this._isFoundDevice) if (this._discovering && !this._isFoundDevice) { console.log('waitForDeviceFound 扫描超时00', 'isconnecting :', this.isConnecting) reject({ errCode: errorCode.discovery_timeOut }) } if (this._discovering) { this.stopDiscovery() } }, this.discoveryTimeOut); } ) } disconnecDevice() { return this.closeConnection(this._deviceId).then( res => { return this.closeAdapter() } ) } /***********初始化接口***************/ /***********蓝牙处理*************/ // 打开适配器 openAdapter() { console.log('打开适配器') return new Promise( (resolve, reject) => { wx.openBluetoothAdapter({ success: resolve, fail: reject }) } ) } // 关闭适配器 closeAdapter() { console.log('关闭适配器') this._isFoundDevice = false this._discovering = false this.isConnecting = false this.adapterStateChangeCallBack = undefined this.onConnectionStateChange = undefined return new Promise( (resolve, reject) => { this.isOpenAdpater = false this.isConnecting = false wx.closeBluetoothAdapter({ success: resolve, fail: reject }) } ) } // 开启扫描 startDiscovery() { console.log('开启扫描') return new Promise( (resolve, reject) => { wx.startBluetoothDevicesDiscovery({ services: ['FFF0'], allowDuplicatesKey: true, success: resolve, fail: reject }) } ) } // 关闭扫描 stopDiscovery() { console.log('关闭扫描') this._isFoundDevice = false return new Promise( (resolve, reject) => { wx.stopBluetoothDevicesDiscovery({ success: resolve, fail: reject }) } ) } // 创建连接 createConnection(deviceId) { console.log('创建连接') return new Promise( (resolve, reject) => { this._connectionFailBlock = undefined this._connectionFailBlock = reject // this._needToToastConnectError = true console.log(deviceId) console.log(this.connnectTimeOut) wx.createBLEConnection({ deviceId: deviceId, // timeout: this.connnectTimeOut, success: res => { console.log('--------createConnection success', res) // 创建成果并不代表发指令成功,有可能连接连接创建成功了,但是发指令的时候连接中断了 resolve(res) }, fail: error => { console.log('--------createConnection fail', error) this._connectionFailBlock = undefined reject(error) } }) } ) } // 关闭连接 closeConnection(deviceId) { console.log('关闭连接') return new Promise( (resolve, reject) => { wx.closeBLEConnection({ deviceId: deviceId, success: resolve, fail: reject }) } ) } // 获取服务 getServices(deviceId) { console.log('获取服务') let that = this return new Promise( (resolve, reject) => { this._connectionFailBlock = undefined this._connectionFailBlock = reject wx.getBLEDeviceServices({ deviceId: deviceId, success: res => { console.log('getServices success', res) if (res.errCode === 0) { res.services.forEach(function (value, index, array) { console.log("设备所有的UUId", value.uuid); if (value.uuid.indexOf(that._serviceId) > -1) { //找到serviceId包含FEF6的服务 that._serviceId = array[index].uuid; // resolve(serviceId) } }) } resolve(res) }, fail: error => { console.log('getServices fail', error) reject(error) } }) } ) } // 获取特征值 getCharacteristics(deviceId, serviceId) { console.log('获取特征值') let that = this return new Promise( (resolve, reject) => { this._connectionFailBlock = undefined this._connectionFailBlock = reject wx.getBLEDeviceCharacteristics({ deviceId: deviceId, serviceId: serviceId, success: res => { console.log('getCharacteristics success', res) for (let i = 0; i < res.characteristics.length; i++) { if (res.characteristics[i].properties.notify && !res.characteristics[i].properties.write) that._characteristicId = res.characteristics[i].uuid; //读的uuid if (res.characteristics[i].properties.write) that._characteristicId_write = res.characteristics[i].uuid; //写的uuid } resolve(res) }, fail: error => { console.log('getCharacteristics fail', error) reject(error) } }) } ) } // 开启notify功能,订阅特征值 openNotifyChsValueChange(deviceId, serviceId, characteristicId) { let that = this return new Promise( (resolve, reject) => { this._connectionFailBlock = undefined this._connectionFailBlock = reject wx.notifyBLECharacteristicValueChange({ deviceId: deviceId, serviceId: serviceId, characteristicId: characteristicId, state: true, success: res => { console.log('openNotifyChsValueChange success', res) resolve(res) }, fail: error => { console.log('openNotifyChsValueChange fail', error) reject(error) } }) } ) } /***********蓝牙处理*************/ /*********action**********/ // //获取随机数 // getRandom() { // return new Promise( // (resolve, reject) => { // console.log('---getRandom---') // // this.sendCommand(cmd.status, undefined, reject); // // this.unlockBike() // this.getRandomSuccessBlock = resolve // setTimeout( // () => { // console.log('---getRandom-超时回调ing--', ) // if (this.getRandomSuccessBlock) { // console.log('---getRandom-超时了--') // this.getRandomSuccessBlock = undefined // reject({ // errMsg: '硬件校验超时' // }) // } // }, this.hardwareCallbackTimeOut // ) // } // ) // } // bellBike() { // return new Promise( // (resolve, reject) => { // // this.sendCommand(0x11, this.randomArray); // this.bellSuccessBlock = resolve // // this.sendCommand(cmd.bell, '', reject); // setTimeout( // () => { // console.log('---bellBike-超时回调') // if (this.bellSuccessBlock) { // this.bellSuccessBlock = undefined // console.log('---bellBike-超时了--') // reject({ // errCode: errorCode.connet_timeOut, // errMsg: '寻铃超时' // }) // } // }, this.hardwareCallbackTimeOut // ) // } // ) // } //开锁 unlockBike() { var key2 = ['0x42', '0x44', '0x00', '0x01', '0x0A', '0x0A', '0x05', '0x05', '0x02', '0x01', '0x01'] let value = util.CRC(key2) console.log(value) var value1 = '424400010A0A0505020101' + value console.log(value1) this.writeBLECharacteristicValue(util.hexStringToArrayBuffer(value1), '123') //播放语音 var key5 = ['0x42', '0x44', '0x00', '0x01', '0x0A', '0x0A', '0x05', '0x05', '0x0A', '0x07', '0x01', '0x02', '0x00', '0x00', '0x00', '0x00', '0x00'] let value2 = util.CRC(key5) var value3 = '424400010A0A05050A0701020000000000' + value2 this.writeBLECharacteristicValue(util.hexStringToArrayBuffer(value3), '123') } //发送关锁指令 lockBike() { var key2 = ['0x42', '0x44', '0x00', '0x01', '0x0A', '0x0A', '0x05', '0x05', '0x02', '0x01', '0x02'] let value = util.CRC(key2) console.log(value) var value1 = '424400010A0A0505020102' + value console.log(value1) this.writeBLECharacteristicValue(util.hexStringToArrayBuffer(value1)) //播放语音 var key5 = ['0x42', '0x44', '0x00', '0x01', '0x0A', '0x0A', '0x05', '0x05', '0x0A', '0x07', '0x01', '0x01', '0x00', '0x00', '0x00', '0x00', '0x00'] let value2 = util.CRC(key5) var value3 = '424400010A0A05050A0701010000000000' + value2 this.writeBLECharacteristicValue(util.hexStringToArrayBuffer(value3)) } play_voice() { var key5 = ['0x42', '0x44', '0x00', '0x01', '0x0A', '0x0A', '0x05', '0x05', '0x0A', '0x07', '0x01', '0x09', '0x00', '0x00', '0x00', '0x00', '0x00'] let value = util.CRC(key5) console.log(value) var value1 = '424400010A0A05050A0701090000000000' + value console.log(value1) this.writeBLECharacteristicValue(util.hexStringToArrayBuffer(value1)) } diankai() { var key3 = ['0x42', '0x44', '0x00', '0x01', '0x0A', '0x0A', '0x05', '0x05', '0x05', '0x01', '0x01'] let value = util.CRC(key3) console.log(value) var value1 = '424400010A0A0505050101' + value console.log(value1) this.writeBLECharacteristicValue(util.hexStringToArrayBuffer(value1)) } // 发送心跳包 // heartBeat() { // console.log('发送心跳包') // let that = this // return new Promise( // (resolve, reject) => { // console.log(resolve) // console.log(reject) // that.heartSuccessBlock = resolve // that.heartTimer = setTimeout( // () => { // if (that.heartSuccessBlock) { // var key2 = ['0x42', '0x44', '0x00', '0x01', '0x0A', '0x0A', '0x05', '0x05', '0x01', '0x00'] // let value = util.CRC(key2) // var value1 = '424400010A0A05050100' + value // // this.writeBLECharacteristicValue(util.hexStringToArrayBuffer(value1)) // var key5 = ['0x42', '0x44', '0x00', '0x01', '0x0A', '0x0A', '0x05', '0x05', '0x0A', '0x07', '0x01', '0x01', '0x00', '0x00', '0x00', '0x00', '0x00'] // let value2 = util.CRC(key5) // var value3 = '424400010A0A05050A0701010000000000' + value2 // // this.writeBLECharacteristicValue(util.hexStringToArrayBuffer(value3)) // that.heartSuccessBlock = undefined // reject({ // errCode: errorCode.connet_timeOut, // errMsg: '超时' // }) // } // }, 30 * 1000 // ) // } // ) // } /*********action**********/ /*******util*********/ //发送指令 // sendCommand(commandCode, dataArray, reject) { // let data = this.generateCommandData(commandCode, dataArray); // this._connectionFailBlock = undefined // this._connectionFailBlock = reject // var dataLen = Math.ceil(data.length / 40); // console.log(dataLen, 'datalen') // if (dataLen > 1) { //3 // for (let i = 0; i < data.length; i += 40) { // let value = util.hexStringToArrayBuffer(data.slice(i, i + 40)); // console.log("分包发送的数据", data.slice(i, i + 40)) // //使用了重发机制,在此不做定时处理 // // this.writeBLECharacteristicValue(value, reject); // } // } else { // let value = util.hexStringToArrayBuffer(data); // console.log(value) // // this.writeBLECharacteristicValue(value, reject); // } // } //发送数据 writeBLECharacteristicValue(data, reject) { console.log(this._deviceId, this._serviceId, this._characteristicId_write, '发送参数') wx.writeBLECharacteristicValue({ deviceId: this._deviceId, serviceId: this._serviceId, characteristicId: this._characteristicId_write, value: data, success: res => { console.log('writeBLECharacteristicValue success', res) }, fail: err => { console.log('writeBLECharacteristicValue fail', err, this._deviceId, this._serviceId, this._characteristicId) // if(){ this.isConnecting = false; // } reject(err) this.closeConnection(this._deviceId) } }) } /** * 根据指令码生成指令帧数据 * commandCode --> 指令码 * array --> 额为携带的数据 */ // generateCommandData(commandCode, array) { // let sequenceId_16 = dataTransition.getSequenceId(this._sequenceId); // // this._sequenceId++; // let sendData = ''; // console.log(commandCode) // // console.log(sequenceId_16) // switch (commandCode) { // case cmd.unlock: // sendData = '03 00 02 01 00'; // break // case cmd.lock: // sendData = '03 00 01 01 01'; // break; // case cmd.bell: // sendData = '03 00 04 01 01'; // break; // case cmd.batteryUnlock: // sendData = '03 00 05 01 01'; // break; // case cmd.batteryLock: // sendData = '03 00 05 01 00'; // break; // case cmd.temporaryUnlockBike: // sendData = '03 00 02 01 00 07 01 01'; // break // case cmd.temporaryLockBike: // sendData = '03 00 07 01 08'; // break; // // case cmd.login: // // // let secretKey = array.key.toString().trim().toLowerCase(); // // console.log(secretKey) // // // let c = secretKey.toString().replace(/\s+/g, ""); // // // let cLength = dataTransition.getSecretKeyLength(c); // // //发送内容 // // let send = `02 00 01`; //02 连接命令 01连接请求 cLength秘钥长度。 // // sendData = `${send} ${secretKey}`; // // console.log(sendData, 'sendValue') // // break; // case cmd.status: // sendData = '42 44 00 01 0A 0A 05 05' // console.log(sendData) // break // case cmd.ack: // sendData = array.data // break; // } // let header = dataTransition.header(sendData); // console.log(header) // if (commandCode == 'responseAck') { // header = '' // } // let data = header + sendData.replace(/\s+/g, ""); // console.log(data) // console.log(`发送${commandCode}指令`, data); // return data; // } /*******util*********/ } // export { // BluetoothManager // } module.exports = { BluetoothManager: BluetoothManager, BtErrorCode: errorCode, CMD:cmd }