123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- import * as tools from "./tools"
- import {inArray, isObject, logs, sleep} from "../util";
- import {showToast} from "../app";
- import {checkBleAuth} from "../uniFunction";
- import {ab2hex, orderSplit, stringToArrayBuffer} from "./hex";
- import {isH5} from "@/utils/platform";
- /**
- * 蓝牙工具类
- * 封装小程序蓝牙流程方法
- * 处理事件通信
- */
- export class bleBase {
- constructor(topClass) {
- this.topClass = topClass
- this.typeKey = ''
- this.option = {}
- this.deviceId = null
- this.serviceId = null
- this.writeId = null // 写入id
- this.characteristicId = null// 接收id
- this.conSevInterval = 2000
- this.sList = []
- this.OSList = []
- }
- /**
- * 搜索蓝牙设备
- * @param data
- * @param op
- * @param showLoad
- * @returns {Promise<unknown>}
- */
- getList(data = {}, op = {}, showLoad = true) {
- let option = {
- second: 5000,
- type: 1,
- start: null,
- fun: null,
- fail: null,
- }
- option = Object.assign(option, op)
- return new Promise(async (resolve, reject) => {
- logs('进入 searchBle')
- try {
- await this.topClass.init()
- console.error('getList init')
- await checkBleAuth() // 检查用户蓝牙授权是否通过
- if (isH5) throw 'H5不支持蓝牙功能'
- if (showLoad) uni.showLoading({title: '搜索设备中。。。'})
- await tools._startSearch(Object.assign({
- allowDuplicatesKey: true,
- // services: [],
- // powerLevel: 'high',
- }, data))
- if (option.type == 3 && option.start) option.start()
- let list = await this.bluetoothDeviceFound(option.second, option.type, option.fun)
- if (showLoad) uni.hideLoading()
- resolve(Object.values(list))
- } catch (msg) {
- console.error('getList err', msg)
- if (showLoad) uni.hideLoading()
- showToast(msg, 4000)
- if (option.type == 3 && option.fail) {
- option.fail(msg)
- } else {
- reject()
- }
- }
- })
- }
- /**
- * 过滤并转换附加参数 ok 表示 是否通过过滤
- * @param item
- * @returns item
- */
- filter(item) {
- item.ok = false
- if (this.option.top) {
- let index = item.manufacturerData.search(this.option.top)
- if (this.option.indexJudge) item.ok = this.option.indexJudge(index)
- } else {
- item.ok = true
- }
- if (item.ok) {
- if (this.option.macSlice) item.mac = item.manufacturerData.slice(...this.option.macSlice)
- if (this.option.order) {
- let res = orderSplit(item.manufacturerData, this.option.order)
- for (const resKey in res) {
- item[resKey] = res[resKey]
- }
- }
- if (this.option.judge) item.ok = this.option.judge(item)
- }
- if (this.option.search && !inArray(item.mac, this.option.machine)) item.ok = false
- return item
- }
- /**
- * 过滤设备信息
- * @param second
- * @param type 1 普通模式(只过滤是否符合);
- * 2 指定模式(只有找到一个就会结束,但因为搜索未完全结束可能会返回多个的情况)
- * 3 无限模式
- * @param fun
- * @returns {Promise<unknown>}
- */
- bluetoothDeviceFound(second = 5000, type = 1, fun = null) {
- let list = {}
- return new Promise(async (resolve, reject) => {
- console.log('bleDeviceFound run')
- try {
- this.topClass.bleDeviceFound((res) => {
- res.devices.forEach((item) => {
- item.manufacturerData = ab2hex(item.advertisData)
- // console.log('res.devices.forEach', item)
- if (item.localName != '') {
- // console.log(`bleDeviceFound forEach localName:${item.localName} deviceId:${item.deviceId} manufacturerData:${item.manufacturerData} advertisData:${item.advertisData}`)
- // console.log('res.devices.forEach', item)
- }
- item = this.filter(item)
- // console.log('res.devices.forEach after', item)
- if (item.ok) {
- list[item.deviceId] = item
- if (type == 2) {
- // console.log('type2 stop')
- tools._stopSearchBluetooth();
- throw '已找到设备'
- } else if (type == 3 && fun) {
- fun({
- run: true,
- data: item,
- })
- }
- }
- })
- })
- if (second > 0) {
- await sleep(second)
- // console.log('sleep stop')
- throw '搜索结束'
- }
- } catch (error) {
- // console.log('catch stop')
- await tools._stopSearchBluetooth();
- if (type != 3) {
- } else if (type == 3 && fun) {
- fun({
- run: false,
- })
- }
- this.topClass.bleDeviceFound(null)
- return resolve(Object.values(list))
- }
- })
- }
- async startSearch(data) {
- await tools._startSearch(Object.assign({
- allowDuplicatesKey: true
- }, data))
- }
- stopSearch() {
- /* #ifndef H5 */
- // console.log('stopSearch stop')
- tools._stopSearchBluetooth();
- /* #endif */
- }
- // 二、 蓝牙连接 根据某一id连接设备,4.0
- async connectionBle(deviceId) {
- try {
- if (isH5) throw 'H5无法运行'
- if (this.deviceId && this.deviceId == deviceId) {
- logs('同一台设备,跳出')
- return Promise.resolve() // 已连接设备与当前为同一台
- }
- if (this.deviceId && this.deviceId != deviceId) {
- logs('有旧设备,关闭旧设备中')
- await this.closeConnection() // 结束前一台
- await sleep(500)
- }
- await checkBleAuth() // 检查用户蓝牙授权是否通过
- this.topClass.addConnect(deviceId, this.typeKey)
- this.deviceId = deviceId
- logs('connectBle --- ' + this.deviceId)
- await tools._connectBlue(this.deviceId)
- // await sleep(this.conSevInterval);
- this.serviceId = await this.getBLEServices(this.option.serviceKey)
- await sleep(500)
- const main = await this.getCharacteristics(this.option.channelKey)
- this.writeId = main.writeId // 写入id
- this.characteristicId = main.characteristicId // 写入id
- await tools._notifyBLECharacteristicValueChange(this.deviceId, this.serviceId, this.characteristicId)
- return Promise.resolve()
- } catch (e) {
- await this.closeConnection()
- console.error('connectionBle catch', e)
- return Promise.reject('连接失败')
- }
- }
- async getBLEServices_old(serviceKey) {
- if (!this.deviceId) console.error('获取服务错误,没有deviceId')
- let servicesList = await tools._getBLEServices(this.deviceId)
- if (!servicesList) throw '链接失败,蓝牙未找到服务号'
- logs('开始蓝牙获取服务', servicesList)
- this.sList = servicesList.services
- let uuid = null
- for (let i = 0; i < servicesList.services.length; i++) {
- if (servicesList.services[i].uuid.indexOf(serviceKey) != -1) {
- // this.serviceId = servicesList.services[i].uuid
- uuid = servicesList.services[i].uuid
- return uuid;
- }
- }
- return uuid;
- }
- async getBLEServices(serviceKey) {
- if (!this.deviceId) console.error('获取服务错误,没有deviceId');
- const timeout = new Promise((_, reject) => {
- setTimeout(() => {
- reject(new Error('超时,未能在5秒内获取到服务'));
- }, 5000);
- });
- const getService = async () => {
- let uuid = null;
- for (let i = 0; i < 5; i++) {
- try {
- const servicesList = await tools._getBLEServices(this.deviceId);
- if (servicesList) {
- logs('getService', servicesList);
- this.sList = servicesList.services;
- for (let j = 0; j < servicesList.services.length; j++) {
- if (servicesList.services[j].uuid.indexOf(serviceKey) !== -1) {
- uuid = servicesList.services[j].uuid;
- break; // 找到匹配的 uuid 后退出内层循环
- }
- }
- if (uuid) break; // 找到匹配的 uuid 后退出外层循环
- }
- } catch (error) {
- // 如果获取失败,继续下一次尝试
- console.error('获取服务失败,重试中...');
- }
- await new Promise(resolve => setTimeout(resolve, 1000)); // 等待1秒后重试
- }
- if (uuid) {
- return uuid;
- } else {
- throw new Error('未能在5秒内获取到服务');
- }
- };
- try {
- const uuid = await Promise.race([getService(), timeout]);
- return uuid;
- } catch (error) {
- throw error;
- }
- }
- async getCharacteristics(channelKey = '', obj = {}) {
- logs('开始蓝牙通道信息')
- // 获取通道信息(读、写、监听)
- let writeKey = ''
- let notifyKey = ''
- if (isObject(channelKey)) {
- writeKey = channelKey.writeKey
- notifyKey = channelKey.notifyKey
- } else {
- writeKey = notifyKey = channelKey
- }
- let op = {
- deviceId: this.deviceId,
- serviceId: this.serviceId,
- ...obj
- }
- let {characteristics} = await tools._getCharacteristics(op.deviceId, op.serviceId)
- logs(`开始蓝牙通道信息 writeKey:${writeKey} notifyKey:${notifyKey} characteristics:${characteristics}`)
- let d = {
- writeId: null,
- characteristicId: null,
- }
- for (let i = 0; i < characteristics.length; i++) {
- let item = characteristics[i];
- if (item.uuid.search(writeKey) != -1) {
- d.writeId = item.uuid // 写入id
- }
- if (item.uuid.search(notifyKey) != -1) {
- d.characteristicId = item.uuid // 写入id
- }
- }
- logs(`开始蓝牙通道信息 writeId:${d.writeId} characteristicId:${d.characteristicId}`)
- return d
- }
- /**
- * 关闭设备连接
- * @param deviceId
- * @returns {Promise<void>}
- */
- async closeConnection(deviceId = null) {
- if (deviceId == null) deviceId = this.deviceId
- // 断开已连接的连接
- try {
- if (this.deviceId) await tools._closeBLEConnection(deviceId);
- } catch (e) {
- }
- this.deviceId = null
- this.serviceId = null
- this.writeId = null
- this.characteristicId = null
- this.sList = []
- this.OSList = []
- this.topClass.delConnect(deviceId)
- }
- async sentOrder(str, type = 1, obj = {}) {
- let buffer = type != 0 ? stringToArrayBuffer(str, type) : str
- logs("-- 发送数据: ", ab2hex(buffer, ' '))
- let op = {
- deviceId: this.deviceId,
- serviceId: this.serviceId,
- writeId: this.writeId,
- ...obj
- }
- try {
- /* #ifndef H5 */
- if (this.deviceId) await tools._writeBLECharacteristicValue(op.deviceId, op.serviceId, op.writeId, buffer)
- /* #endif */
- if (op.suc) op.suc()
- return true
- } catch (error) {
- if (error.errCode == 10006) {
- this.topClass.delConnect(this.deviceId, this.typeKey)
- }
- if (op.err) op.err()
- console.error(error)
- logs(`发送出错 基本信息 deviceId:${this.deviceId}, serviceId:${this.serviceId}, writeId:${this.writeId}`)
- logs(error)
- }
- }
- }
|