let BLEList = [] let getServiceCount = 0; //获取服务的次数 // 蓝牙模块 // 注意: 小程序端不支持蓝牙4.0以下的版本 // 1. 初始化(搜索蓝牙列表) function inArray(arr, key, val) { for (let i = 0; i < arr.length; i++) { if (arr[i][key] === val) { return i } } return -1 } export function getBlooth() { BLEList = [] return new Promise((resolve, reject) => { uni.openBluetoothAdapter({ success(res) { searchBlooth().then(res => { console.log(res, 'searchBlooth') uni.onBluetoothDeviceFound(function(devices) { console.log(devices, '搜索到蓝牙设备') // let result = BLEList.find(devices.devices[0]) // console.log(result, 'res') console.log(devices.devices[0]) let idx = inArray(BLEList, 'deviceId', devices.devices[0] .deviceId) console.log(idx, 'idx') if (idx == '-1') { if (devices.devices[0].localName && (!(devices.devices[0] .name) || devices.devices[0].name == '未知设备')) { devices.devices[0].name = devices.devices[0].localName BLEList.push(devices.devices[0]) } else if (devices.devices[0].name && devices.devices[0] .name != '未知设备') { BLEList.push(devices.devices[0]) } } // BLEList.push(devices.devices[0]) // 5秒后停止搜索 }) setTimeout(() => { DeviceFound().then(res => { console.log(res, 'DeviceFound') console.log(BLEList, 'BLEList') //同时监听蓝牙连接状态 onBLEConnectionStateChange() resolve(res) }).catch(err => { console.log(err, 'searchBlooth1') reject(err) }) }, 5000) }).catch(err => { console.log(err, 'DeviceFound1') reject(err) }) }, fail(err) { console.log(err, 'openBluetoothAdapter err') reject(err) } }) }) } // 2. 检查手机蓝牙开启状态 function searchBlooth() { return new Promise((resolve, reject) => { uni.startBluetoothDevicesDiscovery({ success(res) { console.log(res, 'startBluetoothDevicesDiscovery') // DeviceFound() resolve(res) }, fail(err) { reject(err) } }) }) } // 3. 搜索蓝牙列表 export function DeviceFound() { // uni.onBluetoothDeviceFound(function (devices) { // console.log(devices, '搜索到蓝牙设备') // // 5秒后停止搜索 // }) // setTimeout(() => { stopBlueth() // 搜索到的设备列表 return new Promise((resolve, reject) => { uni.getBluetoothDevices({ success(res) { console.log(res, '蓝牙列表') console.log(BLEList, 'BLEListBLEList') resolve({ devices: BLEList }) }, fail(err) { console.log(err, '错误的') reject(err) } }) }) // }, 5000); } // 4.停止搜索蓝牙 function stopBlueth() { uni.stopBluetoothDevicesDiscovery({ success(res) { console.log(res, '蓝牙停止') } }) } // 5. 断开蓝牙连接 export function closeBle(deviceId2, uuid) { console.log('closeBle') return new Promise((resolve, reject) => { let deviceId = uni.getStorageSync('BLECONNID') console.log(deviceId, 'closeBle') if (deviceId) { uni.closeBLEConnection({ deviceId: deviceId, success(res) { console.log('断开蓝牙连接', res) // 记得打开 uni.removeStorageSync('RESCODE') uni.removeStorageSync('BLECONNID') } }) // 断开蓝牙模块 uni.closeBluetoothAdapter({ success(res) { console.log('断开蓝牙模块', res) if (deviceId2) { uni.openBluetoothAdapter({ success(res) { console.log('打开蓝牙模块') createBLE({ deviceId: deviceId2 }, uuid) }, fail(err) { console.log(err, 'openBluetoothAdapter err') reject(err) } }) } resolve(res) }, fail(err) { console.log(err) reject(err) } }) } }) } // 6.连接蓝牙(连接之前应该把之前连接的蓝牙设备断开) /* item,要连接的蓝牙 uuid */ export function createBLE(item, uuid) { console.log('开始连接') return new Promise((resolve, reject) => { uni.createBLEConnection({ // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接 deviceId: item.deviceId, success(res) { console.log(res, 'createBLE success') getServiceCount = 0 setTimeout(() => { getAllService(item.deviceId, uuid).then(res2 => { console.log(res2, 'createBLE getAllService') getCharacteristics(item.deviceId, res2.uuid).then(res3 => { console.log('createBLE getCharacteristics', res3) resolve(res3) }).catch(err => { uni.hideLoading() reject(err) }) }).catch(err => { uni.hideLoading() reject(err) }) }, 2000) console.log('create end') }, fail(err) { uni.hideLoading() // console.log('111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111') reject(err) } }) }) } /** * 监听低功耗蓝牙连接状态的改变事件。包括开发者主动连接或断开连接,设备丢失,连接异常断开等等 */ function onBLEConnectionStateChange() { console.log('onBLEConnectionStateChange') uni.onBLEConnectionStateChange(function(res) { // 该方法回调中可以用于处理连接意外断开等异常情况 console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`) if (res.deviceId && res.connected) { // 连接成功将本次连接的设备deviceId和name保存本地 uni.setStorageSync('BLECONNID', res.deviceId) uni.setStorageSync('deviceName', name) } }); } // 8.获取所有服务 function getAllService(deviceId, uuid) { console.log(uuid) return new Promise((resolve, reject) => { uni.getBLEDeviceServices({ // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接 deviceId, success: (res) => { console.log('uni.getBLEDeviceServices') console.log(res, getServiceCount) if (res.services.length == 0) { getServiceCount++ if (getServiceCount > 3) { closeBle(deviceId, uuid) // setTimeout(()=>{ // uni.closeBLEConnection({ // deviceId: deviceId, // success(res) { // console.log('断开连接') // // setTimeout(()=>{ // // // uni.hideLoading() // // createBLE({deviceId:deviceId},uuid) // // },500) // } // }) // },500) } else { getAllService(deviceId, uuid) } } else { res.services.forEach((item, index) => { console.log(item, 'deviceid') // 这里的uuid'0000FFE0-0000-1000-8000-00805F9B34FB' if (item.isPrimary && item.uuid === uuid) { uni.setStorageSync("deviceId", deviceId) uni.setStorageSync("serviceId", item.uuid) resolve(item) } // else if (index == (res.services).length-1) { // console.log(index, item, 'getBLEDeviceServices') // reject(res) // } else { // console.log(index, item, 'getBLEDeviceServices') // reject(res) // } }) } // getCharacteristics(deviceId, res.services[0].uuid) }, fail: (err) => { // console.log(err) uni.hideLoading() reject(err) } }) }) } // 9. 获取某个服务的特征值 function getCharacteristics(deviceId, serviceId) { return new Promise((resolve, reject) => { uni.getBLEDeviceCharacteristics({ // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接 deviceId, // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取 serviceId, success(res) { console.log(res, 'getCharacteristics') // console.log('device getBLEDeviceCharacteristics:', res.characteristics) // uni.showLoading({ // title: "检测中...", // icon: "loading", // mask: true // }) res.characteristics.forEach((item, index) => { if (!item.properties.notify && !item.properties.read && item.properties .write) { uni.setStorageSync("characteristicId", item.uuid) console.log('characteristicId1', item.uuid) } if (item.properties.notify && !item.properties.read && !item.properties .write) { // 启用 notify 功能(成功 监听 失败 进行读取操作) console.log('characteristicId2', item.uuid) // console.log(1) // setTimeout(function() { // uni.hideLoading() // }, 500); // console.log(deviceId, serviceId, item.uuid, 'res.deviceId, res.serviceId, item.uuid') notify(deviceId, serviceId, item.uuid).then(res => { // console.log(res, 'notify') resolve(res) }) watchNotify() } else if (index == (res.characteristics).length - 1 && !item.properties .write) { // console.log(index, item, 'fsakdfjslfj') setTimeout(function() { // uni.hideLoading() uni.showToast({ title: "该设备不支持读和写", icon: "none" }) }, 500); reject(res) } else { notify(deviceId, serviceId, item.uuid).then(res => { // console.log(res, 'notify') resolve(res) }) watchNotify() } }) }, fail(err) { reject(err) } }) }) } // 10. 启用 notify 功能 export function notify(deviceId, serviceId, characteristicId) { uni.setStorageSync("characteristicId", characteristicId) return new Promise((resolve, reject) => { uni.notifyBLECharacteristicValueChange({ state: true, // 启用 notify 功能 // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接 deviceId, // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取 serviceId, // 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取 characteristicId, success(res) { // console.log('notifyBLECharacteristicValueChange success', res.errMsg) resolve(res) }, fail(err) { // console.log(err, 'notifuerr') // readBLE(deviceId, serviceId, characteristicId) reject(err) } }) }) } /** * 字符串转换为数组,个数为n,s为字符串 */ function strToArr(s, g) { // var s = "051102003" var re = new RegExp(".{" + g + "}", "g") var a = [] var n while ((n = re.exec(s)) != null) { a[a.length] = n[0] } return a } // 11 监听notify功能 var packData = '' // 分包操作 var first = '' // 开始部分 var center = '' // 中间拼接部分 var last = '' // 结尾部分 var len = 0 // 包的长度 // var flag = true // flag判断是否进行了分包操作 如果分包需要清空开始部分 中间部分 结尾部分 export function watchNotify(isHeart) { console.log('开始监听。。。') // ArrayBuffer转16进度字符串示例 function ab2hex(buffer) { const hexArr = Array.prototype.map.call( new Uint8Array(buffer), function(bit) { return ('00' + bit.toString(16)).slice(-2) } ) return hexArr.join('') } return new Promise((resolve, reject) => { uni.onBLECharacteristicValueChange(function(res) { console.log(res) // 监听帧头帧尾 var resCode1 = ab2hex(res.value) var resCode = resCode1.toUpperCase() console.log(resCode, '收到的') let a = hexCharCodeToStr(resCode) // let arr = a.split('"') uni.$emit('recvEvent', a) }) }) } // 16进制转字符串 function hexCharCodeToStr(hexCharCodeStr) { var trimedStr = hexCharCodeStr.trim(); var rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr; var len = rawStr.length; if (len % 2 !== 0) { alert("Illegal Format ASCII Code!"); return ""; } var curCharCode; var resultStr = []; for (var i = 0; i < len; i = i + 2) { curCharCode = parseInt(rawStr.substr(i, 2), 16); // ASCII Code Value resultStr.push(String.fromCharCode(curCharCode)); } return resultStr.join(""); } // 12.读取功能 export function readBLE(deviceId, serviceId, characteristicId) { uni.readBLECharacteristicValue({ // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接 deviceId, // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取 serviceId, // 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取 characteristicId, success(res) { // console.log('readBLECharacteristicValue:', res.errCode) }, fail(err) { // console.log('readBLEerr:', err) } }) } function str2Bytes(str) { var pos = 0; str = str.replace(/\s*/g, ""); var len = str.length; if (len % 2 != 0) { return null; } len /= 2; var hexA = new Array(); for (var i = 0; i < len; i++) { var s = str.substr(pos, 2); var v = parseInt(s, 16); hexA.push(v); pos += 2; } return hexA; } // 字符串和16进制的互相转换 function strToHexCharCode(str) { if (str === "") return ""; var hexCharCode = []; hexCharCode.push("0x"); for (var i = 0; i < str.length; i++) { let a = (str.charCodeAt(i)).toString(16) if (a.length == 1) { a = '0' + a } hexCharCode.push(a); } var hex = hexCharCode.splice(1, hexCharCode.length); console.log('16-----', hex.join("")) var b = str2Bytes(hex.join("")) return b; } // 14.写入功能. export function writeBLE(strData) { console.log('writeBLE before', strData) // var e = strToHexCharCode(strData) var e = str2Bytes(strData) console.log(e) console.log('writeBLE after') var deviceId = uni.getStorageSync("deviceId") var serviceId = uni.getStorageSync("serviceId") var characteristicId = uni.getStorageSync("characteristicId") console.log(deviceId, serviceId, characteristicId) // 向蓝牙设备发送一个0x00的16进制数据 return new Promise((resolve, reject) => { for (var i = 0; i < e.length; i += 20) { var endLength = 0 // console.log(i) if (i + 20 < e.length) { var senddata = e let buffer = new ArrayBuffer(20) let dataView = new DataView(buffer) for (var j = i; j < i + 20; j++) { dataView.setUint8(j - i, senddata[j]) } // let dataSend = [] // for (var j = i; j < i + 20; j++) { // dataView.setUint8(j - i, senddata[j]) // dataSend.push(dataView.getUint8(j-i)) // } // console.log('多包发送的包数据:'+dataView.buffer) uni.writeBLECharacteristicValue({ // 这里的 deviceId 需要在 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取 deviceId: deviceId, // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取 serviceId: serviceId, // 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取 characteristicId: characteristicId, // 这里的value是ArrayBuffer类型 value: dataView.buffer, // value: buffer, success(res) { resolve(res) }, fail(err) { // console.log(err) reject(err) } }) // 等待 sleep(0.02) } else { var senddata = e // console.log(senddata) if (20 < e.length) { endLength = senddata.length - i // console.log(endLength, 'endLength') } else { endLength = senddata.length // console.log('endLength2', endLength) } let buffer = new ArrayBuffer(endLength) // var dataSend = [] // console.log(senddata.length) let dataViewLast = new DataView(buffer) for (var k = i; k < senddata.length; k++) { // console.log(k) // console.log(i) // console.log(senddata[k]) dataViewLast.setUint8(k - i, senddata[k]) // console.log(dataViewLast.getUint8(k-i)) // dataSend.push(dataViewLast.getUint8(k-i)) } console.log('最后一包或第一数据:') console.log(dataViewLast.buffer) uni.writeBLECharacteristicValue({ // 这里的 deviceId 需要在 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取 deviceId: deviceId, // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取 serviceId: serviceId, // 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取 characteristicId: characteristicId, // 这里的value是ArrayBuffer类型 value: dataViewLast.buffer, // value: buffer, success(res) { resolve(res) }, fail(err) { // console.log(err) reject(err) } }) sleep(0.02) } } }) } function sleep(delay) { var start = (new Date()).getTime(); while ((new Date()).getTime() - start < delay) { continue; } }