ble_manager.js 17 KB

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