小程序蓝牙通信例子
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

481 lines
13 KiB

  1. import errToString from "./error";
  2. var util = require('../util');
  3. let PRINT_SHOW = true //是否开启蓝牙调试
  4. let SYSTEM_INFO = {}
  5. let MTU_SIZE = 512
  6. function toPlatformString(systemInfo, str)
  7. {
  8. if (systemInfo.platform == 'android')
  9. return str.toLowerCase();
  10. else if (systemInfo.platform == 'ios')
  11. return str.toUpperCase();
  12. else
  13. return str;
  14. }
  15. function _openAdapter() {
  16. print(`准备初始化蓝牙适配器...`);
  17. wx.getSystemInfo({
  18. success: function (res) {
  19. print(`model: ${res.model}`);
  20. print(`pixelRatio: ${res.pixelRatio}`);
  21. print(`windowWidth: ${res.windowWidth}`);
  22. print(`windowHeight: ${res.windowHeight}`);
  23. print(`language: ${res.language}`);
  24. print(`version: ${res.version}`);
  25. print(`platform: ${res.platform}`);
  26. print(`environment: ${res.environment}`);
  27. SYSTEM_INFO = res;
  28. }
  29. })
  30. return wx.openBluetoothAdapter().then(
  31. (res) => {
  32. print(`✔ 适配器初始化成功!`);
  33. return [null, res]
  34. },
  35. (err) => {
  36. print(`✘ 初始化失败!${errToString(err)}`);
  37. return [errToString(err), null]
  38. }
  39. );
  40. }
  41. /**
  42. * @param {Array<string>} services
  43. * @param { Int } interval
  44. */
  45. function _startSearch() {
  46. print(`准备搜寻附近的蓝牙外围设备...`);
  47. return promisify(wx.startBluetoothDevicesDiscovery, {
  48. services: [this.serviceId], //如果填写了此UUID,那么只会搜索出含有这个UUID的设备
  49. allowDuplicatesKey: false,
  50. interval: 1000
  51. }).then(
  52. (res) => {
  53. print(`✔ 搜索成功!`);
  54. return [null, res]
  55. },
  56. (err) => {
  57. print(`✘ 搜索蓝牙设备失败!${errToString(err)}`);
  58. return [errToString(err), null]
  59. }
  60. );
  61. }
  62. /**
  63. *@param {Array<string>} devices
  64. *@deviceId 设备ID
  65. */
  66. function _onBluetoothFound() {
  67. print(`监听搜寻新设备事件...`);
  68. return _onBluetoothFound_promise.call(this).then(res => {
  69. print(`✔ 设备 ${this.blename} 查找成功!`);
  70. return [null, res]
  71. }, err => {
  72. print(`✘ 设备 ${this.blename} 查找失败!`);
  73. return [errToString(err), null]
  74. })
  75. }
  76. /**
  77. * @param {Array} devices 查找到设备数组
  78. * @param {int} count 计数器-嗅探2次
  79. */
  80. function _onBluetoothFound_promise() {
  81. let devices = []
  82. let count = 0
  83. return new Promise((resolve, reject) => {
  84. wx.onBluetoothDeviceFound(res => {
  85. devices.push(...res.devices)
  86. print(`已嗅探设备数:${devices.length}...`)
  87. print(`已嗅探设备信息:${JSON.stringify(devices)}`)
  88. count++
  89. print(`已嗅探次数:${count}`)
  90. //if (count > 1)
  91. if(devices.length>0)
  92. {
  93. devices.forEach(element => {
  94. if ((element.name && element.name == this.blename) || (element.localName && element.localName == this.blename)) {
  95. this.deviceId = element.deviceId
  96. print(`我的设备Mac:${this.deviceId} `)
  97. print(`我的设备名:${element.name}, ${element.localName}`)
  98. resolve(res)
  99. }
  100. });
  101. }
  102. reject('device not found')
  103. }, err => {
  104. reject(err)
  105. })
  106. })
  107. }
  108. /**
  109. *@param {Array<string>} devices
  110. *@deviceId 设备ID
  111. */
  112. function _getBluetoothDevices() {
  113. print(`监听搜寻新设备事件...`);
  114. let devices = []
  115. return wx.getBluetoothDevices().then(
  116. (res) => {
  117. devices.push(res.devices)
  118. print(`已嗅探设备数:${res.devices.length}...`)
  119. print(`已嗅探设备信息:${JSON.stringify(res.devices)}`)
  120. if(devices.length>0)
  121. {
  122. devices.forEach(element => {
  123. if ((element.name && element.name == this.blename) || (element.localName && element.localName == this.blename)) {
  124. this.deviceId = element.deviceId
  125. print(`我的设备Mac:${this.deviceId} `)
  126. print(`我的设备名:${element.name}, ${element.localName}`)
  127. print(`✔ 设备 ${this.blename} 查找成功!`);
  128. return [null, res]
  129. }
  130. });
  131. }
  132. return [ "暂时没有嗅探到设备 ${this.blename}, 继续嗅探...", null]
  133. },
  134. (err) => {
  135. print(`✘ 设备 ${this.blename} 查找失败!`);
  136. return [errToString(err), null]
  137. }
  138. );
  139. }
  140. function _getBluetoothDevices_1() {
  141. print(`监听搜寻新设备事件...`);
  142. return _getBluetoothDevices_promise.call(this).then(res => {
  143. print(`✔ 设备 ${this.blename} 查找成功!`);
  144. return [null, res]
  145. }, err => {
  146. print(`✘ 设备 ${this.blename} 查找失败!`);
  147. return [errToString(err), null]
  148. })
  149. }
  150. /**
  151. * @param {Array} devices 查找到设备数组
  152. * @param {int} count 计数器-嗅探2次
  153. */
  154. function _getBluetoothDevices_promise() {
  155. let devices = []
  156. print(`1111`)
  157. return new Promise((resolve, reject) => {
  158. print(`2222`)
  159. wx.getBluetoothDevices(res => {
  160. print(`3333`)
  161. devices.push(...res.devices)
  162. print(`已嗅探设备数:${devices.length}...`)
  163. print(`已嗅探设备信息:${JSON.stringify(devices)}`)
  164. if(devices.length>0)
  165. {
  166. devices.forEach(element => {
  167. if ((element.name && element.name == this.blename) || (element.localName && element.localName == this.blename)) {
  168. this.deviceId = element.deviceId
  169. print(`我的设备Mac:${this.deviceId} `)
  170. print(`我的设备名:${element.name}, ${element.localName}`)
  171. resolve(res)
  172. }
  173. });
  174. }
  175. reject('device not found')
  176. }, err => {
  177. print(`4444`)
  178. reject(err)
  179. })
  180. })
  181. }
  182. function _stopSearchBluetooth() {
  183. print(`停止查找新设备...`);
  184. return wx.stopBluetoothDevicesDiscovery().then(
  185. (res) => {
  186. print(`✔ 停止查找设备成功!`);
  187. return [null, res]
  188. },
  189. (err) => {
  190. print(`✘ 停止查询设备失败!${errToString(err)}`);
  191. return [errToString(err), null]
  192. }
  193. );
  194. }
  195. function _connectBlue() {
  196. print(`准备连接设备...`);
  197. return promisify(wx.createBLEConnection, {
  198. deviceId: this.deviceId,
  199. }).then(
  200. (res) => {
  201. print(`✔ 连接蓝牙成功!`);
  202. return [null, res]
  203. },
  204. (err) => {
  205. print(`✘ 连接蓝牙失败!${errToString(err)}`);
  206. return [errToString(err), null]
  207. }
  208. );
  209. }
  210. function _setBLEMTU() {
  211. if (SYSTEM_INFO.platform != 'android')
  212. {
  213. print(`仅安卓手机需要设置MTU Size`);
  214. return ["仅安卓手机需要设置MTU Size", null];
  215. }
  216. print(`准备设置 MTU Size...`);
  217. return promisify(wx.setBLEMTU, {
  218. deviceId: this.deviceId,
  219. mtu:MTU_SIZE
  220. }).then(
  221. (res) => {
  222. //console.log("setBLEMTU success >> " + JSON.stringify(res))
  223. print(`✔ 设置MTU Size = ${MTU_SIZE} 成功!`);
  224. return [null, res]
  225. },
  226. (err) => {
  227. //console.log("setBLEMTU fail >> " + JSON.stringify(res))
  228. print(`✘ 设置MTU Size 失败!`);
  229. return [errToString(err), null]
  230. }
  231. );
  232. }
  233. function _closeBLEConnection() {
  234. print(`断开蓝牙连接...`)
  235. return promisify(wx.closeBLEConnection, {
  236. deviceId: this.deviceId,
  237. }).then(
  238. (res) => {
  239. print(`✔ 断开蓝牙成功!`);
  240. return [null, res]
  241. },
  242. (err) => {
  243. print(`✘ 断开蓝牙连接失败!${errToString(err)}`);
  244. return [errToString(err), null]
  245. }
  246. );
  247. }
  248. function _closeBLEAdapter() {
  249. print(`释放蓝牙适配器...`)
  250. return wx.closeBluetoothAdapter().then(res => {
  251. print(`✔ 释放适配器成功!`)
  252. return [null, res]
  253. }, err => {
  254. print(`✘ 释放适配器失败!${errToString(err)}`)
  255. return [errToString(err), null]
  256. })
  257. }
  258. function _getBLEServices() {
  259. print(`获取蓝牙设备所有服务...`)
  260. return promisify(wx.getBLEDeviceServices, {
  261. deviceId: this.deviceId
  262. }).then(res => {
  263. print(`✔ 获取service成功!`)
  264. console.log('services UUID:\n', JSON.stringify(res.services));
  265. for (var i = 0; i < res.services.length; i++) {
  266. console.log("第"+(i+1) + "个UUID:" + res.services[i].uuid+"\n")
  267. }
  268. return [null, res]
  269. }, err => {
  270. print(`✘ 获取service失败!${errToString(err)}`)
  271. return [errToString(err), null]
  272. })
  273. }
  274. function _getCharacteristics() {
  275. print(`开始获取特征值...`);
  276. return promisify(wx.getBLEDeviceCharacteristics, {
  277. deviceId: this.deviceId,
  278. serviceId: toPlatformString(SYSTEM_INFO, this.serviceId),//具有写、通知属性的服务uuid
  279. }).then(
  280. (res) => {
  281. print(`✔ 获取特征值成功!`);
  282. for (let i = 0; i < res.characteristics.length; i++) {
  283. let item = res.characteristics[i];
  284. if (item.properties.read) {
  285. this.readCharacteristicId = item.uuid;
  286. print(`readCharacteristicId:${item.uuid}`)
  287. }
  288. if (item.properties.write && !item.properties.read) {
  289. this.writeCharacteristicId = item.uuid;
  290. print(`writeCharacteristicId:${item.uuid}`)
  291. }
  292. if (item.properties.notify || item.properties.indicate) {
  293. this.notifyCharacteristicId = item.uuid;
  294. print(`notifyCharacteristicId:${item.uuid}`)
  295. }
  296. }
  297. return [null, res]
  298. },
  299. (err) => {
  300. print(`✘ 获取特征值失败!${errToString(err)}`);
  301. return [errToString(err), null]
  302. }
  303. );
  304. }
  305. // 订阅特征值
  306. function _notifyBLECharacteristicValueChange() {
  307. return promisify(wx.notifyBLECharacteristicValueChange, {
  308. deviceId: this.deviceId,
  309. serviceId: toPlatformString(SYSTEM_INFO, this.serviceId),
  310. characteristicId: toPlatformString(SYSTEM_INFO, this.notifyCharacteristicId),
  311. state: true
  312. }).then(res => {
  313. print(`✔ 订阅notify成功!`)
  314. return [null, res]
  315. }, err => {
  316. print(`✘ 订阅notify失败!${errToString(err)}`)
  317. return [errToString(err), null]
  318. })
  319. }
  320. /**
  321. * 指令封装
  322. * @param {Array} data
  323. */
  324. function _sentOrder(cmd, payload){
  325. print(`开始封装指令...`)
  326. let data = payload
  327. let payloadLength = data.length;
  328. let length = 13 + payload.length
  329. let b = new Uint8Array(length);
  330. b[0] = 0x89;
  331. b[1] = 0x89;
  332. b[2] = cmd;
  333. let timestamp = new Date().getTime();
  334. let ts = timestamp.toString(16)
  335. let t = util.timeStringToBytes(ts, 12)
  336. b.set(t, 4)
  337. b[3] = b[9];
  338. b[10] = (payloadLength>>8)&0xff;
  339. b[11] = payloadLength & 0xff;
  340. let key = b[3];
  341. for (let i=0; i<payloadLength; i++) {
  342. data[i] -= (payloadLength - i) ^ key;
  343. data[i] = (data[i] ^ (key ^ i));
  344. }
  345. b.set(data, 12)
  346. let xor = b[0];
  347. for (let i=1; i<length-1; i++)
  348. xor ^= b[i];
  349. b[length-1] = xor;
  350. print(`✔ 封装成功! ${b}`)
  351. return b;
  352. }
  353. function _writeBLECharacteristicValue(data) {
  354. return promisify(wx.writeBLECharacteristicValue, {
  355. deviceId: this.deviceId,
  356. serviceId: toPlatformString(SYSTEM_INFO, this.serviceId),
  357. characteristicId: toPlatformString(SYSTEM_INFO, this.writeCharacteristicId),
  358. value: data,
  359. }).then(res => {
  360. print(`✔ 写入数据成功!`)
  361. return [null, res]
  362. }, err => {
  363. print(`✘ 写入数据失败!${errToString(err)}`)
  364. return [errToString(err), null]
  365. })
  366. }
  367. /**
  368. * 对微信接口的promise封装
  369. * @param {function} fn
  370. * @param {object} args
  371. */
  372. function promisify(fn, args) {
  373. return new Promise((resolve, reject) => {
  374. fn({
  375. ...(args || {}),
  376. success: (res) => resolve(res),
  377. fail: (err) => reject(err),
  378. });
  379. });
  380. }
  381. /**
  382. * 对微信接口回调函数的封装
  383. * @param {function} fn
  384. */
  385. function promisify_callback(fn) {
  386. return new Promise((resolve, reject) => {
  387. fn(
  388. (res) => {
  389. resolve(res);
  390. },
  391. (rej) => {
  392. reject(rej);
  393. }
  394. );
  395. });
  396. }
  397. function print(str) {
  398. PRINT_SHOW ? console.log(str) : null;
  399. }
  400. export {
  401. print,
  402. _getCharacteristics,
  403. _connectBlue,
  404. _setBLEMTU,
  405. _getBLEServices,
  406. _closeBLEConnection,
  407. _closeBLEAdapter,
  408. _stopSearchBluetooth,
  409. _notifyBLECharacteristicValueChange,
  410. _onBluetoothFound,
  411. _getBluetoothDevices,
  412. _startSearch,
  413. _openAdapter,
  414. _sentOrder,
  415. _writeBLECharacteristicValue,
  416. promisify,
  417. promisify_callback,
  418. };