368 lines
12 KiB
JavaScript
368 lines
12 KiB
JavaScript
import {Result} from '../constant'
|
||
|
||
/**
|
||
* @typedef {Object} err
|
||
* @property {number} errno - 错误代码
|
||
* @property {number} errCode - 错误代码
|
||
* @property {String} errMsg - 错误信息
|
||
*/
|
||
|
||
// 查找设备并连接
|
||
export function searchAndConnectDevice(name, reset = true, deviceId = null) {
|
||
// 循环查找设备
|
||
let timer
|
||
// 超时计时器
|
||
let timeoutTimer
|
||
|
||
return new Promise(async resolve => {
|
||
// 如果提供了deviceId,则直接连接
|
||
if (deviceId) {
|
||
const connectResult = await createBLEConnection(deviceId)
|
||
resolve(connectResult)
|
||
}
|
||
const result = await startBluetoothDevicesDiscovery()
|
||
if (result.code === Result.Success.code) {
|
||
let searchFlag = false
|
||
timeoutTimer = setTimeout(async () => {
|
||
await stopBluetoothDevicesDiscovery()
|
||
clearInterval(timer)
|
||
if (!searchFlag) {
|
||
resolve(Result.NotAvailableWeChatNearbyDevicesEmpty)
|
||
} else {
|
||
resolve(Result.Fail)
|
||
}
|
||
}, 10500)
|
||
timer = setInterval(async () => {
|
||
const queryResult = await getBluetoothDevices()
|
||
if (queryResult.code === Result.Success.code) {
|
||
const deviceList = queryResult.data
|
||
if (searchFlag === false && deviceList.length > 0) {
|
||
searchFlag = true
|
||
}
|
||
for (let i = 0; i < deviceList.length; i++) {
|
||
if (deviceList[i]?.name === name) {
|
||
const uuid = deviceList[i]?.advertisServiceUUIDs[0]
|
||
if (uuid && uuid.slice(2, 8) === '758824') {
|
||
await stopBluetoothDevicesDiscovery()
|
||
clearTimeout(timeoutTimer)
|
||
clearInterval(timer)
|
||
if (uuid.slice(30, 32) === '00' && reset) {
|
||
resolve(Result.DeviceHasBeenReset)
|
||
} else {
|
||
const connectResult = await createBLEConnection(deviceList[i].deviceId)
|
||
resolve(connectResult)
|
||
}
|
||
break
|
||
}
|
||
if (uuid && uuid.slice(0, 2) === '75') {
|
||
await stopBluetoothDevicesDiscovery()
|
||
clearTimeout(timeoutTimer)
|
||
clearInterval(timer)
|
||
if (uuid.slice(4, 6) === '00' && reset) {
|
||
resolve(Result.DeviceHasBeenReset)
|
||
} else {
|
||
const connectResult = await createBLEConnection(deviceList[i].deviceId)
|
||
resolve(connectResult)
|
||
}
|
||
break
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
resolve(queryResult)
|
||
}
|
||
}, 1000)
|
||
} else {
|
||
resolve(result)
|
||
}
|
||
})
|
||
}
|
||
|
||
// 蓝牙操作报错处理
|
||
async function handleError(err, event) {
|
||
if (err.errCode === 10000) {
|
||
const result = await openBluetoothAdapter()
|
||
if (result.code === Result.Success.code) {
|
||
return await event()
|
||
}
|
||
return result
|
||
}
|
||
if (err.errCode === 10001) {
|
||
if (err.state === 3) {
|
||
return Result.NotAvailableWeChatBluetoothPermission
|
||
}
|
||
return Result.NotAvailableBluetooth
|
||
}
|
||
if (err.errno === 3) {
|
||
return Result.NotAvailableWeChatNearbyDevicesPermission
|
||
}
|
||
if (err.errno === 103) {
|
||
return Result.NotAvailableBluetoothPermission
|
||
}
|
||
if (err.errno === 1509008) {
|
||
return Result.NotAvailableWeChatLocationPermission
|
||
}
|
||
if (err.errMsg === 'openBluetoothAdapter:fail already opened') {
|
||
return Result.Success
|
||
}
|
||
return Result.Fail
|
||
}
|
||
|
||
// 初始化蓝牙模块
|
||
function openBluetoothAdapter() {
|
||
return new Promise(resolve => {
|
||
uni.openBluetoothAdapter({
|
||
success() {
|
||
resolve(Result.Success)
|
||
},
|
||
async fail(err) {
|
||
resolve(await handleError(err))
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
// 关闭蓝牙模块
|
||
export function closeBluetoothAdapter() {
|
||
uni.closeBluetoothAdapter()
|
||
}
|
||
|
||
// 移除蓝牙适配器的全部监听
|
||
export function offBluetoothAdapterStateChange() {
|
||
uni.offBluetoothAdapterStateChange()
|
||
}
|
||
|
||
// 监听蓝牙特征值改变
|
||
export function onBLECharacteristicValueChange(callback) {
|
||
uni.onBLECharacteristicValueChange(res => {
|
||
callback(res)
|
||
})
|
||
}
|
||
|
||
// 开始搜索附近的蓝牙设备
|
||
export function startBluetoothDevicesDiscovery() {
|
||
return new Promise(resolve => {
|
||
uni.startBluetoothDevicesDiscovery({
|
||
success() {
|
||
resolve(Result.Success)
|
||
},
|
||
async fail(err) {
|
||
resolve(await handleError(err, startBluetoothDevicesDiscovery))
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
// 获取所有已发现的蓝牙设备
|
||
export function getBluetoothDevices() {
|
||
return new Promise(resolve => {
|
||
uni.getBluetoothDevices({
|
||
success(res) {
|
||
resolve(new Result(Result.Success.code, res.devices))
|
||
},
|
||
async fail(err) {
|
||
resolve(await handleError(err, getBluetoothDevices))
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
// 停止搜索附近的蓝牙设备
|
||
export function stopBluetoothDevicesDiscovery() {
|
||
return new Promise(resolve => {
|
||
uni.stopBluetoothDevicesDiscovery({
|
||
success() {
|
||
resolve(Result.Success)
|
||
},
|
||
async fail(err) {
|
||
resolve(await handleError(err))
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
// 连接低功耗蓝牙设备
|
||
export function createBLEConnection(deviceId, reconnectNumber = 0) {
|
||
return new Promise(resolve => {
|
||
uni.createBLEConnection({
|
||
deviceId,
|
||
timeout: 10000,
|
||
async success() {
|
||
const res = await getBLEDeviceServicesAndCharacteristics(deviceId)
|
||
await notifyBLECharacteristicValueChange(
|
||
deviceId,
|
||
res.data.serviceId,
|
||
res.data.notifyCharacteristicId
|
||
)
|
||
resolve(res)
|
||
},
|
||
async fail(err) {
|
||
if (err.errno === 1500101) {
|
||
// 未初始化,初始化成功后在重连
|
||
const result = await openBluetoothAdapter()
|
||
if (result.code === Result.Success.code) {
|
||
resolve(await createBLEConnection(deviceId, reconnectNumber + 1))
|
||
}
|
||
}
|
||
if (err.errno === 1509007) {
|
||
const res = await getBLEDeviceServicesAndCharacteristics(deviceId)
|
||
await notifyBLECharacteristicValueChange(
|
||
deviceId,
|
||
res.data.serviceId,
|
||
res.data.notifyCharacteristicId
|
||
)
|
||
resolve(res)
|
||
} else if (err.errno === 1509001 && reconnectNumber < 1) {
|
||
resolve(Result.Fail)
|
||
} else if (reconnectNumber < 1) {
|
||
resolve(await createBLEConnection(deviceId, reconnectNumber + 1))
|
||
} else {
|
||
resolve(Result.Fail)
|
||
}
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
// 获取服务及对应特征值
|
||
async function getBLEDeviceServicesAndCharacteristics(deviceId) {
|
||
const {code, data} = await getBLEDeviceServices(deviceId)
|
||
if (code === Result.Success.code) {
|
||
const {serviceId} = data
|
||
const {
|
||
code,
|
||
data: {notifyCharacteristicId, writeCharacteristicId}
|
||
} = await getBLEDeviceCharacteristics(deviceId, serviceId)
|
||
if (code === Result.Success.code) {
|
||
return new Result(Result.Success.code, {
|
||
deviceId,
|
||
serviceId,
|
||
notifyCharacteristicId,
|
||
writeCharacteristicId
|
||
})
|
||
}
|
||
return Result.Fail
|
||
}
|
||
return Result.Fail
|
||
}
|
||
|
||
// 获取设备的服务
|
||
function getBLEDeviceServices(deviceId) {
|
||
return new Promise(resolve => {
|
||
uni.getBLEDeviceServices({
|
||
deviceId,
|
||
success(res) {
|
||
let serviceId
|
||
for (let i = 0; i < res.services.length; i++) {
|
||
if (res.services[i].uuid.indexOf('FFF0') !== -1) {
|
||
serviceId = res.services[i].uuid
|
||
}
|
||
}
|
||
if (!serviceId) {
|
||
resolve(Result.Fail)
|
||
return
|
||
}
|
||
resolve(new Result(Result.Success.code, {serviceId}))
|
||
},
|
||
fail() {
|
||
resolve(Result.Fail)
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
// 获取服务的特征值
|
||
function getBLEDeviceCharacteristics(deviceId, serviceId) {
|
||
return new Promise(resolve => {
|
||
uni.getBLEDeviceCharacteristics({
|
||
deviceId,
|
||
serviceId,
|
||
success(res) {
|
||
let notifyCharacteristicId
|
||
let writeCharacteristicId
|
||
for (let i = 0; i < res.characteristics.length; i++) {
|
||
const characteristic = res.characteristics[i]
|
||
if (characteristic.properties.notify) {
|
||
notifyCharacteristicId = characteristic.uuid
|
||
}
|
||
if (characteristic.properties.write) {
|
||
writeCharacteristicId = characteristic.uuid
|
||
}
|
||
}
|
||
if (notifyCharacteristicId && writeCharacteristicId) {
|
||
resolve(
|
||
new Result(Result.Success.code, {notifyCharacteristicId, writeCharacteristicId})
|
||
)
|
||
} else {
|
||
resolve(Result.Fail)
|
||
}
|
||
},
|
||
fail() {
|
||
resolve(Result.Fail)
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
// 订阅特征值
|
||
function notifyBLECharacteristicValueChange(deviceId, serviceId, characteristicId) {
|
||
return new Promise(resolve => {
|
||
uni.notifyBLECharacteristicValueChange({
|
||
deviceId,
|
||
serviceId,
|
||
characteristicId,
|
||
state: true,
|
||
success() {
|
||
resolve(Result.Success)
|
||
},
|
||
fail() {
|
||
resolve(Result.Fail)
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
// 断开与低功耗蓝牙设备的连接
|
||
export function closeBLEConnection(deviceId) {
|
||
return new Promise(resolve => {
|
||
uni.closeBLEConnection({
|
||
deviceId,
|
||
success() {
|
||
console.log('断开连接成功')
|
||
resolve(Result.Success)
|
||
},
|
||
fail() {
|
||
console.log('断开连接失败')
|
||
resolve(Result.Fail)
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
// 写入特征值
|
||
export function writeBLECharacteristicValue(deviceId, serviceId, characteristicId, binaryData) {
|
||
return new Promise(resolve => {
|
||
const count = Math.ceil(binaryData.length / 20)
|
||
let successCount = 0
|
||
for (let i = 0; i < count; i++) {
|
||
const writeData = binaryData.slice(i * 20, i === count - 1 ? binaryData.length : (i + 1) * 20)
|
||
uni.writeBLECharacteristicValue({
|
||
deviceId,
|
||
serviceId,
|
||
characteristicId,
|
||
value: writeData.buffer,
|
||
success(res) {
|
||
successCount++
|
||
if (successCount === count) {
|
||
resolve(Result.Success)
|
||
}
|
||
},
|
||
fail(err) {
|
||
console.error("writeBLECharacteristicValue err", err)
|
||
resolve(Result.Fail)
|
||
}
|
||
})
|
||
}
|
||
})
|
||
}
|