最近在做一个蓝牙售货机的项目,放在酒店房间内,哈哈,里边是什么自行脑补。
因为需要适配微信小程序和支付宝小程序,所以最后选用uni-app来开发,省时省力更省钱。
第一次对接蓝牙,做一次记录,话不多说,开始上代码。
*uni-app蓝牙连接的整个流程 *1、初始化蓝牙 uni.openBluetoothAdapter(OBJECT) *2、开始搜索蓝牙设备 uni.startBluetoothDevicesDiscovery(OBJECT) *3、发现外围设备 uni.onBluetoothDeviceFound(CALLBACK) *4、停止搜寻附近的蓝牙外围设备 uni.stopBluetoothDevicesDiscovery(OBJECT) *5、连接低功耗蓝牙设备 uni.createBLEConnection(OBJECT) *6、获取蓝牙设备所有服务 uni.getBLEDeviceServices(OBJECT) *7、获取蓝牙特征 uni.getBLEDeviceCharacteristics(OBJECT) *8、启用蓝牙设备特征值变化时的 notify 功能 uni.notifyBLECharacteristicValueChange(OBJECT) *9、监听低功耗蓝牙设备的特征值变化 uni.onBLECharacteristicValueChange(CALLBACK) *10、对需要操作的特征值进行读、写操作 import store from ‘@/store/index.js‘ let _self; export default class deviceClass { constructor() { _self = this; _self.deviceId = ""; _self.isConnect = false; //是否已连接 _self.isStop = false; //是否停止搜所 _self.UUID_SERVICE = ‘0000FEE0-0000-1000-8000-00805F9B34FB‘; //服务UUID,设备方提供 _self.UUID_CHAR = ‘0000FEE1-0000-1000-8000-00805F9B34FB‘; //特征值UUID,设备方提供 } /* 初始化并搜索蓝牙操作 */ initEventDevice() { uni.showLoading({ title: "蓝牙连接中" }) /* 1、初始化蓝牙 uni.openBluetoothAdapter(OBJECT) */ uni.openBluetoothAdapter({ complete: () => { /* 监听蓝牙是否开启*/ uni.onBluetoothAdapterStateChange(function(res) { //res.available 蓝牙适配器是否可用 //res.discovering 蓝牙适配器是否处于搜索状态 console.log(‘适配器状态变化‘, res) if(!res.available && !res.discovering){ _self.isStop = false; uni.showToast({ duration: 2500, title: "请打开手机蓝牙", icon: ‘error‘, }) store.commit(‘updateStatus‘, false); } else if(_self.isStop==false && res.available && !res.discovering){ console.log("蓝牙已开启,可以执行搜索操作") _self.initEventDevice(); } else if(res.available && res.discovering){ console.log("蓝牙已开启,并且正在搜索中") } }) }, success: (res) => { /* 初始化蓝牙成功 */ /* 2、开始搜索蓝牙设备 uni.startBluetoothDevicesDiscovery(OBJECT) */ /* 监听蓝牙适配器状态变化事件 可以检测当前设备的蓝牙的断开或者连接的情况*/ _self.startBluetoothDevicesDiscovery(); _self.connectTimeout(); }, fail: (res) => { console.log("初始化蓝牙失败:" + JSON.stringify(res)) uni.hideLoading(); uni.showToast({ duration: 2500, title: "请打开手机蓝牙", icon: ‘error‘, }) } }) } /*搜索蓝牙*/ startBluetoothDevicesDiscovery() { uni.startBluetoothDevicesDiscovery({ allowDuplicatesKey: false, //是否允许同一设备多次上报,但RSSI值会有所不同 success: (res) => { console.log("搜索成功:" + JSON.stringify(res)) _self.onBluetoothDeviceFound(); }, fail: (res) => { uni.showModal({ title: ‘蓝牙连接失败了哦‘, content: ` 1、请查看周围是否有连接此设备的蓝牙; 2、请先关闭手机蓝牙在打开一次; 3、请检查位置信息是否打开; 4、退出小程序重新扫码进入。`, showCancel: false, confirmText: "我知道了", success: () => {} }) console.log("搜索失败:" + JSON.stringify(res)) } }) } /* 搜索蓝牙设备回调 */ onBluetoothDeviceFound() { uni.onBluetoothDeviceFound(function(CALLBACK) { console.log(‘搜索蓝牙设备回调===‘ + JSON.stringify(CALLBACK)) /* 每次遍历指定设备,一旦搜索到指定设备就结束搜索*/ let bluename = JSON.parse(uni.getStorageSync(‘deviceInfo‘)).bluename; //需要搜索的设备名称 /* 搜索过程中如果搜索到需要的设备,就停止搜索 */ CALLBACK.devices.forEach(device => { /* 筛选需要的deviceId */ if (device.deviceId === bluename) { //找到需要的设备之后,停止搜索 console.log("搜索到指定设备=="+device.deviceId) _self.isConnect = true; /*停止搜索*/ _self.stopBluetoothDevicesDiscovery(); /* 执行连接 */ _self.connectDevice(device.deviceId); } }) }) } /*设置蓝牙搜索时间30秒, 如果超时没有搜索到就停止搜索*/ connectTimeout() { setTimeout(() => { if(!_self.isConnect) { uni.hideLoading(); _self.stopBluetoothDevicesDiscovery(); uni.showModal({ title: ‘蓝牙连接失败了哦‘, content: ` 1、请查看周围是否有连接此设备的蓝牙; 2、请先关闭手机蓝牙在打开一次; 3、请检查位置信息是否打开; 4、退出小程序重新扫码进入。`, showCancel: false, confirmText: "我知道了", success: () => {} }) } }, 30000) } /* 停止搜索 */ stopBluetoothDevicesDiscovery() { uni.stopBluetoothDevicesDiscovery({ complete: () => { _self.isStop = true; }, success: (res) => { console.log("停止搜索成功") }, fail: (res) => { console.log("停止失败") uni.hideLoading(); } }) } /* 连接低功耗蓝牙 */ connectDevice(deviceId) { console.log("执行到这里了") uni.createBLEConnection({ deviceId, //点击的DeviceId timeout: 5000, success: (res) => { console.log("连接成功") _self.deviceId = deviceId; /* 这边获取全部的服务,并筛选出当前需要的*/ _self.getBLEDeviceServices(deviceId) }, fail: (error) => { /* 连接失败 */ uni.hideLoading(); console.log("连接失败") console.log(error); uni.showModal({ title: ‘蓝牙连接失败了哦‘, content: ` 1、请查看周围是否有连接此设备的蓝牙; 2、请先关闭手机蓝牙在打开一次; 3、请检查位置信息是否打开; 4、退出小程序重新扫码进入。`, showCancel: false, confirmText: "我知道了", success: () => {} }) } }) /* 监听蓝牙设备的连接状态 */ uni.onBLEConnectionStateChange(function(res) { console.log(res.deviceId + "连接状态:" + res.connected) }) } /* 获取所有的服务*/ getBLEDeviceServices(deviceId) { console.log("开始获取服务") //连接成功之后需要延时,继续操作才不会出问题,延时时间短一点都没关系,我这边用了1秒 setTimeout(() => { uni.getBLEDeviceServices({ // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接 deviceId, success: (res) => { console.log(‘device services:‘, res) res.services.forEach((item) => { //这里微信小程序获取的服务ID是大写,支付宝是小写,所以统一转换为大写 let serviceId = item.uuid.toUpperCase(); if (serviceId == _self.UUID_SERVICE) { console.log(‘serverId:‘, serviceId) /* 进入特征值 */ _self.getBLEDeviceCharacteristics(deviceId, serviceId); } }) }, fail: (error) => { console.log("获取服务失败") console.log(error) uni.hideLoading(); } }) }, 1000) } /* 获取所有特征值 */ getBLEDeviceCharacteristics(deviceId, serviceId) { console.log("开始获取特征") setTimeout(() => { uni.getBLEDeviceCharacteristics({ deviceId, serviceId, success: (res) => { console.log(res) res.characteristics.forEach((item) => { console.log(item) //这里跟服务ID一样,支付宝需要转换为大写 //#ifdef MP-ALIPAY let characterId = item.characteristicId.toUpperCase(); //#endif //#ifdef MP-WEIXIN let characterId = item.uuid; //#endif /* 只要用到的唤醒即可 */ if (characterId == _self.UUID_CHAR) { console.log(‘characteristicId:‘, characterId) _self.notifyBLECharacteristicValueChange(deviceId, serviceId, characterId) } }) }, fail: (res) => { uni.hideLoading(); console.log(res) } }) }, 1000) } /* 启用蓝牙设备特征值变化时的 notify 功能 */ notifyBLECharacteristicValueChange(deviceId, serviceId, characteristicId) { console.log("开始唤醒") uni.notifyBLECharacteristicValueChange({ state: true, // 启用 notify 功能 // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接 deviceId, // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取 serviceId, // 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取 characteristicId, success: (res) => { uni.hideLoading(); /* 连接成功 */ uni.showToast({ title: "连接成功", icon: ‘success‘ }); //储存蓝牙连接状态 store.commit(‘updateStatus‘, true); console.log(‘notifyBLECharacteristicValueChange success‘, res.errMsg) /* 连接成功以后,执行设置的操作,并且打开返回值的监听开关并监听 */ //获取设备信息 let DeviceCommand = "01,02,03,04," + func("01020304") + ",1E"; let DeviceArrayBuffer = string2buffer(DeviceCommand); _self.writeDevice(DeviceArrayBuffer); //出货后关门延时设置 let delayedCommand = "01,02,03,04,0A," + func("010203040A") + ",1E"; let delayedArrayBuffer = string2buffer(delayedCommand); _self.writeDevice(delayedArrayBuffer); /* 监听低功耗蓝牙设备的特征值变化 */ uni.onBLECharacteristicValueChange(function(CALLBACK) { let result = blueTool.ab2hex(CALLBACK.value); console.log("收到的数据值==", result); // 这里做一些具体的业务逻辑 //我这里是监听低功耗蓝牙设备的特征值变化,然后调后台接口获取设备的电量,展示在页面 if ("73080182" === result.substring(0, 8)) { var o = result.substring(8, 10); o = parseInt(o, 16); let dl = ""; if (o >= 41) { dl = 100; } else if (o <= 37) { dl = 0; } else { dl = (o - 37) * 100 / (41 - 37); } //获取设备电量 uni.request({ url: baseUrl+"/api/*****", method: "POST", data: { key: value }, header: { "Content-Type": "application/x-www-form-urlencoded" }, success: function(t) { store.commit(‘setDeviceBattery‘, t.data.data); console.log("设备上传回调" + JSON.stringify(t.data)); }, fail: function(t) {} }); } }) }, fail: (res) => { uni.hideLoading(); console.log(‘notifyBLECharacteristicValueChange success‘, res.errMsg) } }) } /* 执行写入命令操作 */ writeDevice(_Buffer) { uni.writeBLECharacteristicValue({ deviceId: _self.deviceId, serviceId: _self.UUID_SERVICE, characteristicId: _self.UUID_CHAR, value: _Buffer, success: (res) => { /* 发送成功 */ console.log(‘最后一次写入成功‘, res) }, fail: (error) => { /* 发送失败 */ console.log(‘最后一次写入失败‘, error) } }) } /* 获取本机蓝牙适配器状态 */ getBluetoothState() { uni.getBluetoothAdapterState({ success: (res) => { console.log("状态" + JSON.stringify(res)) } }) } /* 关闭蓝牙适配器*/ closeBlueAdapter() { uni.closeBluetoothAdapter({ success() { console.log("关闭蓝牙适配器成功") } }) } /* 断开低功耗蓝牙的连接 */ disconnectBle() { uni.closeBLEConnection({ deviceId: _self.deviceId, success: (res) => { console.log("断开成功" + res) store.commit(‘updateStatus‘, false); store.commit(‘setDeviceBattery‘, 0); } }) }, /* 具体的命令BCC校验*/ func(t) { for (var e = t, a = [], i = 0; i < e.length - 1; i += 2) a.push(e.substring(i, i + 2)); for (var o = a[0], s = 0; s < a.length - 1; s++) o ^= a[s + 1]; return o; }, /* 字符串转arraybuffer */ string2buffer: function(str) { // 首先将字符串转为16进制 let val = str console.log(val) // 将16进制转化为ArrayBuffer return new Uint8Array(val.match(/[\da-f]{2}/gi).map(function(h) { return parseInt(h, 16) })).buffer }, }