xBlufi-wx-impl.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. // 全局状态变量
  2. let tempTimer = 0;
  3. let client = null;
  4. let util = null;
  5. let mDeviceEvent = null;
  6. let crypto = null;
  7. let md5 = null;
  8. let aesjs = null;
  9. const timeOut = 20; // 超时时间
  10. let timeId = "";
  11. let sequenceControl = 0;
  12. // let sequenceNumber = -1; // 此变量在代码中未被使用,可以移除
  13. // _self 对象用于维护单个连接会话的状态
  14. let _self = {
  15. data: {
  16. deviceId: null,
  17. isConnected: false,
  18. failure: false,
  19. value: 0,
  20. desc: "请耐心等待...",
  21. isChecksum: true,
  22. isEncrypt: true,
  23. flagEnd: false,
  24. defaultData: 1,
  25. ssidType: 2,
  26. passwordType: 3,
  27. meshIdType: 3,
  28. ssid: "",
  29. password: "",
  30. meshId: "",
  31. uuid: "",
  32. serviceId: "",
  33. processList: [],
  34. result: [],
  35. service_uuid: "0000FFFF-0000-1000-8000-00805F9B34FB",
  36. characteristic_write_uuid: "0000FF01-0000-1000-8000-00805F9B34FB",
  37. characteristic_read_uuid: "0000FF02-0000-1000-8000-00805F9B34FB",
  38. customData: null,
  39. md5Key: 0,
  40. }
  41. };
  42. // =================================================================
  43. // 辅助/工具函数 (已优化)
  44. // =================================================================
  45. /**
  46. * 将 ArrayBuffer 转换为十六进制字符串
  47. * @param {ArrayBuffer} buffer
  48. * @returns {string}
  49. */
  50. function buf2hex(buffer) {
  51. return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
  52. }
  53. /**
  54. * [优化] 将 ArrayBuffer (字节数组) 转换为字符串。
  55. * 使用 TextDecoder API,性能更高且能正确处理 UTF-8 编码。
  56. * @param {ArrayBuffer} buffer
  57. * @returns {string}
  58. */
  59. function buf2string(buffer) {
  60. try {
  61. const dataView = new DataView(buffer);
  62. // 微信小程序环境支持 TextDecoder
  63. const decoder = new TextDecoder('utf-8');
  64. return decoder.decode(dataView);
  65. } catch (e) {
  66. // 降级处理,以防极旧环境不支持
  67. const arr = Array.prototype.map.call(new Uint8Array(buffer), x => x);
  68. let str = '';
  69. for (let i = 0; i < arr.length; i++) {
  70. str += String.fromCharCode(arr[i]);
  71. }
  72. return decodeURIComponent(escape(str));
  73. }
  74. }
  75. /**
  76. * [优化] 将字符串转换为 UTF-8 编码的字节数组。
  77. * 使用 TextEncoder API,性能远超手动循环,且编码更标准。
  78. * @param {string} str
  79. * @returns {number[]}
  80. */
  81. function stringToUtf8Bytes(str) {
  82. try {
  83. // 微信小程序环境支持 TextEncoder
  84. const encoder = new TextEncoder();
  85. return Array.from(encoder.encode(str));
  86. } catch (e) {
  87. // 降级处理
  88. return unescape(encodeURIComponent(str)).split("").map(val => val.charCodeAt());
  89. }
  90. }
  91. /**
  92. * [优化] 判断并处理返回的数据帧,提取负载数据。
  93. * 简化了原有的 if/else 重复逻辑。
  94. * @param {string[]} fragNum - 帧控制字段的二进制数组
  95. * @param {number[]} list - 原始数据包
  96. * @param {any} md5Key - MD5密钥
  97. * @returns {number[]} - 提取出的负载数据
  98. */
  99. function parsePayload(fragNum, list, md5Key) {
  100. let payload = list;
  101. // 步骤1: 如果有校验和,则移除末尾的校验位
  102. if (fragNum[6] == "1") {
  103. payload = payload.slice(0, payload.length - 2);
  104. }
  105. // 步骤2: 根据是否加密进行解密 (当前代码中解密逻辑未实现,仅预留位置)
  106. if (fragNum[7] == "1") {
  107. // 返回数据已加密
  108. // let iv = this.generateAESIV(parseInt(payload[2], 16));
  109. // 在此处添加解密逻辑...
  110. }
  111. // 步骤3: 根据是否分包,移除帧头,提取有效数据
  112. if (fragNum[3] == "0") { // 未分包
  113. _self.data.flagEnd = true;
  114. return payload.slice(4);
  115. } else { // 分包
  116. _self.data.flagEnd = false;
  117. return payload.slice(6);
  118. }
  119. }
  120. // =================================================================
  121. // BLE 核心写入函数
  122. // =================================================================
  123. /**
  124. * 发送安全协商数据 (P, G, K)
  125. * @param {string} deviceId
  126. * @param {string} serviceId
  127. * @param {string} characteristicId
  128. * @param {object} client - DH 客户端实例
  129. * @param {number[]} kBytes - 公钥
  130. * @param {number[]} pBytes - P
  131. * @param {number[]} gBytes - G
  132. * @param {number[]|null} data - 分包后的剩余数据
  133. */
  134. function getSecret(deviceId, serviceId, characteristicId, client, kBytes, pBytes, gBytes, data) {
  135. let obj = {};
  136. let frameControl = 0;
  137. sequenceControl = parseInt(sequenceControl) + 1;
  138. if (!util._isEmpty(data)) {
  139. obj = util.isSubcontractor(data, true, sequenceControl);
  140. frameControl = util.getFrameCTRLValue(false, true, util.DIRECTION_OUTPUT, false, obj.flag);
  141. } else {
  142. let payload = [];
  143. payload.push(util.NEG_SET_SEC_ALL_DATA);
  144. const pLength = pBytes.length;
  145. payload.push((pLength >> 8) & 0xff, pLength & 0xff, ...pBytes);
  146. const gLength = gBytes.length;
  147. payload.push((gLength >> 8) & 0xff, gLength & 0xff, ...gBytes);
  148. const kLength = kBytes.length;
  149. payload.push((kLength >> 8) & 0xff, kLength & 0xff, ...kBytes);
  150. obj = util.isSubcontractor(payload, true, sequenceControl);
  151. frameControl = util.getFrameCTRLValue(false, true, util.DIRECTION_OUTPUT, false, obj.flag);
  152. }
  153. const value = util.writeData(util.PACKAGE_VALUE, util.SUBTYPE_NEG, frameControl, sequenceControl, obj.len, obj.lenData);
  154. const typedArray = new Uint8Array(value);
  155. wx.writeBLECharacteristicValue({
  156. deviceId: deviceId,
  157. serviceId: serviceId,
  158. characteristicId: characteristicId,
  159. value: typedArray.buffer,
  160. success: function (res) {
  161. if (obj.flag) { // 如果有剩余数据,则继续发送
  162. getSecret(deviceId, serviceId, characteristicId, client, kBytes, pBytes, gBytes, obj.laveData);
  163. }
  164. },
  165. fail: function (res) {
  166. console.error("getSecret failed:", res, { deviceId, serviceId, characteristicId });
  167. }
  168. });
  169. }
  170. /**
  171. * [新增] 通用的数据包发送函数,用于取代原先多个重复的 writeXXX 函数
  172. * @param {number} subType - 包的子类型
  173. * @param {number[]} dataPayload - 要发送的原始数据负载
  174. * @param {function} onSuccess - 发送成功(且无分包)后的回调函数
  175. */
  176. function sendBlufiDataPacket(subType, dataPayload, onSuccess) {
  177. const deviceId = _self.data.deviceId;
  178. const serviceId = _self.data.service_uuid;
  179. const characteristicId = _self.data.characteristic_write_uuid;
  180. function writePacket(remainingData) {
  181. sequenceControl = parseInt(sequenceControl) + 1;
  182. // 检查是否需要分包
  183. const obj = util.isSubcontractor(remainingData, _self.data.isChecksum, sequenceControl, _self.data.isEncrypt);
  184. const frameControl = util.getFrameCTRLValue(_self.data.isEncrypt, _self.data.isChecksum, util.DIRECTION_OUTPUT, false, obj.flag);
  185. // 加密数据
  186. const encryptedData = util.encrypt(aesjs, _self.data.md5Key, sequenceControl, obj.lenData, true);
  187. // 组装最终数据包
  188. const value = util.writeData(util.PACKAGE_VALUE, subType, frameControl, sequenceControl, obj.len, encryptedData);
  189. const typedArray = new Uint8Array(value);
  190. wx.writeBLECharacteristicValue({
  191. deviceId: deviceId,
  192. serviceId: serviceId,
  193. characteristicId: characteristicId,
  194. value: typedArray.buffer,
  195. success: function (res) {
  196. if (obj.flag) {
  197. // 如果有分包,继续发送剩余数据
  198. writePacket(obj.laveData);
  199. } else if (onSuccess) {
  200. // 发送完成,执行成功回调
  201. onSuccess();
  202. }
  203. },
  204. fail: function (res) {
  205. console.error(`sendBlufiDataPacket failed for subType ${subType}:`, res);
  206. }
  207. });
  208. }
  209. // 启动第一次写入
  210. writePacket(dataPayload);
  211. }
  212. function writeDeviceRouterInfoStart() {
  213. const payload = [_self.data.defaultData];
  214. const onSuccess = () => writeRouterSsid();
  215. // 注意:此处的 subType 需要根据你的 util 库定义来确定
  216. sendBlufiDataPacket(util.SUBTYPE_WIFI_MODEl, payload, onSuccess);
  217. }
  218. function writeRouterSsid() {
  219. const ssidData = stringToUtf8Bytes(_self.data.ssid);
  220. const onSuccess = () => writeDevicePwd();
  221. sendBlufiDataPacket(util.SUBTYPE_SET_SSID, ssidData, onSuccess);
  222. }
  223. function writeDevicePwd() {
  224. const pwdData = stringToUtf8Bytes(_self.data.password);
  225. const onSuccess = () => writeDeviceEnd();
  226. sendBlufiDataPacket(util.SUBTYPE_SET_PWD, pwdData, onSuccess);
  227. }
  228. function writeCutomsData() {
  229. const customDataBytes = stringToUtf8Bytes(_self.data.customData);
  230. // 自定义数据发送后通常没有下一步,所以 onSuccess 为 null
  231. sendBlufiDataPacket(util.SUBTYPE_CUSTOM_DATA, customDataBytes, null);
  232. }
  233. /**
  234. * 发送结束指令
  235. */
  236. function writeDeviceEnd() {
  237. sequenceControl = parseInt(sequenceControl) + 1;
  238. const frameControl = util.getFrameCTRLValue(_self.data.isEncrypt, false, util.DIRECTION_OUTPUT, false, false);
  239. const value = util.writeData(_self.data.PACKAGE_CONTROL_VALUE, util.SUBTYPE_END, frameControl, sequenceControl, 0, null);
  240. const typedArray = new Uint8Array(value);
  241. wx.writeBLECharacteristicValue({
  242. deviceId: _self.data.deviceId,
  243. serviceId: _self.data.service_uuid,
  244. characteristicId: _self.data.characteristic_write_uuid,
  245. value: typedArray.buffer,
  246. success: function (res) {},
  247. fail: function (res) {}
  248. });
  249. }
  250. /**
  251. * 发送获取附近Wi-Fi列表的指令
  252. */
  253. function writeGetNearRouterSsid() {
  254. const deviceId = _self.data.deviceId;
  255. const serviceId = _self.data.service_uuid;
  256. const characteristicId = _self.data.characteristic_write_uuid;
  257. sequenceControl = parseInt(sequenceControl) + 1;
  258. const frameControl = util.getFrameCTRLValue(_self.data.isEncrypt, false, util.DIRECTION_OUTPUT, false, false);
  259. const value = util.writeData(util.PACKAGE_CONTROL_VALUE, util.SUBTYPE_WIFI_NEG, frameControl, sequenceControl, 0, null);
  260. const typedArray = new Uint8Array(value);
  261. wx.writeBLECharacteristicValue({
  262. deviceId: deviceId,
  263. serviceId: serviceId,
  264. characteristicId: characteristicId,
  265. value: typedArray.buffer,
  266. success: function (res) {},
  267. fail: function (res) {}
  268. });
  269. }
  270. // =================================================================
  271. // 事件监听与主逻辑
  272. // =================================================================
  273. function init() {
  274. // 加载依赖
  275. mDeviceEvent = require('./xBlufi.js');
  276. util = require('@/utils/blufi/util.js');
  277. crypto = require('@/utils/blufi/crypto/crypto-dh.js');
  278. md5 = require('@/utils/blufi/crypto/md5.min.js');
  279. aesjs = require('@/utils/blufi/crypto/aes.js');
  280. // 监听蓝牙连接状态变化
  281. wx.onBLEConnectionStateChange(function (res) {
  282. const obj = {
  283. 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_STATUS_CONNECTED,
  284. 'result': res.connected,
  285. 'data': res
  286. };
  287. mDeviceEvent.notifyDeviceMsgEvent(obj);
  288. });
  289. // 监听开始扫描蓝牙设备事件
  290. mDeviceEvent.listenStartDiscoverBle(true, function (options) {
  291. if (options.isStart) {
  292. wx.closeBluetoothAdapter({
  293. complete: function (res) {
  294. wx.openBluetoothAdapter({
  295. success: function (res) {
  296. wx.startBluetoothDevicesDiscovery({
  297. allowDuplicatesKey: true,
  298. success: function (res) {
  299. const devicesList = [];
  300. const foundDevices = new Set(); // 使用 Set 来快速去重
  301. mDeviceEvent.notifyDeviceMsgEvent({
  302. 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS_START,
  303. 'result': true,
  304. 'data': res
  305. });
  306. wx.onBluetoothDeviceFound(function (deviceRes) {
  307. const device = deviceRes.devices[0];
  308. if (device && device.deviceId && !foundDevices.has(device.deviceId)) {
  309. foundDevices.add(device.deviceId);
  310. devicesList.push({
  311. ...device,
  312. advertisData: device.advertisData ? buf2hex(device.advertisData) : ''
  313. });
  314. mDeviceEvent.notifyDeviceMsgEvent({
  315. 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS,
  316. 'result': true,
  317. 'data': [...devicesList] // 发送列表的副本
  318. });
  319. }
  320. });
  321. },
  322. fail: function (res) {
  323. mDeviceEvent.notifyDeviceMsgEvent({ 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS_START, 'result': false, 'data': res });
  324. }
  325. });
  326. },
  327. fail: function (res) {
  328. mDeviceEvent.notifyDeviceMsgEvent({ 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS_START, 'result': false, 'data': res });
  329. }
  330. });
  331. }
  332. });
  333. } else {
  334. wx.stopBluetoothDevicesDiscovery({
  335. success: function (res) {
  336. mDeviceEvent.notifyDeviceMsgEvent({ 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS_STOP, 'result': true, 'data': res });
  337. },
  338. fail: function (res) {
  339. mDeviceEvent.notifyDeviceMsgEvent({ 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS_STOP, 'result': false, 'data': res });
  340. }
  341. });
  342. }
  343. });
  344. // 监听连接/断开蓝牙设备事件 (按要求,此函数未修改)
  345. mDeviceEvent.listenConnectBle(true, function (options) {
  346. //console.log("我要连接?", (options.isStart))
  347. if (options.isStart)
  348. wx.createBLEConnection({
  349. deviceId: options.deviceId,
  350. success: function (res) {
  351. wx.setBLEMTU({
  352. deviceId: options.deviceId,
  353. mtu: 128
  354. })
  355. _self.data.deviceId = options.deviceId
  356. mDeviceEvent.notifyDeviceMsgEvent({
  357. 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_CONNECTED,
  358. 'result': true,
  359. 'data': {
  360. deviceId: options.deviceId,
  361. name: options.name
  362. },
  363. });
  364. },
  365. fail: function (res) {
  366. _self.data.deviceId = null
  367. mDeviceEvent.notifyDeviceMsgEvent({
  368. 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_CONNECTED,
  369. 'result': false,
  370. 'data': res,
  371. });
  372. }
  373. });
  374. else wx.closeBLEConnection({
  375. deviceId: options.deviceId,
  376. success: function (res) {
  377. console.log('断开成功')
  378. _self.data.deviceId = null
  379. mDeviceEvent.notifyDeviceMsgEvent({
  380. 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_CLOSE_CONNECTED,
  381. 'result': true,
  382. 'data': {
  383. deviceId: options.deviceId,
  384. name: options.name
  385. }
  386. });
  387. },
  388. fail: function (res) {
  389. _self.data.deviceId = null
  390. mDeviceEvent.notifyDeviceMsgEvent({
  391. 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_CLOSE_CONNECTED,
  392. 'result': false,
  393. 'data': res,
  394. });
  395. }
  396. })
  397. });
  398. // 监听初始化ESP32(BluFi流程)事件
  399. mDeviceEvent.listenInitBleEsp32(true, function (options) {
  400. // 重置状态
  401. sequenceControl = 0;
  402. _self.data.result = [];
  403. _self.data.deviceId = options.deviceId;
  404. wx.getBLEDeviceServices({
  405. deviceId: options.deviceId,
  406. success: function (res) {
  407. const service = res.services.find(s => s.uuid === _self.data.service_uuid);
  408. if (!service) {
  409. throw new Error("Blufi service not found");
  410. }
  411. const serviceId = service.uuid;
  412. wx.getBLEDeviceCharacteristics({
  413. deviceId: options.deviceId,
  414. serviceId: serviceId,
  415. success: function (charRes) {
  416. const writeChar = charRes.characteristics.find(c => c.uuid === _self.data.characteristic_write_uuid);
  417. const readChar = charRes.characteristics.find(c => c.uuid === _self.data.characteristic_read_uuid);
  418. if (!writeChar || !readChar) {
  419. throw new Error("Blufi characteristics not found");
  420. }
  421. _self.data.serviceId = serviceId;
  422. _self.data.uuid = writeChar.uuid;
  423. wx.notifyBLECharacteristicValueChange({
  424. state: true,
  425. deviceId: options.deviceId,
  426. serviceId: serviceId,
  427. characteristicId: readChar.uuid,
  428. success: function (notifyRes) {
  429. // 启用通知成功,开始安全协商
  430. client = util.blueDH(util.DH_P, util.DH_G, crypto);
  431. const kBytes = util.uint8ArrayToArray(client.getPublicKey());
  432. const pBytes = util.hexByInt(util.DH_P);
  433. const gBytes = util.hexByInt(util.DH_G);
  434. const pgkLength = pBytes.length + gBytes.length + kBytes.length + 6;
  435. const data = [
  436. util.NEG_SET_SEC_TOTAL_LEN,
  437. (pgkLength >> 8) & 0xff,
  438. pgkLength & 0xff
  439. ];
  440. const frameControl = util.getFrameCTRLValue(false, false, util.DIRECTION_OUTPUT, false, false);
  441. const value = util.writeData(util.PACKAGE_VALUE, util.SUBTYPE_NEG, frameControl, sequenceControl, data.length, data);
  442. const typedArray = new Uint8Array(value);
  443. wx.writeBLECharacteristicValue({
  444. deviceId: options.deviceId,
  445. serviceId: serviceId,
  446. characteristicId: writeChar.uuid,
  447. value: typedArray.buffer,
  448. success: function (writeRes) {
  449. getSecret(options.deviceId, serviceId, writeChar.uuid, client, kBytes, pBytes, gBytes, null);
  450. },
  451. fail: (err) => mDeviceEvent.notifyDeviceMsgEvent({ 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_INIT_ESP32_RESULT, 'result': false, 'data': err })
  452. });
  453. // 监听从设备返回的数据
  454. wx.onBLECharacteristicValueChange(function (changeRes) {
  455. const list2 = (util.ab2hex(changeRes.value));
  456. if (list2.length < 4) { return; }
  457. const val = parseInt(list2[0], 16);
  458. const type = val & 3;
  459. const subType = val >> 2;
  460. // 使用优化后的 payload 解析函数
  461. const fragNum = util.hexToBinArray(list2[1]);
  462. const payload = parsePayload(fragNum, list2, _self.data.md5Key);
  463. _self.data.result = _self.data.result.concat(payload);
  464. if (_self.data.flagEnd) {
  465. const resultData = [..._self.data.result];
  466. _self.data.result = []; // 清空缓存
  467. if (type == 1) { // Type: Data
  468. console.log("Receive data, subType: ", subType);
  469. switch (subType) {
  470. case util.SUBTYPE_NEGOTIATION_NEG: // 安全协商响应
  471. const arr = util.hexByInt(resultData.join(""));
  472. const clientSecret = client.computeSecret(new Uint8Array(arr));
  473. _self.data.md5Key = md5.array(clientSecret);
  474. mDeviceEvent.notifyDeviceMsgEvent({
  475. 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_INIT_ESP32_RESULT,
  476. 'result': true,
  477. 'data': { deviceId: options.deviceId, serviceId, characteristicId: writeChar.uuid }
  478. });
  479. break;
  480. case 15: // Wi-Fi连接状态报告
  481. const stationStatus = String.fromCharCode(...resultData.map(hex => parseInt(hex, 16)));
  482. mDeviceEvent.notifyDeviceMsgEvent({
  483. 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_CONNECT_ROUTER_RESULT,
  484. 'result': resultData.length > 3,
  485. 'data': { 'progress': 100, 'status': stationStatus }
  486. });
  487. break;
  488. case 17: // 附近Wi-Fi列表
  489. getList(resultData);
  490. break;
  491. case 19: // 自定义数据
  492. const customDataStr = String.fromCharCode(...resultData.map(hex => parseInt(hex, 16)));
  493. mDeviceEvent.notifyDeviceMsgEvent({
  494. 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_RECIEVE_CUSTON_DATA,
  495. 'result': true,
  496. 'data': customDataStr
  497. });
  498. break;
  499. default:
  500. console.log("Unhandled data subType:", subType);
  501. break;
  502. }
  503. } else {
  504. console.error("Received an error type frame:", type);
  505. }
  506. }
  507. });
  508. },
  509. fail: (err) => mDeviceEvent.notifyDeviceMsgEvent({ 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_INIT_ESP32_RESULT, 'result': false, 'data': err })
  510. });
  511. },
  512. fail: (err) => mDeviceEvent.notifyDeviceMsgEvent({ 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_INIT_ESP32_RESULT, 'result': false, 'data': err })
  513. });
  514. },
  515. fail: (err) => mDeviceEvent.notifyDeviceMsgEvent({ 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_INIT_ESP32_RESULT, 'result': false, 'data': err })
  516. });
  517. });
  518. // 监听发送SSID和密码事件
  519. mDeviceEvent.listenSendRouterSsidAndPassword(true, function (options) {
  520. _self.data.password = options.password;
  521. _self.data.ssid = options.ssid;
  522. writeDeviceRouterInfoStart();
  523. });
  524. // 监听发送自定义数据事件
  525. mDeviceEvent.listenSendCustomData(true, function (options) {
  526. _self.data.customData = options.customData;
  527. writeCutomsData();
  528. });
  529. // 监听发送获取附近Wi-Fi指令事件
  530. mDeviceEvent.listenSendGetNearRouterSsid(true, function(options) {
  531. writeGetNearRouterSsid();
  532. });
  533. }
  534. /**
  535. * [优化] 处理Wi-Fi列表数据
  536. * 使用循环和索引替代递归和splice,性能更高。
  537. * @param {number[]} arr - 包含所有Wi-Fi信息的字节数组
  538. */
  539. function getList(arr) {
  540. let currentIndex = 0;
  541. while (currentIndex < arr.length) {
  542. const len = parseInt(arr[currentIndex], 16);
  543. if (len <= 0) {
  544. // 长度异常,跳出循环
  545. break;
  546. }
  547. // 检查数据是否完整
  548. if (currentIndex + 1 + len > arr.length) {
  549. console.error("Incomplete Wi-Fi data frame.");
  550. break;
  551. }
  552. const rssi = parseInt(arr[currentIndex + 1], 16);
  553. const nameBytes = arr.slice(currentIndex + 2, currentIndex + 1 + len);
  554. const name = String.fromCharCode(...nameBytes.map(hex => parseInt(hex, 16)));
  555. mDeviceEvent.notifyDeviceMsgEvent({
  556. 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_CONNECT_NEAR_ROUTER_LISTS,
  557. 'result': true,
  558. 'data': { "rssi": rssi, "SSID": decodeURIComponent(escape(name)) } // 保持和原逻辑一致的解码方式
  559. });
  560. // 移动索引到下一个Wi-Fi信息的开头
  561. currentIndex += (1 + len);
  562. }
  563. }
  564. /****************************** 对外导出 ***************************************/
  565. module.exports = {
  566. init: init,
  567. };