@jiabaida/tools 1.0.8 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/cjs/core/BleApiManager.js +1 -1
  2. package/dist/cjs/core/BleCmdAnalysis/BaseParamProtocol.js +1 -1
  3. package/dist/cjs/core/BleCmdAnalysis/BleCmdAnalysis.js +1 -1
  4. package/dist/cjs/core/BleCmdAnalysis/BleCmdDD.js +1 -1
  5. package/dist/cjs/core/BleCmdAnalysis/BleCmdDDA4.js +1 -1
  6. package/dist/cjs/core/BleCmdAnalysis/BleCmdFFAA.js +1 -1
  7. package/dist/cjs/core/BleCmdAnalysis/readAndSetParam.js +1 -1
  8. package/dist/cjs/core/BleDataProcess.js +1 -1
  9. package/dist/cjs/core/OtaUpgrade.js +1 -1
  10. package/dist/cjs/core/mqttServer.js +1 -1
  11. package/dist/cjs/core/tcpServer.js +1 -1
  12. package/dist/cjs/index.js +1 -1
  13. package/dist/esm/core/BleApiManager.js +1 -1
  14. package/dist/esm/core/BleCmdAnalysis/BaseParamProtocol.js +1 -1
  15. package/dist/esm/core/BleCmdAnalysis/BleCmdAnalysis.js +1 -1
  16. package/dist/esm/core/BleCmdAnalysis/BleCmdDD.js +1 -1
  17. package/dist/esm/core/BleCmdAnalysis/BleCmdDDA4.js +1 -1
  18. package/dist/esm/core/BleCmdAnalysis/BleCmdFFAA.js +1 -1
  19. package/dist/esm/core/BleCmdAnalysis/BleCmdHVES.js +1 -1
  20. package/dist/esm/core/BleCmdAnalysis/readAndSetParam.js +1 -1
  21. package/dist/esm/core/BleDataProcess.js +1 -1
  22. package/dist/esm/core/OtaUpgrade.js +1 -1
  23. package/dist/esm/core/mqttServer.js +1 -1
  24. package/dist/esm/core/tcpServer.js +1 -1
  25. package/dist/esm/index.js +1 -1
  26. package/package.json +1 -1
  27. package/src/core/BleApiManager.js +33 -15
  28. package/src/core/BleCmdAnalysis/BaseParamProtocol.js +59 -34
  29. package/src/core/BleCmdAnalysis/BleCmdAnalysis.js +58 -2
  30. package/src/core/BleCmdAnalysis/BleCmdDD.js +16 -6
  31. package/src/core/BleCmdAnalysis/BleCmdDDA4.js +154 -227
  32. package/src/core/BleCmdAnalysis/BleCmdFFAA.js +1 -0
  33. package/src/core/BleCmdAnalysis/readAndSetParam.js +45 -17
  34. package/src/core/BleDataProcess.js +15 -11
  35. package/src/core/OtaUpgrade.js +356 -356
  36. package/src/core/mqttServer.js +58 -7
  37. package/src/core/tcpServer.js +76 -38
@@ -20,7 +20,8 @@ export const getDDA420Async = async (deviceId) => {
20
20
  return { verified: c1 == _c1 && c2 == _c2 };
21
21
  },
22
22
  },
23
- 'DDA420'
23
+ 'DDA420',
24
+ 1500
24
25
  );
25
26
  }
26
27
 
@@ -85,10 +86,11 @@ export const getDDA420Async = async (deviceId) => {
85
86
  );
86
87
 
87
88
  // 6. 充电器温度(2字节)
88
- const chargeTemperature = hexToDecimal(
89
+ const tempChargeTemperature = hexToDecimal(
89
90
  decimalToHex(data[n++]) +
90
91
  decimalToHex(data[n++])
91
- ) / 10;
92
+ );
93
+ const chargeTemperature = tempChargeTemperature > 32768 ? (tempChargeTemperature - 65536) / 10 : tempChargeTemperature / 10;
92
94
 
93
95
  // 7. 已充电量(4字节)
94
96
  const chargeCapacity = hexToDecimal(
@@ -231,7 +233,7 @@ export const getDDA420Async = async (deviceId) => {
231
233
  const checks = generateCrcCheckSum(_command);
232
234
  const command = ['0xdd', '0xa4', ..._command, ...checks, '0x77'];
233
235
 
234
- return this.getData(
236
+ return getData(
235
237
  deviceId,
236
238
  {
237
239
  command,
@@ -243,7 +245,8 @@ export const getDDA420Async = async (deviceId) => {
243
245
  return { verified: c1 == _c1 && c2 == _c2 };
244
246
  },
245
247
  },
246
- 'DDA421'
248
+ 'DDA421',
249
+ 1500
247
250
  );
248
251
  }
249
252
  /** 解析充电电池信息21指令
@@ -271,7 +274,8 @@ export const getDDA420Async = async (deviceId) => {
271
274
  const batterySOC = data[18]; // %
272
275
  // 电池温度 2BYTE [19,20]
273
276
  const batteryTempHex = decimalToHex(data[19]) + decimalToHex(data[20]);
274
- const batteryTemperature = hexToDecimal(batteryTempHex) / 10; // 0.1摄氏度
277
+ const tempBatteryTemperature = hexToDecimal(batteryTempHex);
278
+ const batteryTemperature = tempBatteryTemperature > 32768 ? (tempBatteryTemperature - 65536) / 10 : tempBatteryTemperature / 10; // 0.1摄氏度
275
279
  // const batteryTemperature = [data[19] ?? 0, [data[20] ?? 0]] // 摄氏度,保留一位小数
276
280
  // 加热状态 1BYTE [21]
277
281
  const heatingStatus = data[21]; // 0未加热 1加热中
@@ -332,7 +336,8 @@ export const getDDA420Async = async (deviceId) => {
332
336
  return { verified: true };
333
337
  },
334
338
  },
335
- 'DDA425'
339
+ 'DDA425',
340
+ 1500
336
341
  );
337
342
  }
338
343
  export const resolveDDA425 = (data) => {
@@ -377,7 +382,8 @@ export const getDDA420Async = async (deviceId) => {
377
382
  return { verified: c1 == _c1 && c2 == _c2 };
378
383
  },
379
384
  },
380
- 'DDA422'
385
+ 'DDA422',
386
+ 3000
381
387
  );
382
388
  }
383
389
  /** 解析充电器参数22指令响应
@@ -406,46 +412,66 @@ export const getDDA420Async = async (deviceId) => {
406
412
  * 设置充电器参数23指令
407
413
  */
408
414
  export const getDDA423Async = async (deviceId, startReg, endReg, values, valuesLength) => {
409
- // 转为2字节十六进制字符串
410
- const startRegHex = decimalToHex(startReg, 4);
411
- // 起始地址
412
- const startRegArr = [
413
- parseInt(startRegHex.slice(0, 2), 16),
414
- parseInt(startRegHex.slice(2, 4), 16)
415
- ];
416
- // 结束地址
417
- const endRegHex = decimalToHex(endReg, 4);
418
- const endRegArr = [
419
- parseInt(endRegHex.slice(0, 2), 16),
420
- parseInt(endRegHex.slice(2, 4), 16)
421
- ];
422
- // 数据内容
423
- const valueRegHex = decimalToHex(values, valuesLength * 2);
424
- let valueArr = [];
425
- for (let i = 0; i < valuesLength; i++) {
426
- const hex = valueRegHex.slice(i * 2, i * 2 + 2);
427
- valueArr.push(parseInt(hex.slice(0, 2), 16));
428
- }
429
-
430
- const lengthHex = decimalToHex(4+valuesLength, 2);
415
+ try {
416
+ // 起始/结束地址 2 字节大端
417
+ const startRegHex = decimalToHex(startReg, 4);
418
+ const startRegArr = [
419
+ parseInt(startRegHex.slice(0, 2), 16),
420
+ parseInt(startRegHex.slice(2, 4), 16)
421
+ ];
422
+ const endRegHex = decimalToHex(endReg, 4);
423
+ const endRegArr = [
424
+ parseInt(endRegHex.slice(0, 2), 16),
425
+ parseInt(endRegHex.slice(2, 4), 16)
426
+ ];
427
+
428
+ let valueArr = [];
429
+ // 批量模式:传入数组
430
+ if (Array.isArray(values)) {
431
+ valueArr = values.map(v => (Number(v) || 0) & 0xFF);
432
+ const expectLen = endReg - startReg + 1;
433
+ if (valueArr.length !== expectLen) {
434
+ if (valueArr.length > expectLen) {
435
+ valueArr = valueArr.slice(0, expectLen);
436
+ } else {
437
+ while (valueArr.length < expectLen) valueArr.push(0);
438
+ }
439
+ }
440
+ valuesLength = valueArr.length;
441
+ } else {
442
+ // 单值模式:保持兼容旧逻辑
443
+ const len = valuesLength || (endReg - startReg + 1);
444
+ const valueRegHex = decimalToHex(values, len * 2);
445
+ for (let i = 0; i < len; i++) {
446
+ const hex = valueRegHex.slice(i * 2, i * 2 + 2);
447
+ valueArr.push(parseInt(hex, 16));
448
+ }
449
+ valuesLength = len;
450
+ }
431
451
 
432
- const _command = ['0x23', lengthHex, ...startRegArr, ...endRegArr, ...valueArr];
433
- const checks = generateCrcCheckSum(_command);
434
- const command = ['0xDD', '0xA4', ..._command, ...checks, '0x77'];
435
- return getData(
436
- deviceId,
437
- {
438
- command,
439
- commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0x23, pkgLen: hexArr[3] + 7 }),
440
- pkgVerifyHandler: (pkg) => {
441
- const len = pkg.length;
442
- const [c1, c2] = generateCrcCheckSum(pkg.slice(2, len - 3));
443
- const [_c1, _c2] = [pkg[len - 3], pkg[len - 2]];
444
- return { verified: c1 == _c1 && c2 == _c2 };
452
+ const lengthHex = 4 + valuesLength;
453
+ const _command = ['0x23', lengthHex, ...startRegArr, ...endRegArr, ...valueArr];
454
+ const checks = generateCrcCheckSum(_command);
455
+ const command = ['0xDD', '0xA4', ..._command, ...checks, '0x77'];
456
+ return getData(
457
+ deviceId,
458
+ {
459
+ command,
460
+ commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0x23, pkgLen: hexArr[3] + 7 }),
461
+ pkgVerifyHandler: (pkg) => {
462
+ const len = pkg.length;
463
+ const [c1, c2] = generateCrcCheckSum(pkg.slice(2, len - 3));
464
+ const [_c1, _c2] = [pkg[len - 3], pkg[len - 2]];
465
+ return { verified: c1 == _c1 && c2 == _c2 };
466
+ },
445
467
  },
446
- },
447
- 'DDA423'
448
- );
468
+ 'DDA423',
469
+ 3000
470
+ );
471
+ } catch (e) {
472
+ console.warn('getDDA423Async build frame error', e);
473
+ return Promise.reject(e);
474
+ }
449
475
  }
450
476
  export const resolveDDA423 = (data) => {
451
477
  if (!data) return null;
@@ -475,14 +501,14 @@ export const getDDA420Async = async (deviceId) => {
475
501
 
476
502
  // 转 4 字节 (大端) 十六进制 -> 数组
477
503
  const to4Bytes = (val) => {
478
- const hex = commonfun.decimalToHex(val, 8); // 8位十六进制字符串
504
+ const hex = decimalToHex(val, 8); // 8位十六进制字符串
479
505
  return [0, 2, 4, 6].map(i => parseInt(hex.slice(i, i + 2), 16));
480
506
  };
481
507
  const voltageArr = to4Bytes(outputVoltage);
482
508
  const currentArr = to4Bytes(outputCurrent);
483
509
 
484
510
  // 长度 = 1(模式) +4(电压)+4(电流) = 9
485
- const lengthHex = commonfun.decimalToHex(9, 2); // '09'
511
+ const lengthHex = decimalToHex(9, 2); // '09'
486
512
  const _command = ['0x26', `0x${lengthHex}`, testMode & 0xFF, ...voltageArr, ...currentArr].map(o => typeof o === 'number' ? `0x${('00' + o.toString(16)).slice(-2)}` : o);
487
513
  // 去掉 0x 前缀转成数值数组生成 CRC
488
514
  const _commandNums = _command.map(h => parseInt(h, 16));
@@ -615,49 +641,31 @@ export const getDDA420Async = async (deviceId) => {
615
641
  * @param {*} deviceId
616
642
  * @returns
617
643
  */
618
- export const getDDA429Async = async (deviceId, id) => {
619
- // id、是四个bites
644
+ export const getDDA429Async = async (deviceId, id = 1, seq = 0) => {
645
+ // ID 与 SEQ 均为 4 字节大端
620
646
  const idHex = decimalToHex(id, 8);
621
- // 拆分为4字节
647
+ const seqHex = decimalToHex(seq, 8);
622
648
  const idArr = [
623
649
  parseInt(idHex.slice(0, 2), 16),
624
650
  parseInt(idHex.slice(2, 4), 16),
625
651
  parseInt(idHex.slice(4, 6), 16),
626
- parseInt(idHex.slice(4, 6), 16),
627
652
  parseInt(idHex.slice(6, 8), 16)
628
653
  ];
629
- const _command = ['0x29', '0x04', ...idArr];
654
+ const seqArr = [
655
+ parseInt(seqHex.slice(0, 2), 16),
656
+ parseInt(seqHex.slice(2, 4), 16),
657
+ parseInt(seqHex.slice(4, 6), 16),
658
+ parseInt(seqHex.slice(6, 8), 16)
659
+ ];
660
+ // 长度 = 8 (ID+SEQ)
661
+ const _command = ['0x29', '0x08', ...idArr, ...seqArr];
630
662
  const checks = generateCrcCheckSum(_command);
631
- const command = ['0xdd', '0xa4', ..._command, ...checks, '0x77'];
632
-
633
-
663
+ const command = ['0xDD', '0xA4', ..._command, ...checks, '0x77'];
634
664
  return getData(
635
665
  deviceId,
636
666
  {
637
667
  command,
638
- commandVerifyHandler: (hexArr) => {
639
- // 基本头部验证
640
- if (hexArr[0] != 0xdd || hexArr[1] != 0x29) return { verified: false, pkgLen: null };
641
-
642
- // 验证数据包长度是否合理
643
- if (hexArr.length < 8) return { verified: false, pkgLen: null };
644
-
645
- // 根据resolveDDA429的解析结构,ID在响应偏移32位置
646
- // 实际协议中可能有所不同,需要根据协议规范调整
647
- if (hexArr.length >= 36) {
648
- // 从resolveDDA429可知,ID位于n=32处的4个字节
649
- const respIdHex = decimalToHex(hexArr[32]) +
650
- decimalToHex(hexArr[33]) +
651
- decimalToHex(hexArr[34]) +
652
- decimalToHex(hexArr[35]);
653
- const respId = hexToDecimal(respIdHex);
654
-
655
- // 如果ID不匹配,则拒绝该数据包
656
- if (respId !== id) return { verified: false, pkgLen: null };
657
- }
658
-
659
- return { verified: true, pkgLen: hexArr[3] + 7 };
660
- },
668
+ commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0x29, pkgLen: hexArr[3] + 7 }),
661
669
  pkgVerifyHandler: (pkg) => {
662
670
  const len = pkg.length;
663
671
  const [c1, c2] = generateCrcCheckSum(pkg.slice(2, len - 3));
@@ -665,161 +673,80 @@ export const getDDA420Async = async (deviceId) => {
665
673
  return { verified: c1 == _c1 && c2 == _c2 };
666
674
  },
667
675
  },
668
- 'DDA429'
676
+ 'DDA429',
677
+ 3000
669
678
  );
670
679
  }
671
680
  export const resolveDDA429 = (data) => {
672
681
  if (!data) return null;
682
+ const status = data[2];
683
+ const content = data.slice(4, data.length - 3);
673
684
  const dataStr = hexArr2string(data);
674
- let n = 4; // 起始偏移
675
-
676
- // 1. 工作状态
677
- const workStatus = data[n++];
678
-
679
- // 2. 充电状态
680
- const chargeStatus = data[n++];
681
-
682
- // 3. 充电电压(4字节)
683
- const chargeVoltage = hexToDecimal(
684
- decimalToHex(data[n++]) +
685
- decimalToHex(data[n++]) +
686
- decimalToHex(data[n++]) +
687
- decimalToHex(data[n++])
688
- );
689
-
690
- // 4. 充电电流(4字节)
691
- const chargeElectricity = hexToDecimal(
692
- decimalToHex(data[n++]) +
693
- decimalToHex(data[n++]) +
694
- decimalToHex(data[n++]) +
695
- decimalToHex(data[n++])
696
- );
697
-
698
- // 5. 充电功率(2字节)
699
- const chargePower = hexToDecimal(
700
- decimalToHex(data[n++]) +
701
- decimalToHex(data[n++])
702
- );
703
-
704
- // 6. 充电器温度(2字节)
705
- const chargeTemperature = hexToDecimal(
706
- decimalToHex(data[n++]) +
707
- decimalToHex(data[n++])
708
- ) / 10;
709
-
710
- // 7. 已充电量(4字节)
711
- const chargeCapacity = hexToDecimal(
712
- decimalToHex(data[n++]) +
713
- decimalToHex(data[n++]) +
714
- decimalToHex(data[n++]) +
715
- decimalToHex(data[n++])
716
- );
717
-
718
- // 8. 充电时长(2字节)
719
- const chargeTime = hexToDecimal(
720
- decimalToHex(data[n++]) +
721
- decimalToHex(data[n++])
722
- );
723
-
724
- // 9. 充电剩余时间(2字节)
725
- const chargeRemainTime = hexToDecimal(
726
- decimalToHex(data[n++]) +
727
- decimalToHex(data[n++])
728
- );
729
-
730
- // 10. 充电完成时长(2字节)
731
- const chargeCompleteTime = hexToDecimal(
732
- decimalToHex(data[n++]) +
733
- decimalToHex(data[n++])
734
- );
735
-
736
- // 输出电压占空比
737
- const outputVoltagePercent = data[n++];
738
-
739
- // 输出电流占空比
740
- const outputElectricityPercent = data[n++];
741
-
742
- // id(4字节)
743
- const id1 = hexToDecimal(
744
- decimalToHex(data[n++]) +
745
- decimalToHex(data[n++]) +
746
- decimalToHex(data[n++]) +
747
- decimalToHex(data[n++])
748
- );
749
-
750
- // 检测输出电流(4字节)
751
- const outputElectricity = hexToDecimal(
752
- decimalToHex(data[n++]) +
753
- decimalToHex(data[n++]) +
754
- decimalToHex(data[n++]) +
755
- decimalToHex(data[n++])
756
- );
757
-
758
- // 检测电池电压(4字节)
759
- const id = hexToDecimal(
760
- decimalToHex(data[n++]) +
761
- decimalToHex(data[n++]) +
762
- decimalToHex(data[n++]) +
763
- decimalToHex(data[n++])
764
- );
765
-
766
- // 开关状态(2字节)
767
- const switchStatus = hexToDecimal(
768
- decimalToHex(data[n++]) +
769
- decimalToHex(data[n++])
770
- );
771
- const swtichStatusArr = switchStatus.toString(2).padStart(16, '0').split('').reverse();
772
- const chargeSwitch = swtichStatusArr[0] == '1';
773
- const preChargeSwitch = swtichStatusArr[1] == '1';
774
- const fanSwitch = swtichStatusArr[2] == '1';
775
-
776
- // 保护状态(4字节)
777
- const protectStatus = hexToDecimal(
778
- decimalToHex(data[n++]) +
779
- decimalToHex(data[n++]) +
780
- decimalToHex(data[n++]) +
781
- decimalToHex(data[n++])
782
- );
783
- const protectStatusArr = protectStatus.toString(2).padStart(32, '0').split('').reverse();
784
- let protectStatusIndexs = [];
785
- for (let i = 0; i < protectStatusArr.length; i++) {
786
- if (protectStatusArr[i] == '1') protectStatusIndexs.push(i);
685
+ if (content.length < 8) return { dataStr, status, error: 'content too short' };
686
+
687
+ const id = hexToDecimal(decimalToHex(content[0]) + decimalToHex(content[1]) + decimalToHex(content[2]) + decimalToHex(content[3]));
688
+ const seq = hexToDecimal(decimalToHex(content[4]) + decimalToHex(content[5]) + decimalToHex(content[6]) + decimalToHex(content[7]));
689
+ const body = content.slice(8);
690
+
691
+ // ID=1 解析:末尾 57 字节固定含义,其余视作工作信息原始区
692
+ if (id === 1) {
693
+ const peerTailLen = 57;
694
+ let workInfo = [];
695
+ let peerSection = [];
696
+ if (body.length >= peerTailLen) {
697
+ workInfo = body.slice(0, body.length - peerTailLen);
698
+ peerSection = body.slice(body.length - peerTailLen);
699
+ } else {
700
+ peerSection = body.slice();
701
+ }
702
+ const workinfoField = {
703
+ state: workInfo[0] || 0,
704
+ ipwm: hexToDecimal(decimalToHex(workInfo[24]) + decimalToHex(workInfo[25]) + decimalToHex(workInfo[26]) + decimalToHex(workInfo[27])),
705
+ vpwm: hexToDecimal(decimalToHex(workInfo[28]) + decimalToHex(workInfo[29]) + decimalToHex(workInfo[30]) + decimalToHex(workInfo[31])),
706
+ vout: hexToDecimal(decimalToHex(workInfo[32]) + decimalToHex(workInfo[33]) + decimalToHex(workInfo[34]) + decimalToHex(workInfo[35])),
707
+ iout: hexToDecimal(decimalToHex(workInfo[36]) + decimalToHex(workInfo[37]) + decimalToHex(workInfo[38]) + decimalToHex(workInfo[39])),
708
+ vbat: hexToDecimal(decimalToHex(workInfo[40]) + decimalToHex(workInfo[41]) + decimalToHex(workInfo[42]) + decimalToHex(workInfo[43])),
709
+ port: String(workInfo[54]) || 0
710
+ };
711
+ const fieldNames = ['peer_curr', 'peer_num', 'ble_state', 'ble_init', 'ble_release', 'release_cnt', 'scan_start', 'scan_end', 'scan_res', 'scan_resp', 'conn_start', 'conn_resp', 'conn_end', 'conn_idx', 'conn_res', 'cmp_resp', 'handshake_resp', 'qr_chg', 'blacklist', 'ext_resp', 'ext_num'];
712
+ const peerMap = {};
713
+ peerSection.slice(0, 21).forEach((b, i) => { peerMap[fieldNames[i] || (`extra_${i}`)] = b; });
714
+
715
+ const extraBytes = peerSection.slice(21);
716
+ let i = 0;
717
+ let j = 0;
718
+ const fieldNamesExtra = ['run_ts', 'scan_ts', 'scan_end_ts', 'get_ts', 'get_end_ts', 'conn_ts', 'conn_end_ts', 'cmp_ts', 'cmp_end_ts'];
719
+ while (i < extraBytes.length) {
720
+ peerMap[fieldNamesExtra[j] || (`extra_${j}`)] = hexToDecimal(
721
+ decimalToHex(extraBytes[i] || 0) +
722
+ decimalToHex(extraBytes[i + 1] || 0) +
723
+ decimalToHex(extraBytes[i + 2] || 0) +
724
+ decimalToHex(extraBytes[i + 3] || 0)
725
+ );
726
+ i += 4;
727
+ j += 1;
728
+ }
729
+ return { dataStr, status, id, seq, type: 'ID1', ...workinfoField, ...peerMap };
787
730
  }
788
731
 
789
- // 告警状态(4字节)
790
- const alarmStatus = hexToDecimal(
791
- decimalToHex(data[n++]) +
792
- decimalToHex(data[n++]) +
793
- decimalToHex(data[n++]) +
794
- decimalToHex(data[n++])
795
- );
796
- const alarmStatusArr = alarmStatus.toString(2).padStart(32, '0').split('').reverse();
797
- let alarmStatusIndexs = [];
798
- for (let i = 0; i < alarmStatusArr.length; i++) {
799
- if (alarmStatusArr[i] == '1') alarmStatusIndexs.push(i);
732
+ // ID=2/3 解析:按 16 字节一组 peer_info
733
+ if (id === 2 || id === 3) {
734
+ const peerInfos = [];
735
+ for (let i = 0; i + 16 <= body.length; i += 16) {
736
+ const seg = body.slice(i, i + 16);
737
+ const macBytes = seg.slice(0, 6).map(b => decimalToHex(b));
738
+ const mac = macBytes.map(m => m.toUpperCase()).join(':');
739
+ const state = seg[6] === 255 ? -1 : seg[6];
740
+ const cmp = seg[7] === 255 ? -1 : seg[7];
741
+ const voltage = hexToDecimal(decimalToHex(seg[8]) + decimalToHex(seg[9]));
742
+ const b_voltage = hexToDecimal(decimalToHex(seg[10]) + decimalToHex(seg[11]));
743
+ const current = hexToDecimal(decimalToHex(seg[12]) + decimalToHex(seg[13]));
744
+ const b_current = hexToDecimal(decimalToHex(seg[14]) + decimalToHex(seg[15]));
745
+ peerInfos.push({ mac, state, cmp, voltage, b_voltage, current, b_current });
746
+ }
747
+ return { dataStr, status, id, seq, type: `ID${id}`, peerInfos: peerInfos.map((item, i) => ({ id: i, ...item })) };
800
748
  }
801
749
 
802
- return {
803
- dataStr,
804
- workStatus,
805
- chargeStatus,
806
- chargeVoltage,
807
- chargeElectricity,
808
- chargePower,
809
- chargeTemperature,
810
- chargeCapacity,
811
- chargeTime,
812
- chargeRemainTime,
813
- chargeCompleteTime,
814
- outputVoltagePercent,
815
- outputElectricityPercent,
816
- id,
817
- outputElectricity,
818
- id1,
819
- chargeSwitch,
820
- preChargeSwitch,
821
- fanSwitch,
822
- protectStatusIndexs,
823
- alarmStatusIndexs,
824
- };
750
+ // 未知 ID
751
+ return { dataStr, status, id, seq, raw: body };
825
752
  }
@@ -168,6 +168,7 @@ export const getFFAA80Async = async (deviceId, ATStr) => {
168
168
  },
169
169
  'FFAA_80(AT)'
170
170
  );
171
+ console.log('getFFAA80Async', hex)
171
172
  if(!hex) return null;
172
173
  return resolveFFAA80(hex);
173
174
  }
@@ -1,4 +1,4 @@
1
- import { decimalToHex, decimalToTwoByteHexArray } from '../BleDataProcess.js';
1
+ import { decimalToHex, decimalToTwoByteHexArray, sleep, decimalToHex0x } from '../BleDataProcess.js';
2
2
  import { enterFactory, existFactory, getDD5AE1Async, getDD5AFBAsync, getDDA5FAAsync, getDDA5OldAsync, readExistFactory, resolveBaseDD, setDDA5FAAsync, setDDA5OldAsync } from './BleCmdDD.js';
3
3
 
4
4
  // #region 发指令读取参数
@@ -20,7 +20,7 @@ export const readParamCmd = (chipType, deviceId, paramInfo, needFactoryMode = tr
20
20
  /** 地址转换为16进制 */
21
21
  const hexAddress = decimalToTwoByteHexArray(address);
22
22
  // 长度转换为16进制
23
- const hexLength = decimalToHex(length);
23
+ const hexLength = decimalToHex0x(length);
24
24
  const handleRead = async (readFunction, index) => {
25
25
  try {
26
26
  const hex = await readFunction();
@@ -68,7 +68,7 @@ export const readParamCmd = (chipType, deviceId, paramInfo, needFactoryMode = tr
68
68
  */
69
69
  export const getSysParamCmd = async (chipType, deviceId, paramInfo, needFactoryMode = true) => {
70
70
  try {
71
- console.log('paramInfo: ', paramInfo);
71
+ console.warn('paramInfo:参数信息', paramInfo);
72
72
  const paramObj = {
73
73
  address: paramInfo.paramNo,
74
74
  length: paramInfo.paramLength / 2,
@@ -104,7 +104,7 @@ export const getSysParamCmd = async (chipType, deviceId, paramInfo, needFactoryM
104
104
  * @param {*} paramInfoArray[].divisor 缩放系数(十进制)如 10
105
105
  * @param {*} paramInfoArray[].isTemp 是否是温度参数
106
106
  */
107
- export const setSysParamCmd = async (chipType, deviceId, paramInfoArray, macAddr, blueConnect = true) => {
107
+ export const setSysParamCmd = async (chipType, deviceId, paramInfoArray) => {
108
108
  try {
109
109
  console.log('paramInfoArray: ', paramInfoArray);
110
110
 
@@ -118,15 +118,13 @@ export const setSysParamCmd = async (chipType, deviceId, paramInfoArray, macAddr
118
118
  // 根据系数处理参数值
119
119
  let value = Number(paramInfo?.paramValue || paramInfo.newValue) / Number(paramInfo?.divisor || 1);
120
120
  console.log('value: ', value);
121
- if (paramInfo.isTemp && blueConnect) {
121
+ if (paramInfo.isTemp) {
122
122
  value = 2731 + (Number(paramInfo.newValue) * 10)
123
123
  }
124
124
  value = Math.round(value);
125
125
  let valuesHexs = [];
126
- if(blueConnect) {
127
- valuesHexs = decimalToTwoByteHexArray(value);
128
- console.log('valuesHexs: ', valuesHexs);
129
- }
126
+ valuesHexs = decimalToTwoByteHexArray(value);
127
+ console.log('valuesHexs: ', valuesHexs);
130
128
 
131
129
  // 将处理后的参数对象添加到数组中
132
130
  paramObjs.push({
@@ -319,17 +317,17 @@ export const setCapacityParamCmd = (chipType, deviceId, paramInfo) => {
319
317
  const { values } = paramInfo;
320
318
  // 循环 循环是标称的80%
321
319
  const circular = {
322
- address: 1,
323
- oldAddress: "0x11",
320
+ paramNo: 1,
321
+ oldParamNo: "0x11",
324
322
  values: values * 0.8,
325
- length: 1,
323
+ paramLength: 2,
326
324
  };
327
325
  // 满充 满充等于标称 旧协议没有满充
328
326
  const full = {
329
- address: 112,
330
- oldAddress: "0x10",
327
+ paramNo: 112,
328
+ oldParamNo: "0x10",
331
329
  values: values,
332
- length: 1,
330
+ paramLength: 2,
333
331
  };
334
332
 
335
333
  const handleSet = async (setFunction, index) => {
@@ -361,12 +359,42 @@ export const setCapacityParamCmd = (chipType, deviceId, paramInfo) => {
361
359
  return await handleSet(() => setDDA5OldAsync(deviceId, oldParamNo, hexValues), 4);
362
360
  }
363
361
  };
362
+
363
+ // 写入容量参数的高低位(标称容量、满充容量)
364
+ const handleCapacityParam = async (paramObj, lowParamNo, highParamNo) => {
365
+ const value = Math.round(Number(paramObj.values) / paramInfo.divisor);
366
+ console.log(`容量参数value (paramNo ${lowParamNo}):`, value);
367
+
368
+ // 拆分成高低16位
369
+ const lowValue = value & 0xFFFF; // 低16位
370
+ const highValue = (value >> 16) & 0xFFFF; // 高16位
371
+
372
+ // 写入低16位
373
+ const lowBytes = decimalToTwoByteHexArray(lowValue);
374
+ const lowAddress = decimalToTwoByteHexArray(lowParamNo);
375
+ const hexLength = decimalToHex(1);
376
+ const lowHex = await handleSet(async () => await setDDA5FAAsync(deviceId, lowAddress, hexLength, lowBytes), 7);
377
+
378
+ // 写入高16位
379
+ const highBytes = decimalToTwoByteHexArray(highValue);
380
+ const highAddress = decimalToTwoByteHexArray(highParamNo);
381
+ const highHex = await handleSet(async () => await setDDA5FAAsync(deviceId, highAddress, hexLength, highBytes), 7);
382
+
383
+ return lowHex && highHex;
384
+ };
364
385
  try {
365
386
  await enterFactory(deviceId);
366
- const paramInfoHex = await handleParam(paramInfo);
387
+ let paramInfoHex;
388
+ if (chipType) {
389
+ // 新协议:标称容量需要写入两个参数(paramNo 0和155)
390
+ paramInfoHex = await handleCapacityParam(paramInfo, 0, 155);
391
+ } else {
392
+ // 旧协议:直接写入
393
+ paramInfoHex = await handleParam(paramInfo);
394
+ }
367
395
  const circularHex = await handleParam(circular);
368
396
  if (chipType) {
369
- const fullHex = await handleParam(full);
397
+ const fullHex = await handleCapacityParam(full, 112, 156);
370
398
  }
371
399
  await existFactory(deviceId);
372
400
  if (paramInfoHex) {
@@ -312,22 +312,26 @@
312
312
  return new Promise((r) => setTimeout(() => r(true), n));
313
313
  }
314
314
  /**
315
- * 十进制数转换为两个字节的十六进制数组
316
- * @param {number} decimal 十进制数,范围 0 - 65535
317
- * @returns {Array} 包含两个字节十六进制字符串的数组
318
- */
315
+ * 将一个十进制数转换为两个字节的十六进制数组。
316
+ * @param {number} decimal - 要转换的十进制数。
317
+ * @returns {Array<string>} 包含两个十六进制字符串的数组,每个字符串表示一个字节。
318
+ */
319
319
  export const decimalToTwoByteHexArray = (decimal) => {
320
- // 添加类型和整数检查
321
- if (typeof decimal !== 'number' || !Number.isInteger(decimal)) {
322
- throw new Error('输入必须为整数');
320
+ // 范围检查(支持有符号和无符号)
321
+ if (decimal < -32768 || decimal > 65535) {
322
+ throw new Error('输入超出范围(-32768 到 65535)');
323
323
  }
324
- if (decimal < 0 || decimal > 65535) {
325
- throw new Error('输入的十进制数超出 16 位无符号整数范围(0 - 65535)');
324
+
325
+ // 负数转为无符号 16 位表示
326
+ if (decimal < 0) {
327
+ decimal = decimal & 0xFFFF;
326
328
  }
327
- let f = `00${(decimal >> 8).toString(16)}`.slice(-2);
328
- let e = `00${(decimal & 0xff).toString(16)}`.slice(-2);
329
+
330
+ let f = `00${(decimal >> 8).toString(16).toUpperCase()}`.slice(-2);
331
+ let e = `00${(decimal & 0xff).toString(16).toUpperCase()}`.slice(-2);
329
332
  return [`0x${f}`, `0x${e}`];
330
333
  }
334
+
331
335
 
332
336
  /**
333
337
  * 将十六进制字符串转换为两个十六进制的数组