ble_manager.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. // 引入必要的微信小程序 API
  2. // const wx = require('wx');
  3. class bleManager {
  4. constructor() {
  5. var that = this;
  6. that.isAvailable = false;
  7. that.hasPermission = false;
  8. that.scanDevices = [];
  9. that.publicDevice = null;
  10. ///用来对比列表
  11. that.compareList = [];
  12. that.searching = false;
  13. }
  14. ///获取比较的数据
  15. getCompareList() {
  16. return this.compareList;
  17. }
  18. ///处理当前正在连接中,对比暂停
  19. setSearching(search) {
  20. this.searching = search;
  21. }
  22. getSearching() {
  23. return this.searching;
  24. }
  25. /// 监控蓝牙打开状态
  26. initBluetoothAdapter() {
  27. var that = this;
  28. wx.onBluetoothAdapterStateChange(function (res) {
  29. that.isAvailable = res.available;
  30. })
  31. }
  32. ///监听搜索设备列表
  33. getBluetoothDevices(callBack, toCompare) {
  34. var that = this;
  35. wx.onBluetoothDeviceFound(function (res) {
  36. ///第一种情况
  37. if (res.deviceId) {
  38. if (!toCompare) {
  39. if (res.name == getApp().globalData.connectWillDevice.clientType) {
  40. res.advertisData = res.advertisData ? that.buf2hex(res.advertisData) : '';
  41. callBack(res);
  42. }
  43. } else {
  44. if (res.name != "") {
  45. if (that.compareList.length > 0) {
  46. var has = false;
  47. for (var i = 0; i < that.compareList.length; i++) {
  48. if (res.deviceId == that.compareList[i].deviceId) {
  49. has = true;
  50. break;
  51. }
  52. }
  53. if (!has) {
  54. that.compareList.push(res);
  55. }
  56. } else {
  57. that.compareList.push(res);
  58. }
  59. }
  60. }
  61. }
  62. ///第二种情况
  63. else if (res.devices) {
  64. if (!toCompare) {
  65. for (var i = 0; i < res.devices.length; i++) {
  66. var temp = res.devices[i];
  67. if (temp.name == getApp().globalData.connectWillDevice.clientType) {
  68. temp.advertisData = temp.advertisData ? that.buf2hex(temp.advertisData) : '';
  69. callBack(temp);
  70. break;
  71. }
  72. }
  73. } else {
  74. for (var i = 0; i < res.devices.length; i++) {
  75. if (that.compareList.length > 0) {
  76. var has = false;
  77. for (var j = 0; j < that.compareList.length; j++) {
  78. if (res.devices[i].name != "") {
  79. if (res.devices[i].deviceId == that.compareList[j].deviceId) {
  80. has = true;
  81. break;
  82. }
  83. }
  84. }
  85. if (!has) {
  86. that.compareList.push(res.devices[i]);
  87. }
  88. } else {
  89. that.compareList.push(res.devices[i]);
  90. }
  91. }
  92. }
  93. }
  94. ///第三种情况
  95. else if (res[0]) {
  96. if (!toCompare) {
  97. if (res[0].name == getApp().globalData.connectWillDevice.clientType) {
  98. res[0].advertisData = res[0].advertisData ? that.buf2hex(res[0].advertisData) : '';
  99. callBack(res[0]);
  100. }
  101. } else {
  102. if (res[0].name != "") {
  103. if (that.compareList.length > 0) {
  104. var has = false;
  105. for (var i = 0; i < that.compareList.length; i++) {
  106. if (res[0].deviceId == that.compareList[i].deviceId) {
  107. has = true;
  108. break;
  109. }
  110. }
  111. if (!has) {
  112. that.compareList.push(res[0]);
  113. }
  114. } else {
  115. that.compareList.push(res[0]);
  116. }
  117. }
  118. }
  119. }
  120. });
  121. }
  122. ///获取数据
  123. buf2hex(buffer) {
  124. return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
  125. }
  126. // 开始搜索蓝牙设备
  127. startScan(boolean) {
  128. var that = this;
  129. wx.closeBluetoothAdapter({
  130. complete: function (res) {
  131. wx.openBluetoothAdapter({
  132. success: function (res) {
  133. wx.getBluetoothAdapterState({
  134. success: function (res) {},
  135. fail(err) {
  136. boolean(false);
  137. },
  138. })
  139. wx.startBluetoothDevicesDiscovery({
  140. allowDuplicatesKey: false,
  141. success: function (res) {
  142. boolean(true);
  143. that.compareList = [];
  144. },
  145. fail(err) {},
  146. })
  147. },
  148. fail: function (res) {
  149. wx.showModal({
  150. title: '提示',
  151. content: '请检查手机蓝牙是否打开',
  152. showCancel: false,
  153. success: function (res) {}
  154. });
  155. boolean(false);
  156. }
  157. })
  158. }
  159. })
  160. }
  161. // 停止搜索
  162. stopSearch() {
  163. return new Promise((resolve, reject) => {
  164. wx.stopBluetoothDevicesDiscovery({
  165. success: (res) => {
  166. console.log('停止搜索成功:', res);
  167. resolve(res);
  168. },
  169. fail: (err) => {
  170. console.error('停止搜索失败:', err);
  171. reject(new Error('停止搜索失败'));
  172. }
  173. });
  174. });
  175. }
  176. closeBle() {
  177. console.log('关闭蓝牙了')
  178. closeBluetoothAdapter();
  179. }
  180. // 断开与指定设备的连接
  181. disconnect() {
  182. var that = this;
  183. let device = that.publicDevice ?? {};
  184. let deviceId = device.deviceId ?? ""
  185. if (deviceId.length === 0) {
  186. return;
  187. }
  188. return new Promise((resolve, reject) => {
  189. wx.closeBLEConnection({
  190. deviceId: that.publicDevice.deviceId ?? "",
  191. success: (res) => {
  192. that.publicDevice = null;
  193. console.log('断开连接成功:', res);
  194. resolve(res);
  195. },
  196. fail: (err) => {
  197. console.error('断开连接失败:', err);
  198. reject(new Error('断开连接失败'));
  199. }
  200. });
  201. });
  202. }
  203. // 发送数据到指定设备
  204. async sendData(data) {
  205. var that = this
  206. return new Promise((resolve, reject) => {
  207. var buffer = null;
  208. // todo 判断是否是buffer
  209. // if (Buffer.isBuffer(data)) {
  210. // buffer = data;
  211. // } else {
  212. buffer = new ArrayBuffer(data.length);
  213. // 下面是赋值,不能删
  214. const dataView = new DataView(buffer);
  215. data.forEach((value, index) => {
  216. dataView.setUint8(index, value); // 将每个16进制数值写入到 buffer 中
  217. });
  218. // }
  219. console.log('开始发送数据:', data, buffer);
  220. wx.writeBLECharacteristicValue({
  221. deviceId: that.publicDevice.deviceId,
  222. serviceId: that.publicDevice.serviceId,
  223. characteristicId: that.publicDevice.characteristicId,
  224. value: buffer,
  225. success: (res) => {
  226. // console.log('数据发送成功:');
  227. resolve(res);
  228. },
  229. fail: (err) => {
  230. console.error('数据发送失败:', err);
  231. reject(new Error('数据发送失败'));
  232. }
  233. });
  234. });
  235. }
  236. ab2hex(buffer) {
  237. var hexArr = Array.prototype.map.call(
  238. new Uint8Array(buffer),
  239. function (bit) {
  240. return ('00' + bit.toString(16)).slice(-2)
  241. }
  242. )
  243. return hexArr.join(':');
  244. }
  245. fiterDevice(res) {
  246. var that = this;
  247. var devices = res.devices.filter(device => {
  248. const name = device.name || '';
  249. const localName = device.localName || '';
  250. let isNot = that.isNotEmpty(name) || that.isNotEmpty(localName);
  251. if (isNot) {
  252. // console.log('是猫王设备名称:', device.advertisData, device.serviceData)
  253. let mac = that.ab2hex(device.advertisData)
  254. // console.log(mac)
  255. device.mac = mac
  256. }
  257. return isNot
  258. });
  259. let newDevices = devices.map((device) => {
  260. let uuid = device.advertisServiceUUIDs[0] ?? ""
  261. return {
  262. deviceId: device.deviceId,
  263. name: device.name,
  264. localName: device.localName,
  265. uuid: uuid,
  266. mac: device.mac,
  267. connectable: device.connectable
  268. }
  269. });
  270. return newDevices
  271. }
  272. isNotEmpty(name) {
  273. let isNot = (name !== '' &&
  274. (name.startsWith("MW_") ||
  275. name.startsWith("MW-") ||
  276. // name.startsWith("猫王") ||
  277. // name.startsWith("妙播") ||
  278. // name.startsWith("AirSmart") ||
  279. name === "le")
  280. )
  281. // if (!isNot && name !== '') {
  282. // console.log('不是猫王设备名称:', name)
  283. // }
  284. return isNot;
  285. }
  286. // 连接到指定设备
  287. async connectToDevice(device) {
  288. var that = this;
  289. return new Promise((resolve, reject) => {
  290. console.log("开始连接蓝牙:", device.deviceId)
  291. wx.createBLEConnection({
  292. deviceId: device.deviceId,
  293. success: (res) => {
  294. that.publicDevice = device
  295. console.log('连接成功:', res);
  296. resolve(true);
  297. },
  298. fail: (err) => {
  299. that.publicDevice = null
  300. console.error('连接失败:', err);
  301. resolve(false);
  302. }
  303. });
  304. });
  305. }
  306. // 发现服务
  307. discoverServices(deviceId) {
  308. var that = this;
  309. console.log('发现服务:', deviceId);
  310. return new Promise((resolve, reject) => {
  311. wx.getBLEDeviceServices({
  312. deviceId: deviceId,
  313. success: (res) => {
  314. // that.publicDevice .services = res.services;
  315. let service_id = "";
  316. for (let i = 0; i < res.services.length; i++) {
  317. if (res.services[i].uuid.toUpperCase().indexOf("AB00") != -1 ||
  318. res.services[i].uuid.toUpperCase().indexOf("FFC0") != -1
  319. // res.services[i].uuid.toUpperCase().indexOf("ae800") != -1
  320. ) {
  321. service_id = res.services[i].uuid;
  322. break;
  323. }
  324. console.log('发现服务1:', service_id);
  325. service_id = res.services[i].uuid;
  326. }
  327. that.publicDevice.serviceId = service_id;
  328. console.log('发现服务2:', service_id);
  329. resolve(service_id);
  330. // resolve(res.services);
  331. },
  332. fail: (err) => {
  333. that.publicDevice.serviceId = null;
  334. console.error('发现服务失败:', err);
  335. reject([]);
  336. }
  337. });
  338. });
  339. }
  340. // 发现特征值 read / write
  341. discoverCharacteristics(deviceId, serviceId) {
  342. var that = this;
  343. console.log('发现特征值:' + deviceId + " , " + serviceId);
  344. // if (deviceId !== that.publicDevice .deviceId) {
  345. // console.log('设备id不匹配')
  346. // return false
  347. // }
  348. return new Promise((resolve, reject) => {
  349. wx.getBLEDeviceCharacteristics({
  350. deviceId: deviceId,
  351. serviceId: serviceId,
  352. success: (res) => {
  353. // that.characteristics[serviceId] = res.characteristics;
  354. console.log('发现特征值2:', res);
  355. // that.publicDevice .characteristics = res.characteristics;
  356. resolve(res.characteristics);
  357. },
  358. fail: (err) => {
  359. that.publicDevice.characteristics = null;
  360. console.error('发现特征值失败:', err);
  361. reject("");
  362. }
  363. });
  364. });
  365. }
  366. // 读取特征值
  367. readCharacteristicValue(characteristicId) {
  368. var that = ths;
  369. console.log('开始读取特征值', characteristicId)
  370. return new Promise((resolve, reject) => {
  371. wx.readBLECharacteristicValue({
  372. deviceId: that.publicDevice.deviceId,
  373. serviceId: that.publicDevice.serviceId,
  374. characteristicId: characteristicId,
  375. success: (res) => {
  376. const name = that.parseBLEValue(res.value); // 解析读取到的值
  377. console.log('读取特征值成功:', name, res);
  378. resolve(res);
  379. },
  380. fail: (err) => {
  381. console.error('读取特征值失败:', err);
  382. reject("");
  383. }
  384. });
  385. });
  386. }
  387. // 解析读取到的设备名称
  388. parseBLEValue(buffer) {
  389. return String.fromCharCode.apply(null, new Uint8Array(buffer));
  390. }
  391. // 监听特征值变化
  392. notifyCharacteristicValueChange(characteristicId, callback) {
  393. var that = this;
  394. console.log('监听特征值变化:', characteristicId, that.publicDevice.deviceId, that.publicDevice.serviceId);
  395. wx.notifyBLECharacteristicValueChange({
  396. deviceId: that.publicDevice.deviceId, //设备mac IOS和安卓系统不一样
  397. serviceId: that.publicDevice.serviceId, //服务通道,这里主要是notify
  398. characteristicId: characteristicId, //notify uuid
  399. state: true,
  400. success: function (res) {
  401. console.log("开启notify 成功")
  402. //TODO onBLECharacteristicValueChange 监听特征值 设备的数据在这里获取到
  403. wx.onBLECharacteristicValueChange(function (characteristic) {
  404. let buffer = characteristic.value
  405. let dataView = new DataView(buffer)
  406. let dataResult = []
  407. for (let i = 0; i < dataView.byteLength; i++) {
  408. // console.log("0x" + dataView.getUint8(i).toString(16))
  409. // dataResult.push("0x" + dataView.getUint8(i).toString(16))
  410. dataResult.push(dataView.getUint8(i))
  411. }
  412. const result = dataResult
  413. console.log("拿到的数据:", result)
  414. if (callback) {
  415. callback(result)
  416. }
  417. })
  418. },
  419. fail: function (res) {
  420. console.log("订阅特征失败:", res)
  421. }
  422. })
  423. }
  424. setWrite(wirte, characteristicId) {
  425. var that = this;
  426. console.log('写入特征值:', characteristicId)
  427. // that.publicDevice .wirte = wirte
  428. that.publicDevice.characteristicId = characteristicId;
  429. }
  430. }
  431. // const ble = new bleManager();
  432. // 导出 bleManager 类
  433. module.exports = bleManager;
  434. // wx.getSetting({
  435. // success(res) {
  436. // if (res.authSetting["scope.userFuzzyLocation"]) {
  437. // // 成功
  438. // // that.getBluetoothStatus();
  439. // console.log("有定位权限")
  440. // resolve(true);
  441. // } else if (res.authSetting["scope.userFuzzyLocation"] === undefined) {
  442. // wx.authorize({
  443. // scope: "scope.userFuzzyLocation",
  444. // success() {
  445. // console.log("再次获取定位权限")
  446. // resolve(that.getSetting());
  447. // }
  448. // });
  449. // } else {
  450. // wx.showModal({
  451. // title: '请打开系统位置获取定位权限',
  452. // success(res) {
  453. // if (res.confirm) {
  454. // console.log('用户点击确定')
  455. // wx.openSetting({
  456. // complete() {
  457. // // that.getSetting();
  458. // // resolve(that.getSetting());
  459. // }
  460. // })
  461. // } else if (res.cancel) {
  462. // console.log('用户点击取消');
  463. // }
  464. // }
  465. // })
  466. // console.log("没有有定位权限")
  467. // reject(false);
  468. // }
  469. // }
  470. // })
  471. // // 获取已连接的蓝牙设备
  472. // getConnectedDevices() {
  473. // var that = this;
  474. // if (!that.isAvailable && !that.hasPermission) {
  475. // return [];
  476. // }
  477. // return new Promise((resolve, reject) => {
  478. // wx.getConnectedBluetoothDevices({
  479. // // services: ["FFC0", "ffc0", "FFC1", "FFC2", "ffc1", "ffc2", "AB00", "ab00", "AB01", "AB02", "FFF1", "fff1", "FFE2", "FFE5",],
  480. // // services: ["ab00", "ffe5", "1111", "FFC0", "FFC1", "FFF1", ],
  481. // // services: [],
  482. // // services: [
  483. // // "0000ab00-0000-1000-8000-00805f9b34fb",
  484. // // "0000ffc0-0000-1000-8000-00805f9b34fb",
  485. // // "0000FFF0-0000-1000-8000-00805F9B34FB",
  486. // // "0000FFF1-0000-1000-8000-00805F9B34FB",
  487. // // "0000FFE5-0000-1000-8000-00805F9B34FB",
  488. // // ],
  489. // success: (res) => {
  490. // console.log('已连接的蓝牙设备==11==:', newDevices);
  491. // let newDevices = that.fiterDevice(res)
  492. // console.log('已连接的蓝牙设备==22==:', newDevices);
  493. // resolve(newDevices);
  494. // },
  495. // fail: (err) => {
  496. // console.error('获取已连接的蓝牙设备失败:', err);
  497. // reject([]);
  498. // }
  499. // });
  500. // });
  501. // }