368 lines
12 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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