/** * 1. 获取本机蓝牙适配器状态 wx.getBluetoothAdapterState * 2. 初始化蓝牙适配器 wx.openBluetoothAdapter() * 3. 启动蓝牙发现 wx.wx.startBluetoothDevicesDiscovery() * 4. 获取扫描到的所有设备 wx.getBluetoothDevices() * * * 参数: * @callback function 回调函数,用于接收返回值 * * 返回值: * ret:{isBluetoothAvailable:true, isBluetoothSearching:true, scanList:[]} * isBluetoothAvailable boolean 蓝牙适配器状态,true表示初始化蓝牙适配器成功 * isBluetoothSearching boolean 蓝牙搜索状态,true表示开启蓝牙发现成功 * scanList array 搜索的设备列表 */ function scanDevices(callback) { if (typeof callback != "function") { // console.log('Parameter callback is not a function'); return; } ; //scanList格式如下: //[{RSSI:-xx, advertisServiceUUIDs:[], deviceId:'', name:''},{...}] //注意:Android系统的deviceId是设备的mac地址,iOS系统的deviceId是设备的UUID var ret = { isBluetoothAvailable: false, isBluetoothSearching: false, scanList: [] }; /** * 获取蓝牙适配器状态 * */ uni.getBluetoothAdapterState({ success: function (res) { // console.log("---getBluetoothAdapterState--success:", res) ret.isBluetoothAvailable = res.available; ret.isBluetoothSearching = res.discovering; }, fail: function (res) { console.log("---getBluetoothAdapterState--fail:", res); }, complete: function (res) { /** * 初始化蓝牙 */ if (!ret.isBluetoothAvailable) { uni.openBluetoothAdapter({ success: function (res) { // console.log("---openBluetoothAdapter--success:", res); ret.isBluetoothAvailable = true; startBluetoothDiscoveryAndScanDevice(ret, callback); }, fail: function (res) { // console.log("---openBluetoothAdapter--fail:", res); callback(ret); //蓝牙初始化失败,直接返回,不进行后续搜索操作 return; } }); } else { startBluetoothDiscoveryAndScanDevice(ret, callback); } } }); } function startBluetoothDiscoveryAndScanDevice(ret, callback) { /** * 开启蓝牙发现 */ if (!ret.isBluetoothSearching) { uni.startBluetoothDevicesDiscovery({ services: [], allowDuplicatesKey: true, success: function (res) { // console.log("---startBluetoothDevicesDiscovery--success: ", res); ret.isBluetoothSearching = res.isDiscovering; }, fail: function (res) {// console.log('---startBluetoothDevicesDiscovery--fail:', res); // 刷新页面后,开启蓝牙发现失败,暂时忽略10008错误 // if (res.errCode != 10008) { // callback(ret); // } }, complete: function (res) { // console.log('---startBluetoothDevicesDiscovery--complete:', res) if (res.errCode === 0 || res.errCode === 10008) { scanBluetoothDevice(ret, callback); } else { callback(ret); } } }); } else { scanBluetoothDevice(ret, callback); } } function scanBluetoothDevice(ret, callback) { /** * 获取扫描到的所有设备 */ setTimeout(function () { uni.getBluetoothDevices({ success: function (res) { //{devices: Array[11], errMsg: "getBluetoothDevices:ok"} // console.log('---getBluetoothDevices--success:', res); console.log('---getBluetoothDevices--success:', res.devices); var devArr = []; //根据广播UUID进行设备列表筛选 for (var i = 0; i < res.devices.length; i++) { if (!('advertisServiceUUIDs' in res.devices[i])) { delete res.devices[i]; continue; } for (let j = 0; j < res.devices[i].advertisServiceUUIDs.length; j++) { if (res.devices[i].advertisServiceUUIDs[j].toUpperCase().indexOf('FEF5') != -1) { var devSn = res.devices[i].name; // console.log("devSn:", devSn); if (devSn.indexOf("-") >= 0) { devArr.push({ "deviceId": res.devices[i].deviceId, "name": devSn.split("-")[1], "RSSI": res.devices[i].RSSI }); } } } } ret.scanList = devArr; callback(ret); }, fail: function (res) { console.log('---getBluetoothDevices--fail:', res); callback(ret); } }); }, 3000); } /** * * 参数: * @deviceid String 参考scanDevices方法 * @sendData String 发送到设备的开门指令 * @callback function 回调函数,用于处理返回值 * * 返回值: * ret{errCode:'', errMsg:'', receiveData:''} * errCode: 错误码, 0表示开门成功 * errMsg: 错误信息,Ok表示开门成功 * receiveData: 接收的设备消息,消息内容为ac1c8表示开门成功 */ function openDoor(deviceid, sendData, callback) { var ret = { errCode: 0, errMsg: 'Ok', receiveData: '' }; if (typeof callback != "function") { ret.errCode = 6; ret.errMsg = 'parameter callback is not a function'; callback(ret); return; } else if (typeof deviceid != "string" || deviceid === '') { ret.errCode = 4; ret.errMsg = 'deviceId is not a string type or is empty'; callback(ret); return; } else if (typeof sendData != "string" || sendData === '') { ret.errCode = 5; ret.errMsg = 'sendData is not a string type or is empty'; callback(ret); return; } var serviceId = ''; var characteristics = []; var notifyCharacter = ''; var writeCharacter = ''; var readCharacter = ''; var deviceId = deviceid.toUpperCase(); //BLE蓝牙连接 uni.createBLEConnection({ deviceId: deviceId, success: function (res) { // console.log('---createBLEConnection--success:', res); /** * 监听特定BLE设备连接状态变化 */ uni.onBLEConnectionStateChange(function (res) {// 该方法回调中可以用于处理连接意外断开等异常情况 // console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`); }); //获取指定设备的所有服务 uni.getBLEDeviceServices({ deviceId: deviceId, success: function (res) { //筛选指定的服务UUID for (var i = 0; i < res.services.length; i++) { if (res.services[i].uuid.toLowerCase().indexOf('0886') != -1 || res.services[i].uuid.toLowerCase().indexOf('ffe0') != -1) { serviceId = res.services[i].uuid; break; } } /** * 获取指定服务下的所有特征值 */ uni.getBLEDeviceCharacteristics({ deviceId: deviceId, serviceId: serviceId, success: function (res) { for (var i = 0; i < res.characteristics.length; i++) { if (res.characteristics[i].uuid.toLowerCase().indexOf('878b') != -1) { notifyCharacter = res.characteristics[i].uuid; } else if (res.characteristics[i].uuid.toLowerCase().indexOf('878c') != -1) { writeCharacter = res.characteristics[i].uuid; readCharacter = res.characteristics[i].uuid; } } /** * 启用低功耗蓝牙设备特征值变化时的 notify 功能 */ uni.notifyBLECharacteristicValueChange({ deviceId: deviceId, serviceId: serviceId, characteristicId: notifyCharacter, state: true, success: function (res) {// console.log('---notifyBLECharacteristicValueChange--success:', res.errMsg); } }); /** * 监听低功耗蓝牙设备的特征值变化 */ uni.onBLECharacteristicValueChange(function (res) { // console.log(`characteristic ${res.characteristicId} has changed, now is ${res.value}`); let buffer = res.value; let dataView = new DataView(buffer); let receiveData = ''; for (let i = 0; i < buffer.byteLength; i++) { receiveData += dataView.getUint8(i).toString(16); } if (sendData.length <= 20) { // 向蓝牙设备发送20字节16进制数据,如果不超过20字节数据,监听低功耗蓝牙设备的特征值变化,如果超过,就不监听 if (receiveData != 'ac1c8') { ret.errCode = 7; ret.errMsg = "paramater 'sendData' is incorrect."; } ret.receiveData = receiveData; callback(ret); } }); //向蓝牙设备发送20字节16进制数据,超过20字节数据,分包续传 var data = sendData; var buffer_size = data.length > 20 ? data.length / 2 : 20; var buffer = new ArrayBuffer(buffer_size); var dataView = new DataView(buffer); for (let i = 0; i < data.length / 2; i++) { var subData = data.slice(2 * i, 2 * i + 2); dataView.setUint8(i, parseInt('0x' + subData)); } /** * 写入特征值下的二进制数据 * */ setTimeout(function () { var count = 0; if (buffer_size == 20) { count = 1; } else { count = 2; } var send_data_array = new Array(); for (let i = 0; i < count; i++) { var start_buffer = i * 20; var end_buffer = (i + 1) * 20; if (end_buffer > buffer.byteLength) { end_buffer = buffer.byteLength; } var buffer_content = buffer.slice(start_buffer, end_buffer); if (buffer_content.byteLength > 0) { send_data_array.push(buffer_content); } } var send_index = 0; send_bledata_device(send_index, send_data_array); function send_bledata_device(send_index, send_data_array) { // console.log("----deviceId=" + deviceId + "--serviceId=" + serviceId + "--send_index=" + send_index); uni.writeBLECharacteristicValue({ deviceId: deviceId, serviceId: serviceId, characteristicId: writeCharacter, value: send_data_array[send_index], success: function (res) { console.log('++++++++writeBLECharacteristicValue-success:', res); if (send_index < send_data_array.length - 1) { setTimeout(function () { send_index += 1; send_bledata_device(send_index, send_data_array); }, 250); } else { ret.errCode = 0; callback(ret); } }, fail: function (res) { ret.errCode = res.errCode; //3 ret.errMsg = 'writeBLECharacteristicValue fail'; console.log('++++++++writeBLECharacteristicValue-fail-errorCode:', ret.errCode); callback(ret); } }); } }, 500); }, fail: function (res) { ret.errCode = res.errCode; //2 ret.errMsg = 'getBLEDeviceCharacteristics fail'; callback(ret); } }); } }); }, fail: function (res) { ret.errCode = res.errCode; //1 ret.errMsg = 'createBLEConnection fail'; callback(ret); } }); } module.exports = { scanDevices: scanDevices, openDoor: openDoor };