最近做中铁的叉车项目包含了蓝牙开锁的功能,上周供应商发给我一块板子,大概就张这样子:
老实说刚看到这东西那是一脸懵逼,连电源线都不给我,怎么玩嘛。后面跟厂家沟通了几次,看了通信部分和硬件通电图,去买了个12V的电源给接上,直到今天调通蓝牙模块发送指令成功,嗯,还是有一些成就感的,接下来把代码贴上,留作纪念。
/* * @Description: In User Settings Edit * @Author: zhaoyulong * @Date: 2019-08-12 09:51:44 * @LastEditTime: 2019-08-19 15:59:21 * @LastEditors: Please set LastEditors */ import { buf2hex, getCommand // 获取开锁指令 // setSnCommand // 获取写入SN号指令 } from '@/utils' import { mapActions, mapState } from 'vuex' export default { computed: { ...mapState({ bluetoolthInfo: state => state.bluetoolthInfo, connected: state => state.bluetoolthInfo.connected, deviceId: state => state.bluetoolthInfo.deviceId, // 用于区分设备id - 设备物理地址(9C:A5:25:23:A4:E2) serviceId: state => state.bluetoolthInfo.serviceId, // 蓝牙特征值对应服务的 uuid characteristicId: state => state.bluetoolthInfo.characteristicId, // 订阅蓝牙特征值uuid(notify) writeCharacteristicId: state => state.bluetoolthInfo.writeCharacteristicId // 写入特征值uuid(write) }) }, data: { // connected: false, // 是否已经连接上蓝牙设备 searching: '', // 设备是否可搜索 devicesList: [], // 设备列表 connectDeviceIndex: 0, // 连接设备的次数 // deviceId: '', // 用于区分设备id - 设备物理地址(9C:A5:25:23:A4:E2) // serviceId: '', // 蓝牙特征值对应服务的 uuid // characteristicId: '', // 订阅蓝牙特征值uuid(notify) // writeCharacteristicId: '', // 写入特征值uuid(write) getConnectedTimer: undefined, // 计时器-获取已连接的蓝牙设备 discoveryDevicesTimer: undefined, // 计时器-搜寻附件设备 timerOpen: undefined, // 循环获取开锁结果 openBluetoothSuccess: false, // 蓝牙开锁是否成功 bluetoothName: '' }, methods: { ...mapActions([ 'setBluetoolthInfo' // 设置蓝牙信息 ]), /** * @author: zhaoyulong * @desc: 修改蓝牙store数据 */ changeBluetoolthInfo(key, value) { let tempInfo = JSON.parse(JSON.stringify(this.bluetoolthInfo)) tempInfo[key] = value this.setBluetoolthInfo(tempInfo) }, /** * @author: zhaoyulong * @desc: 开启蓝牙设备入口 */ openBlueDevice(scanCode) { var that = this that.bluetoothName = scanCode return new Promise(function(resolve, reject) { that.openBluetoothAdapter() if (that.timerOpen) { clearInterval(that.timerOpen) } let i = 0 that.timerOpen = setInterval(function() { i++ if (that.openBluetoothSuccess) { clearInterval(that.timerOpen) resolve(true) } if (i > 60) { reject(new Error('蓝牙开锁超时,请联系调度中心')) } }, 1000) }) }, // 开启蓝牙适配 openBluetoothAdapter() { var that = this wx.openBluetoothAdapter({ success(res) { console.log('初始化蓝牙适配器成功', res) that.getBluetoothAdapterState() }, fail(res) { console.log('fail', res) switch (res.errCode) { case 10001: wx.showToast({ title: '当前蓝牙不可用,请打开蓝牙!', icon: 'none', duration: 3000 }) break default: wx.showToast({ title: '初始化蓝牙模块错误码:' + res.errCode, icon: 'none', duration: 3000 }) } } }) }, // 获取本机蓝牙适配器状态 getBluetoothAdapterState() { var that = this wx.getBluetoothAdapterState({ success: function(res) { var available = res.available // 蓝牙适配器是否可用 var discovering = res.discovering // 是否正在搜索设备 if (!available) { wx.showToast({ title: '设备无法开启蓝牙连接', icon: 'success', duration: 2000 }) } else { if (!discovering) { that.step = 3 // 开启扫描附近的蓝牙设备 that.startBluetoothDevicesDiscovery() // 开启获取已连接的蓝牙设备 that.getConnectedBluetoothDevices() } } }, fail: function(res) { console.log('fail', res) } }) }, // 开始搜寻附近的蓝牙外围设备。 // 此操作比较耗费系统资源,请在搜索并连接到设备后调用 wx.stopBluetoothDevicesDiscovery 方法停止搜索 startBluetoothDevicesDiscovery() { var that = this // wx.showLoading({ // title: '蓝牙搜索' // }) console.log('开始搜寻附近的蓝牙外围设备') wx.startBluetoothDevicesDiscovery({ services: [], allowDuplicatesKey: false, success: function(res) { console.log('搜寻结果', res) if (!res.isDiscovering) { that.getBluetoothAdapterState() } else { that.onBluetoothDeviceFound() } }, fail: function(err) { console.log(err) } }) }, // 根据uuid获取处于已连接状态的设备 getConnectedBluetoothDevices() { var that = this console.log('开始根据 uuid 获取处于已连接状态的设备:', that.serviceId) if (that.serviceId) { wx.getConnectedBluetoothDevices({ services: [that.serviceId], success: function(res) { console.log('获取处于连接状态的设备', res) var devices = res['devices'] var flag = false var index = 0 var conDevList = [] devices.forEach(function(value, i, array) { // name: NS-00000001 (在蓝牙连接中呈现的名字) if (value['name'] === that.bluetoothName) { // 如果存在包含bluetoothName字段的设备 flag = true index += 1 conDevList.push(value['deviceId']) that.changeBluetoolthInfo('deviceId', value['deviceId']) // that.deviceId = value['deviceId'] console.log('设备数量', index) // return } }) // 循环连接 - 这里的逻辑还没屡清楚 if (flag) { that.connectDeviceIndex = 0 that.loopConnect(conDevList) } else { if (!that.getConnectedTimer) { that.getConnectedTimer = setTimeout(function() { // 开启获取已连接的蓝牙设备 that.getConnectedBluetoothDevices() }, 5000) } } }, fail: function(err) { console.log('获取处于连接状态的设备失败', err) if (!that.getConnectedTimer) { that.getConnectedTimer = setTimeout(function() { // 开启获取已连接的蓝牙设备 that.getConnectedBluetoothDevices() }, 5000) } } }) } }, // 开启发现附近蓝牙设备事件监听 onBluetoothDeviceFound: function() { var that = this console.log('开启发现附近蓝牙设备事件监听-会把所有设备找出来') wx.onBluetoothDeviceFound(function(res) { // 每找出来一个设备这个逻辑会执行一次 console.log('附件的设备列表', res) if (res.devices[0]) { var name = res.devices[0]['name'] if (name !== '') { // name: NS-00000001 (在蓝牙连接中呈现的名字) if (name === that.bluetoothName) { var deviceId = res.devices[0]['deviceId'] that.changeBluetoolthInfo('deviceId', deviceId) // that.deviceId = deviceId // console.log(that.deviceId) that.startConnectDevices() } } } }) }, // 连接低功耗蓝牙设备 // 若小程序在之前已有搜索过某个蓝牙设备,并成功建立连接,可直接传入之前搜索获取的 deviceId 直接尝试连接该设备,无需进行搜索操作 startConnectDevices: function(ltype, array) { var that = this clearTimeout(that.getConnectedTimer) that.getConnectedTimer = null clearTimeout(that.discoveryDevicesTimer) // 停止循环获取已连接设备 that.stopBluetoothDevicesDiscovery() // that.isConnectting = true if (!this.connected) { console.log('开始连接低功耗蓝牙设备') wx.createBLEConnection({ deviceId: that.deviceId, success: function(res) { console.log('连接成功', res) if (res.errCode === 0) { // that.connected = true that.changeBluetoolthInfo('connected', true) setTimeout(function() { that.getService(that.deviceId) }, 5000) } }, fail: function(err) { console.log('连接失败:', err) if (ltype === 'loop') { that.connectDeviceIndex += 1 that.loopConnect(array) } else { // 开启扫描附近的蓝牙设备 that.startBluetoothDevicesDiscovery() // 开启获取已连接的蓝牙设备 that.getConnectedBluetoothDevices() } }, complete: function() { console.log('连接结束') // that.isConnectting = false } }) } else { that.getService(that.deviceId) } }, // 连接成功后根据deiviceId获取设备的所有服务 getService: function(deviceId) { var that = this // 监听低功耗蓝牙连接状态的改变事件。包括开发者主动连接或断开连接,设备丢失,连接异常断开等等 wx.onBLEConnectionStateChange(function(res) { console.log('监听蓝牙连接', res) }) // 获取蓝牙设备所有服务(service)。 wx.getBLEDeviceServices({ deviceId: deviceId, success: function(res) { console.log('获取蓝牙设备service值', res) that.getCharacter(deviceId, res.services) } }) }, // 读取服务的特征值 getCharacter: function(deviceId, services) { var that = this if (services && services.length > 0) { // 获取蓝牙设备某个服务中所有特征值(characteristic)。第0个是稳定的服务。这里服务有多个,循环会报错。 console.log('读取服务', services[0]) wx.getBLEDeviceCharacteristics({ deviceId: deviceId, serviceId: services[0].uuid, success: function(res) { console.log('设备特征值列表', res) var tempServiceId = services[0].uuid var tempCharacteristicId = '' var tempWriteCharacteristicId = '' if ( res.errCode === 0 && res.characteristics && res.characteristics.length > 0 ) { for (var i = 0; i < res.characteristics.length; i++) { var item = res.characteristics[i] if (item.properties.notify) { // that.characteristicId = item.uuid tempCharacteristicId = item.uuid } else if (item.properties.write) { // that.writeCharacteristicId = item.uuid tempWriteCharacteristicId = item.uuid } } } if (tempCharacteristicId && tempWriteCharacteristicId) { // 只有服务中的特征值可以notify和write的时候记录服务id和特征值id that.changeBluetoolthInfo('serviceId', tempServiceId) that.changeBluetoolthInfo('characteristicId', tempCharacteristicId) that.changeBluetoolthInfo('writeCharacteristicId', tempWriteCharacteristicId) that.step = 4 // 执行开锁指令 - 已经调通 that.writeBLECharacteristicValue(getCommand(that.bluetoothName)) that.openNotifyService() } else { console.log('第0个服务特征值不能同时notify和write') } }, fail: function(err) { console.log('获取服务特征值错误', err) } }) } }, // 订阅特征值 openNotifyService() { console.log('开始订阅特征值') var that = this wx.notifyBLECharacteristicValueChange({ state: true, // 启用 notify 功能 // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接 deviceId: that.deviceId, // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取 serviceId: that.serviceId, // 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取 characteristicId: that.characteristicId, success(res) { console.log('订阅特征值成功', res) that.onBLECharacteristicValueChange() } }) }, onBLECharacteristicValueChange() { console.log('监听低功耗蓝牙设备的特征值变化事件') wx.onBLECharacteristicValueChange(function(res) { console.log(`特征值${res.characteristicId}被改变,现在是${res.value}`) console.log(buf2hex(res.value)) }) }, writeBLECharacteristicValue(value) { console.log('本次发送的指令:', value) var that = this if (that.connected) { //连接蓝牙状态 var hex = value var typedArray = new Uint8Array( hex.match(/[\da-f]{2}/gi).map(function(h) { return parseInt(h, 16) }) ) var buffer = typedArray.buffer let pos = 0 let bytes = buffer.byteLength while (bytes > 0) { let tmpBuffer if (bytes > 20) { tmpBuffer = buffer.slice(pos, pos + 20) pos += 20 bytes -= 20 } else { tmpBuffer = buffer.slice(pos, pos + bytes) pos += bytes bytes -= bytes } console.log( '开始写入指令:', `deviceId:${that.deviceId}, serviceId:${ that.serviceId }, writeCharacteristicId:${that.writeCharacteristicId}` ) // 向低功耗蓝牙设备特征值中写入二进制数据。注意:必须设备的特征值支持 write 才可以成功调用 wx.writeBLECharacteristicValue({ deviceId: that.deviceId, serviceId: that.serviceId, characteristicId: that.writeCharacteristicId, value: tmpBuffer, success: function(res) { console.log('写入指令结果', res) that.openBluetoothSuccess = true }, fail: function(err) { console.log('写入指令失败', err) } }) } } else { wx.showModal({ title: '提示', content: '蓝牙已断开', showCancel: false, success: function(res) { that.searching = false } }) } }, // 通过递归调用获取已配对蓝牙设备的deviceId,如果获取到了就去连接, // devicesId[x]为空说明上传调用getConnectedBluetoothDevices()时获取到的已配对设备全部连接失败了。 // 则开启重新获取已配对蓝牙设备,并开启扫描附近蓝牙设备 loopConnect: function(devicesId) { var that = this // var listLen = devicesId.length if (devicesId[this.connectDeviceIndex]) { // that.deviceId = devicesId[this.connectDeviceIndex] that.changeBluetoolthInfo( 'deviceId', devicesId[this.connectDeviceIndex] ) that.startConnectDevices('loop', devicesId) } else { console.log('已配对的设备小程序蓝牙连接失败') // 开启扫描附近的蓝牙设备 that.startBluetoothDevicesDiscovery() // 开启获取已连接的蓝牙设备 that.getConnectedBluetoothDevices() } }, // 停止搜寻设备 stopBluetoothDevicesDiscovery() { // var that = this console.log('停止搜寻附近的蓝牙外围设备') wx.stopBluetoothDevicesDiscovery({ success: function(res) { console.log('停止搜寻结果', res) }, fail: function(err) { console.log('停止搜寻错误', err) } }) } } }
评论区