619 lines
16 KiB
JavaScript

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;
}
}