ecBLEWX.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. const regeneratorRuntime = require('./regenerator/runtime.js')
  2. const logEnable = false
  3. let isAndroid = false
  4. let ecBluetoothAdapterStateChangeCallback = () => {}
  5. let ecBLEConnectionStateChangeCallback = () => {}
  6. let ecDeviceId = ''
  7. let ecGattServerUUID = ''
  8. const ecGattServerUUIDOption1 = '0000FFF0-0000-1000-8000-00805F9B34FB'
  9. const ecGattServerUUIDOption2 = 'FFF0'
  10. let ecGattCharacteristicWriteUUID = ''
  11. const ecGattCharacteristicWriteUUIDOption1 = '0000FFF2-0000-1000-8000-00805F9B34FB'
  12. const ecGattCharacteristicWriteUUIDOption2 = 'FFF2'
  13. const log = data => {
  14. if (logEnable) {
  15. console.log('[eciot]:' + JSON.stringify(data))
  16. }
  17. }
  18. const onBluetoothAdapterStateChange = cb => {
  19. ecBluetoothAdapterStateChangeCallback = cb
  20. }
  21. const getSetting = () => {
  22. return new Promise(function (resolve, reject) {
  23. wx.getSetting({
  24. success(res) {
  25. log(res)
  26. if (res.authSetting && res.authSetting['scope.bluetooth']) {
  27. resolve({ ok: true, errCode: 0, errMsg: '' })
  28. } else {
  29. resolve({
  30. ok: false,
  31. errCode: 30001,
  32. errMsg: 'getSetting fail',
  33. })
  34. }
  35. },
  36. fail(res) {
  37. log(res)
  38. resolve({
  39. ok: false,
  40. errCode: res.errCode ? res.errCode : 30000,
  41. errMsg: res.errMsg ? res.errMsg : 'getSetting fail',
  42. })
  43. },
  44. })
  45. })
  46. }
  47. const authorize = () => {
  48. return new Promise(function (resolve, reject) {
  49. wx.authorize({
  50. scope: 'scope.bluetooth',
  51. success(res) {
  52. log(res)
  53. resolve({ ok: true, errCode: 0, errMsg: '' })
  54. },
  55. fail(res) {
  56. log(res)
  57. // {"errMsg":"authorize:fail:auth deny"}
  58. resolve({ ok: false, errCode: 30000, errMsg: res.errMsg })
  59. },
  60. })
  61. })
  62. }
  63. const _openBluetoothAdapter = () => {
  64. return new Promise(function (resolve, reject) {
  65. wx.openBluetoothAdapter({
  66. success(res) {
  67. log(res)
  68. // {errno: 0, errMsg: "openBluetoothAdapter:ok"}
  69. resolve({ ok: true, errCode: 0, errMsg: '' })
  70. },
  71. fail(res) {
  72. log(res)
  73. resolve({
  74. ok: false,
  75. errCode: res.errCode ? res.errCode : 30000,
  76. errMsg: res.errMsg,
  77. })
  78. },
  79. })
  80. })
  81. }
  82. const openBluetoothAdapter = async () => {
  83. await _openBluetoothAdapter()
  84. const systemInfo = wx.getSystemInfoSync()
  85. log(systemInfo)
  86. if (systemInfo.platform.toLowerCase() === 'android') {
  87. isAndroid = true
  88. }
  89. if (!systemInfo.bluetoothEnabled) {
  90. ecBluetoothAdapterStateChangeCallback({
  91. ok: false,
  92. errCode: 30001,
  93. errMsg: '请打开系统蓝牙开关',
  94. })
  95. return
  96. }
  97. if (isAndroid && !systemInfo.locationEnabled) {
  98. ecBluetoothAdapterStateChangeCallback({
  99. ok: false,
  100. errCode: 30002,
  101. errMsg: '请打开系统定位开关',
  102. })
  103. return
  104. }
  105. if (isAndroid && !systemInfo.locationAuthorized) {
  106. ecBluetoothAdapterStateChangeCallback({
  107. ok: false,
  108. errCode: 30003,
  109. errMsg: '请打开微信定位权限,允许微信使用您的位置信息',
  110. })
  111. return
  112. }
  113. const setting = await getSetting() //小程序蓝牙权限
  114. if (!setting.ok) {
  115. const authRes = await authorize()
  116. if (!authRes.ok) {
  117. ecBluetoothAdapterStateChangeCallback({
  118. ok: false,
  119. errCode: 30004,
  120. errMsg: '请打开小程序蓝牙开关,点击右上角三个点,然后点击设置',
  121. })
  122. return
  123. }
  124. }
  125. wx.offBluetoothAdapterStateChange()
  126. wx.onBluetoothAdapterStateChange(res => {
  127. log(res) // {available: true, discovering: true}
  128. if (!res.available) {
  129. ecBluetoothAdapterStateChangeCallback({
  130. ok: false,
  131. errCode: 30005,
  132. errMsg: '蓝牙适配器不可用',
  133. })
  134. }
  135. })
  136. const openRes = await _openBluetoothAdapter()
  137. ecBluetoothAdapterStateChangeCallback(openRes)
  138. }
  139. const onBluetoothDeviceFound = cb => {
  140. wx.offBluetoothDeviceFound()
  141. wx.onBluetoothDeviceFound(res => {
  142. log(res)
  143. const device = res.devices[0]
  144. const name = device.name ? device.name : device.localName
  145. if (!name) {
  146. return
  147. }
  148. let id = device.deviceId
  149. let rssi = device.RSSI
  150. cb({ id, name, rssi })
  151. })
  152. }
  153. const startBluetoothDevicesDiscovery = () => {
  154. wx.startBluetoothDevicesDiscovery({
  155. //services: [ecServerId],
  156. allowDuplicatesKey: true,
  157. powerLevel: 'high',
  158. complete(res) {
  159. log(res)
  160. },
  161. })
  162. }
  163. const stopBluetoothDevicesDiscovery = () => {
  164. wx.stopBluetoothDevicesDiscovery({
  165. complete(res) {
  166. // {errno: 0, errMsg: "stopBluetoothDevicesDiscovery:ok", isDiscovering: false}
  167. log(res)
  168. },
  169. })
  170. }
  171. const onBLEConnectionStateChange = cb => {
  172. ecBLEConnectionStateChangeCallback = cb
  173. }
  174. const _createBLEConnection = () => {
  175. return new Promise(function (resolve, reject) {
  176. wx.createBLEConnection({
  177. deviceId: ecDeviceId,
  178. success(res) {
  179. log(res)
  180. // {"errno":0,"errCode":0,"errMsg":"createBLEConnection:ok"}
  181. resolve({ ok: true, errCode: 0, errMsg: '' })
  182. },
  183. fail(res) {
  184. log(res)
  185. // {"errno":1001,"errMsg":"createBLEConnection:fail parameter error: parameter.deviceId should be String instead of Undefined;"}
  186. resolve({
  187. ok: false,
  188. errCode: res.errCode ? res.errCode : res.errno,
  189. errMsg: res.errMsg,
  190. })
  191. },
  192. })
  193. })
  194. }
  195. const getBLEDeviceServices = () => {
  196. return new Promise(function (resolve, reject) {
  197. wx.getBLEDeviceServices({
  198. deviceId: ecDeviceId,
  199. success(res) {
  200. log(res)
  201. //{"services":[{"uuid":"0000FFF0-0000-1000-8000-00805F9B34FB","isPrimary":true}],"errCode":0,"errno":0,"errMsg":"getBLEDeviceServices:ok"}
  202. // {"errno":0,"deviceId":"7C7E20F2-CB75-6DA8-F8DF-FFF702B0D63F","services":[{"isPrimary":true,"uuid":"0000FFF0-0000-1000-8000-00805F9B34FB"}],"errMsg":"getBLEDeviceServices:ok","errCode":0}
  203. resolve({
  204. ok: true,
  205. errCode: 0,
  206. errMsg: '',
  207. services: res.services,
  208. })
  209. },
  210. fail(res) {
  211. log(res)
  212. resolve({ ok: false, errCode: res.errCode, errMsg: res.errMsg })
  213. },
  214. })
  215. })
  216. }
  217. const getBLEDeviceCharacteristics = serviceId => {
  218. return new Promise(function (resolve, reject) {
  219. wx.getBLEDeviceCharacteristics({
  220. deviceId: ecDeviceId,
  221. serviceId,
  222. success(res) {
  223. log(res)
  224. // {"characteristics":[{"uuid":"0000FFF2-0000-1000-8000-00805F9B34FB","handle":3,"properties":{"read":false,"write":true,"notify":false,"indicate":false,"writeNoResponse":true,"writeDefault":true}},{"uuid":"0000FFF1-0000-1000-8000-00805F9B34FB","handle":5,"properties":{"read":true,"write":true,"notify":true,"indicate":false,"writeNoResponse":true,"writeDefault":true}}],"errCode":0,"errno":0,"errMsg":"getBLEDeviceCharacteristics:ok"}
  225. // {"characteristics":[{"properties":{"writeDefault":true,"notify":false,"write":true,"indicate":false,"read":false,"writeNoResponse":true},"uuid":"0000FFF2-0000-1000-8000-00805F9B34FB"},{"properties":{"writeDefault":true,"notify":true,"write":true,"indicate":false,"read":true,"writeNoResponse":true},"uuid":"0000FFF1-0000-1000-8000-00805F9B34FB"}],"deviceId":"7C7E20F2-CB75-6DA8-F8DF-FFF702B0D63F","serviceId":"0000FFF0-0000-1000-8000-00805F9B34FB","errno":0,"errMsg":"getBLEDeviceCharacteristics:ok","errCode":0}
  226. resolve({
  227. ok: true,
  228. errCode: 0,
  229. errMsg: '',
  230. characteristics: res.characteristics,
  231. })
  232. },
  233. fail(res) {
  234. log(res)
  235. resolve({ ok: false, errCode: res.errCode, errMsg: res.errMsg })
  236. },
  237. })
  238. })
  239. }
  240. const notifyBLECharacteristicValueChange = (serviceId, characteristicId) => {
  241. return new Promise(function (resolve, reject) {
  242. wx.notifyBLECharacteristicValueChange({
  243. state: true,
  244. deviceId: ecDeviceId,
  245. serviceId,
  246. characteristicId,
  247. success(res) {
  248. log(res)
  249. // {"errCode":0,"errno":0,"errMsg":"notifyBLECharacteristicValueChange:ok"}
  250. resolve({ ok: true, errCode: 0, errMsg: '' })
  251. },
  252. fail(res) {
  253. log(res)
  254. resolve({ ok: false, errCode: res.errCode, errMsg: res.errMsg })
  255. },
  256. })
  257. })
  258. }
  259. const setBLEMTU = mtu => {
  260. return new Promise(function (resolve, reject) {
  261. wx.setBLEMTU({
  262. deviceId: ecDeviceId,
  263. mtu,
  264. success(res) {
  265. log(res)
  266. // {"errMsg":"setBLEMTU:ok","errno":0,"errCode":0,"mtu":50}
  267. resolve({ ok: true, errCode: 0, errMsg: '' })
  268. },
  269. fail(res) {
  270. log(res)
  271. // {"errCode":-1,"errno":1500104,"errMsg":"setBLEMTU:fail:internal error"}
  272. resolve({ ok: false, errCode: res.errCode, errMsg: res.errMsg })
  273. },
  274. })
  275. })
  276. }
  277. //和设备建立连接
  278. const createBLEConnection = async id => {
  279. ecDeviceId = id
  280. wx.offBLEConnectionStateChange()
  281. wx.onBLEConnectionStateChange(async res => {
  282. log(res)
  283. // {"deviceId":"EC:22:05:13:78:49","connected":true}
  284. if (res.connected) {
  285. const servicesResult = await getBLEDeviceServices()
  286. if (!servicesResult.ok) {
  287. ecBLEConnectionStateChangeCallback(servicesResult)
  288. closeBLEConnection()
  289. return
  290. }
  291. for (const service of servicesResult.services) {
  292. if ((service.uuid.toUpperCase() === ecGattServerUUIDOption1) ||
  293. (service.uuid.toUpperCase() === ecGattServerUUIDOption2)) {
  294. ecGattServerUUID = service.uuid
  295. }
  296. const characteristicsResult = await getBLEDeviceCharacteristics(
  297. service.uuid
  298. )
  299. if (!characteristicsResult.ok) {
  300. ecBLEConnectionStateChangeCallback(characteristicsResult)
  301. closeBLEConnection()
  302. return
  303. }
  304. for (const characteristic of characteristicsResult.characteristics) {
  305. if (
  306. characteristic.properties &&
  307. characteristic.properties.notify
  308. ) {
  309. const notifyResult =
  310. await notifyBLECharacteristicValueChange(
  311. service.uuid,
  312. characteristic.uuid
  313. )
  314. if (!notifyResult.ok) {
  315. ecBLEConnectionStateChangeCallback({
  316. ok: false,
  317. errCode: 30000,
  318. errMsg: 'notify error',
  319. })
  320. closeBLEConnection()
  321. return
  322. }
  323. }
  324. if ((characteristic.uuid.toUpperCase() === ecGattCharacteristicWriteUUIDOption1) ||
  325. (characteristic.uuid.toUpperCase() === ecGattCharacteristicWriteUUIDOption2)) {
  326. ecGattCharacteristicWriteUUID = characteristic.uuid
  327. }
  328. }
  329. }
  330. if (isAndroid) {
  331. await setBLEMTU(247)
  332. }
  333. ecBLEConnectionStateChangeCallback({
  334. ok: true,
  335. errCode: 0,
  336. errMsg: '',
  337. })
  338. } else {
  339. ecBLEConnectionStateChangeCallback({
  340. ok: false,
  341. errCode: 0,
  342. errMsg: 'disconnect',
  343. })
  344. }
  345. })
  346. const res = await _createBLEConnection()
  347. if (!res.ok) {
  348. ecBLEConnectionStateChangeCallback(res)
  349. }
  350. }
  351. //关闭当前连接
  352. const closeBLEConnection = () => {
  353. wx.closeBLEConnection({
  354. deviceId: ecDeviceId,
  355. complete(res) {
  356. log(res)
  357. },
  358. })
  359. }
  360. const onBLECharacteristicValueChange = cb => {
  361. wx.offBLECharacteristicValueChange()
  362. wx.onBLECharacteristicValueChange(res => {
  363. log(res)
  364. let x = new Uint8Array(res.value)
  365. log(x)
  366. let str = utf8BytesToStr(x)
  367. let strHex = ''
  368. for (let i = 0; i < x.length; i++) {
  369. strHex =
  370. strHex + x[i].toString(16).padStart(2, '0').toUpperCase()
  371. }
  372. log(str)
  373. log(strHex)
  374. cb(str, strHex)
  375. })
  376. }
  377. const _writeBLECharacteristicValue = buffer => {
  378. return new Promise(function (resolve, reject) {
  379. wx.writeBLECharacteristicValue({
  380. deviceId: ecDeviceId,
  381. serviceId: ecGattServerUUID,
  382. characteristicId: ecGattCharacteristicWriteUUID,
  383. value: buffer,
  384. writeType: 'writeNoResponse',
  385. success(res) {
  386. log(res)
  387. // {"errno":0,"errCode":0,"errMsg":"writeBLECharacteristicValue:ok"}
  388. resolve({ ok: true, errCode: 0, errMsg: '' })
  389. },
  390. fail(res) {
  391. log(res)
  392. resolve({ ok: false, errCode: res.errCode, errMsg: res.errMsg })
  393. },
  394. })
  395. })
  396. }
  397. const writeBLECharacteristicValue = async (str, isHex) => {
  398. if (str.length === 0)
  399. return { ok: false, errCode: 30000, errMsg: 'data is null' }
  400. let buffer
  401. if (isHex) {
  402. buffer = new ArrayBuffer(str.length / 2)
  403. let x = new Uint8Array(buffer)
  404. for (let i = 0; i < x.length; i++) {
  405. x[i] = parseInt(str.substr(2 * i, 2), 16)
  406. }
  407. } else {
  408. buffer = new Uint8Array(strToUtf8Bytes(str)).buffer
  409. }
  410. return await _writeBLECharacteristicValue(buffer)
  411. }
  412. const utf8BytesToStr = utf8Bytes => {
  413. let unicodeStr = ''
  414. for (let pos = 0; pos < utf8Bytes.length; ) {
  415. let flag = utf8Bytes[pos]
  416. let unicode = 0
  417. if (flag >>> 7 === 0) {
  418. unicodeStr += String.fromCharCode(utf8Bytes[pos])
  419. pos += 1
  420. }
  421. // else if ((flag & 0xFC) === 0xFC) {
  422. // unicode = (utf8Bytes[pos] & 0x3) << 30
  423. // unicode |= (utf8Bytes[pos + 1] & 0x3F) << 24
  424. // unicode |= (utf8Bytes[pos + 2] & 0x3F) << 18
  425. // unicode |= (utf8Bytes[pos + 3] & 0x3F) << 12
  426. // unicode |= (utf8Bytes[pos + 4] & 0x3F) << 6
  427. // unicode |= (utf8Bytes[pos + 5] & 0x3F)
  428. // unicodeStr += String.fromCharCode(unicode)
  429. // pos += 6
  430. // }
  431. // else if ((flag & 0xF8) === 0xF8) {
  432. // unicode = (utf8Bytes[pos] & 0x7) << 24
  433. // unicode |= (utf8Bytes[pos + 1] & 0x3F) << 18
  434. // unicode |= (utf8Bytes[pos + 2] & 0x3F) << 12
  435. // unicode |= (utf8Bytes[pos + 3] & 0x3F) << 6
  436. // unicode |= (utf8Bytes[pos + 4] & 0x3F)
  437. // unicodeStr += String.fromCharCode(unicode)
  438. // pos += 5
  439. // }
  440. else if ((flag & 0xf0) === 0xf0) {
  441. unicode = (utf8Bytes[pos] & 0xf) << 18
  442. unicode |= (utf8Bytes[pos + 1] & 0x3f) << 12
  443. unicode |= (utf8Bytes[pos + 2] & 0x3f) << 6
  444. unicode |= utf8Bytes[pos + 3] & 0x3f
  445. unicodeStr += String.fromCharCode(unicode)
  446. pos += 4
  447. } else if ((flag & 0xe0) === 0xe0) {
  448. unicode = (utf8Bytes[pos] & 0x1f) << 12
  449. unicode |= (utf8Bytes[pos + 1] & 0x3f) << 6
  450. unicode |= utf8Bytes[pos + 2] & 0x3f
  451. unicodeStr += String.fromCharCode(unicode)
  452. pos += 3
  453. } else if ((flag & 0xc0) === 0xc0) {
  454. //110
  455. unicode = (utf8Bytes[pos] & 0x3f) << 6
  456. unicode |= utf8Bytes[pos + 1] & 0x3f
  457. unicodeStr += String.fromCharCode(unicode)
  458. pos += 2
  459. } else {
  460. unicodeStr += String.fromCharCode(utf8Bytes[pos])
  461. pos += 1
  462. }
  463. }
  464. return unicodeStr
  465. }
  466. const strToUtf8Bytes = str => {
  467. let bytes = []
  468. for (let i = 0; i < str.length; ++i) {
  469. let code = str.charCodeAt(i)
  470. if (code >= 0x10000 && code <= 0x10ffff) {
  471. bytes.push((code >> 18) | 0xf0) // 第一个字节
  472. bytes.push(((code >> 12) & 0x3f) | 0x80)
  473. bytes.push(((code >> 6) & 0x3f) | 0x80)
  474. bytes.push((code & 0x3f) | 0x80)
  475. } else if (code >= 0x800 && code <= 0xffff) {
  476. bytes.push((code >> 12) | 0xe0)
  477. bytes.push(((code >> 6) & 0x3f) | 0x80)
  478. bytes.push((code & 0x3f) | 0x80)
  479. } else if (code >= 0x80 && code <= 0x7ff) {
  480. bytes.push((code >> 6) | 0xc0)
  481. bytes.push((code & 0x3f) | 0x80)
  482. } else {
  483. bytes.push(code)
  484. }
  485. }
  486. return bytes
  487. }
  488. module.exports = {
  489. onBluetoothAdapterStateChange,
  490. openBluetoothAdapter,
  491. onBluetoothDeviceFound,
  492. startBluetoothDevicesDiscovery,
  493. stopBluetoothDevicesDiscovery,
  494. onBLEConnectionStateChange,
  495. createBLEConnection,
  496. closeBLEConnection,
  497. onBLECharacteristicValueChange,
  498. writeBLECharacteristicValue,
  499. }