index.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. import * as tools from "./tools"
  2. import {inArray, isObject, logs, sleep} from "../util";
  3. import {showToast} from "../app";
  4. import {checkBleAuth} from "../uniFunction";
  5. import {ab2hex, stringToArrayBuffer} from "./hex";
  6. import {isH5} from "@/utils/platform";
  7. import Vue from "vue";
  8. /**
  9. * 蓝牙工具类
  10. * 封装小程序蓝牙流程方法
  11. * 处理事件通信
  12. */
  13. export class bleBase {
  14. constructor(topClass) {
  15. this.topClass = topClass
  16. this.typeKey = ''
  17. this.option = {}
  18. this.deviceId = null
  19. this.serviceId = null
  20. this.writeId = null // 写入id
  21. this.characteristicId = null// 接收id
  22. }
  23. /**
  24. * 搜索蓝牙设备
  25. * @param data
  26. * @param op
  27. * @param showLoad
  28. * @returns {Promise<unknown>}
  29. */
  30. getList(data = {}, op = {}, showLoad = true) {
  31. let option = {
  32. second: 5000,
  33. type: 1,
  34. fun: null,
  35. }
  36. option = Object.assign(option, op)
  37. return new Promise(async (resolve, reject) => {
  38. logs('进入 searchBle')
  39. try {
  40. await this.topClass.init()
  41. if (isH5) throw 'H5不支持蓝牙功能'
  42. await checkBleAuth() // 检查用户蓝牙授权是否通过
  43. if (showLoad) uni.showLoading({title: '搜索设备中。。。'})
  44. await tools._startSearch(Object.assign({
  45. allowDuplicatesKey: true
  46. }, data))
  47. let list = await this.bluetoothDeviceFound(option.second, option.type, option.fun)
  48. if (showLoad) uni.hideLoading()
  49. resolve(Object.values(list))
  50. } catch (msg) {
  51. if (showLoad) uni.hideLoading()
  52. showToast(msg, 4000)
  53. resolve(new Object())
  54. }
  55. })
  56. }
  57. /**
  58. * 过滤并转换附加参数 ok 表示 是否通过过滤
  59. * @param item
  60. * @returns item
  61. */
  62. filter(item) {
  63. item.ok = false
  64. if (this.option.top) {
  65. let index = item.manufacturerData.search(this.option.top)
  66. if (this.option.indexJudge) item.ok = this.option.indexJudge(index)
  67. } else {
  68. item.ok = true
  69. }
  70. if (item.ok && this.option.macSlice) item.mac = item.manufacturerData.slice(...this.option.macSlice)
  71. if (this.option.search && !inArray(item.mac, this.option.machine)) item.ok = !1
  72. return item
  73. }
  74. /**
  75. * 过滤设备信息
  76. * @param second
  77. * @param type 1 普通模式(只过滤是否符合);
  78. * 2 指定模式(只有找到一个就会结束,但因为搜索未完全结束可能会返回多个的情况)
  79. * 3 无限模式
  80. * @param fun
  81. * @returns {Promise<unknown>}
  82. */
  83. bluetoothDeviceFound(second = 5000, type = 1, fun = null) {
  84. let list = {}
  85. return new Promise(async (resolve, reject) => {
  86. try {
  87. this.topClass.bleDeviceFound((res) => {
  88. res.devices.forEach((item) => {
  89. item.manufacturerData = ab2hex(item.advertisData)
  90. item = this.filter(item)
  91. if (item.ok) {
  92. list[item.deviceId] = item
  93. if (type == 2) {
  94. tools._stopSearchBluetooth();
  95. throw '已找到设备'
  96. } else if (type == 3 && fun) {
  97. fun({
  98. run: true,
  99. data: item,
  100. })
  101. }
  102. }
  103. })
  104. })
  105. if (second > 0) {
  106. await sleep(second)
  107. throw '搜索结束'
  108. }
  109. } catch (error) {
  110. if (type != 3) {
  111. await tools._stopSearchBluetooth();
  112. } else if (type == 3 && fun) {
  113. fun({
  114. run: false,
  115. })
  116. }
  117. this.topClass.bleDeviceFound(null)
  118. return resolve(Object.values(list))
  119. }
  120. })
  121. }
  122. async startSearch(data) {
  123. await tools._startSearch(Object.assign({
  124. allowDuplicatesKey: true
  125. }, data))
  126. }
  127. stopSearch() {
  128. /* #ifndef H5 */
  129. tools._stopSearchBluetooth();
  130. /* #endif */
  131. }
  132. // 二、 蓝牙连接 根据某一id连接设备,4.0
  133. async connectionBle(deviceId) {
  134. try {
  135. if (isH5) throw 'H5无法运行'
  136. if (this.deviceId && this.deviceId == deviceId) {
  137. logs('同一台设备,跳出')
  138. return Promise.resolve() // 已连接设备与当前为同一台
  139. }
  140. if (this.deviceId && this.deviceId != deviceId) {
  141. logs('有旧设备,关闭旧设备中')
  142. await this.closeConnection() // 结束前一台
  143. await sleep(500)
  144. }
  145. this.topClass.addConnect(deviceId, this.typeKey)
  146. this.deviceId = deviceId
  147. logs('connectBle --- ' + this.deviceId)
  148. await tools._connectBlue(this.deviceId)
  149. await sleep(2000);
  150. await this.getBLEServices(this.option.serviceKey)
  151. await this.getCharacteristics(this.option.channelKey)
  152. await tools._notifyBLECharacteristicValueChange(this.deviceId, this.serviceId, this.characteristicId)
  153. return Promise.resolve()
  154. } catch (e) {
  155. await this.closeConnection()
  156. console.log('connectionBle catch', e)
  157. return Promise.reject('连接失败')
  158. }
  159. }
  160. async getBLEServices(serviceKey) {
  161. logs('开始蓝牙获取服务')
  162. let servicesList = await tools._getBLEServices(this.deviceId)
  163. if (!servicesList) throw '链接失败,蓝牙未找到服务号'
  164. logs('开始蓝牙获取服务', servicesList)
  165. for (let i = 0; i < servicesList.services.length; i++) {
  166. if (servicesList.services[i].isPrimary && (servicesList.services[i].uuid.indexOf(serviceKey) != -1)) {
  167. this.serviceId = servicesList.services[i].uuid
  168. return;
  169. }
  170. }
  171. }
  172. async getCharacteristics(channelKey = '') {
  173. logs('开始蓝牙通道信息')
  174. // 获取通道信息(读、写、监听)
  175. let writeKey = ''
  176. let notifyKey = ''
  177. if (isObject(channelKey)) {
  178. writeKey = channelKey.writeKey
  179. notifyKey = channelKey.notifyKey
  180. } else {
  181. writeKey = notifyKey = channelKey
  182. }
  183. let {characteristics} = await tools._getCharacteristics(this.deviceId, this.serviceId)
  184. logs(`开始蓝牙通道信息 writeKey:${writeKey} notifyKey:${notifyKey} characteristics:${characteristics}`)
  185. for (let i = 0; i < characteristics.length; i++) {
  186. let item = characteristics[i];
  187. if (item.uuid.search(writeKey) != -1) {
  188. this.writeId = item.uuid // 写入id
  189. }
  190. if (item.uuid.search(notifyKey) != -1) {
  191. this.characteristicId = item.uuid // 写入id
  192. }
  193. }
  194. logs(`开始蓝牙通道信息 writeId:${this.writeId} characteristicId:${this.characteristicId}`)
  195. }
  196. /**
  197. * 关闭设备连接
  198. * @param deviceId
  199. * @returns {Promise<void>}
  200. */
  201. async closeConnection(deviceId = '') {
  202. if (!deviceId) deviceId = this.deviceId
  203. // 断开已连接的连接
  204. try {
  205. if (this.deviceId) await tools._closeBLEConnection(deviceId);
  206. } catch (e) {
  207. }
  208. this.deviceId = null
  209. this.serviceId = null
  210. this.writeId = null
  211. this.characteristicId = null
  212. this.topClass.delConnect(deviceId)
  213. }
  214. async sentOrder(str, type = 1) {
  215. let buffer = type != 0 ? stringToArrayBuffer(str, type) : str
  216. logs("-- 发送数据: ", ab2hex(buffer, ' '))
  217. try {
  218. /* #ifndef H5 */
  219. if (this.deviceId) await tools._writeBLECharacteristicValue(this.deviceId, this.serviceId, this.writeId, buffer)
  220. /* #endif */
  221. return true
  222. } catch (error) {
  223. if (error.errCode == 10006) {
  224. this.topClass.delConnect(this.deviceId, this.typeKey)
  225. }
  226. console.error(error)
  227. logs(`发送出错 基本信息 deviceId:${this.deviceId}, serviceId:${this.serviceId}, writeId:${this.writeId}`)
  228. logs(error)
  229. }
  230. }
  231. }