@jiabaida/tools 1.0.3 → 1.0.7
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.
- package/dist/cjs/core/BleApiManager.js +1 -1
- package/dist/cjs/core/BleCmdAnalysis/BaseParamProtocol.js +1 -1
- package/dist/cjs/core/BleCmdAnalysis/BleCmdAnalysis.js +1 -1
- package/dist/cjs/core/BleCmdAnalysis/BleCmdDD.js +1 -1
- package/dist/cjs/core/BleCmdAnalysis/BleCmdDDA4.js +1 -0
- package/dist/cjs/core/BleDataProcess.js +1 -1
- package/dist/cjs/core/OtaUpgrade.js +1 -1
- package/dist/cjs/core/Transfer.js +1 -1
- package/dist/cjs/core/commonfun.js +1 -1
- package/dist/cjs/core/dataJson/baseParamsJson.js +1 -1
- package/dist/cjs/core/mqttServer.js +1 -0
- package/dist/cjs/core/rsaEncrypt.js +1 -0
- package/dist/cjs/index.js +1 -1
- package/dist/esm/core/BleApiManager.js +1 -1
- package/dist/esm/core/BleCmdAnalysis/BaseParamProtocol.js +1 -1
- package/dist/esm/core/BleCmdAnalysis/BleCmdAnalysis.js +1 -1
- package/dist/esm/core/BleCmdAnalysis/BleCmdDD.js +1 -1
- package/dist/esm/core/BleCmdAnalysis/BleCmdDDA4.js +1 -0
- package/dist/esm/core/BleDataProcess.js +1 -1
- package/dist/esm/core/OtaUpgrade.js +1 -1
- package/dist/esm/core/Transfer.js +1 -1
- package/dist/esm/core/commonfun.js +1 -1
- package/dist/esm/core/dataJson/baseParamsJson.js +1 -1
- package/dist/esm/core/mqttServer.js +1 -0
- package/dist/esm/core/rsaEncrypt.js +1 -0
- package/dist/esm/index.js +1 -1
- package/package.json +4 -3
- package/src/core/BleApiManager.js +113 -75
- package/src/core/BleCmdAnalysis/BaseParamProtocol.js +35 -6
- package/src/core/BleCmdAnalysis/BleCmdAnalysis.js +3 -2
- package/src/core/BleCmdAnalysis/BleCmdDD.js +132 -5
- package/src/core/BleCmdAnalysis/BleCmdDDA4.js +74 -11
- package/src/core/BleCmdAnalysis/index.js +6 -5
- package/src/core/BleDataProcess.js +40 -0
- package/src/core/OtaUpgrade.js +16 -4
- package/src/core/Transfer.js +1 -1
- package/src/core/commonfun.js +2 -1
- package/src/core/dataJson/baseParamsJson.js +135 -33
- package/src/core/mqttServer.js +9 -9
- package/src/core/rsaEncrypt.js +1 -1
- package/src/index.js +4 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { decimalToHex, generateCrc16modbusCheck, generateCrcCheckSum, hex2string, hexArr2Assic, hexArr2string, hexToDecimal, sleep, stringToTwoHexArray } from '../BleDataProcess';
|
|
1
|
+
import { decimalToHex, fromBCD, generateCrc16modbusCheck, generateCrcCheckSum, hex2string, hexArr2Assic, hexArr2string, hexToDecimal, isWithin30Minutes, sleep, stringToTwoHexArray, toBCD } from '../BleDataProcess';
|
|
2
2
|
import { getData } from './BleCmdAnalysis.js';
|
|
3
3
|
import { getFFAA80Async, resolveFFAA80 } from './BleCmdFFAA.js';
|
|
4
4
|
|
|
@@ -244,9 +244,21 @@ export const resolveDDA503 = (data) => {
|
|
|
244
244
|
|
|
245
245
|
const binArr = data[24].toString(2).padStart(8, '0').split('').reverse();
|
|
246
246
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
)
|
|
247
|
+
|
|
248
|
+
// 获取16-19索引的4个字节
|
|
249
|
+
const BC1 = (data[16] << 8 | data[17])
|
|
250
|
+
.toString(2)
|
|
251
|
+
.padStart(16, "0")
|
|
252
|
+
.split("")
|
|
253
|
+
.reverse();
|
|
254
|
+
console.log('BC1: ', BC1);
|
|
255
|
+
const BC2 = (data[18] << 8 | data[19])
|
|
256
|
+
.toString(2)
|
|
257
|
+
.padStart(16, "0")
|
|
258
|
+
.split("")
|
|
259
|
+
.reverse();
|
|
260
|
+
const BC = BC1.concat(BC2);
|
|
261
|
+
const balances = BC;
|
|
250
262
|
console.warn("BC: ---------------", balances);
|
|
251
263
|
const fet = data[24];
|
|
252
264
|
/**充电开关 */
|
|
@@ -1332,4 +1344,119 @@ export const resetCapacity = (deviceId) => {
|
|
|
1332
1344
|
},
|
|
1333
1345
|
'DD5A_0A'
|
|
1334
1346
|
);
|
|
1335
|
-
}
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
/**读取BMS系统时间*/
|
|
1350
|
+
export const getDDA506Async = async (deviceId) => {
|
|
1351
|
+
const command = ['0xdd', '0xa5', '0x06', '0x00', '0xff', '0xfa', '0x77'];
|
|
1352
|
+
const response = '';
|
|
1353
|
+
return getData(
|
|
1354
|
+
deviceId,
|
|
1355
|
+
{
|
|
1356
|
+
command,
|
|
1357
|
+
commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0x06, pkgLen: hexArr[3] + 7 }),
|
|
1358
|
+
pkgVerifyHandler: (pkg) => {
|
|
1359
|
+
const len = pkg.length;
|
|
1360
|
+
const [c1, c2] = generateCrcCheckSum(pkg.slice(2, len - 3));
|
|
1361
|
+
const [_c1, _c2] = [pkg[len - 3], pkg[len - 2]];
|
|
1362
|
+
return { verified: c1 == _c1 && c2 == _c2 };
|
|
1363
|
+
},
|
|
1364
|
+
},
|
|
1365
|
+
'DDA5_06'
|
|
1366
|
+
);
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
/**解析BMS系统时间*/
|
|
1370
|
+
export const resolveDDA506 = (data) => {
|
|
1371
|
+
if (!data) return null;
|
|
1372
|
+
if (data[1] == 6 && data[2] == 0 && data[3] == 6) {
|
|
1373
|
+
//解析各字段
|
|
1374
|
+
const seconds = fromBCD(data[4]);
|
|
1375
|
+
const minutes = fromBCD(data[5]);
|
|
1376
|
+
const hours = fromBCD(data[6]);
|
|
1377
|
+
const day = fromBCD(data[7]);
|
|
1378
|
+
const month = fromBCD(data[8]);
|
|
1379
|
+
const year = 2000 + fromBCD(data[9]);
|
|
1380
|
+
const timeStr = `${year}-${String(month).padStart(2, 0)}-${String(day).padStart(2, 0)} ${String(hours).padStart(2, 0)}:${String(minutes).padStart(2, 0)}:${String(seconds).padStart(2, 0)}`;
|
|
1381
|
+
console.log('timeStr: ', timeStr, isWithin30Minutes(timeStr));
|
|
1382
|
+
return isWithin30Minutes(timeStr);
|
|
1383
|
+
} else {
|
|
1384
|
+
return false;
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
/**设置BMS系统时间*/
|
|
1389
|
+
//verified: hexArr[0] ->响应指令头 hexArr[1] ->指令码 pkgLen -> 响应指令长度
|
|
1390
|
+
export const setDD5AE3sync = async (deviceId) => {
|
|
1391
|
+
const header = ['0xDD', '0x5A']
|
|
1392
|
+
const now = new Date();
|
|
1393
|
+
const year = now.getFullYear();
|
|
1394
|
+
const month = now.getMonth() + 1;
|
|
1395
|
+
const day = now.getDate();
|
|
1396
|
+
const hours = now.getHours();
|
|
1397
|
+
const minutes = now.getMinutes();
|
|
1398
|
+
const seconds = now.getSeconds();
|
|
1399
|
+
|
|
1400
|
+
const values = [toBCD(seconds), toBCD(minutes), toBCD(hours) | 0x80, toBCD(day), toBCD(month), toBCD(year - 2000)].map(b => '0x' + b.toString(16).padStart(2, '0'));
|
|
1401
|
+
const content = ['0xE3', '0x07', '0x06', ...values];
|
|
1402
|
+
const checks = generateCrcCheckSum(content);
|
|
1403
|
+
const command = [...header, ...content, ...checks, '0x77'];
|
|
1404
|
+
console.log('command: ', command);
|
|
1405
|
+
return getData(
|
|
1406
|
+
deviceId,
|
|
1407
|
+
{
|
|
1408
|
+
command,
|
|
1409
|
+
commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0xe3, pkgLen: hexArr[3] + 7 }),
|
|
1410
|
+
pkgVerifyHandler: (pkg) => {
|
|
1411
|
+
return { verified: true };
|
|
1412
|
+
},
|
|
1413
|
+
},
|
|
1414
|
+
'SET_DDA5_E3'
|
|
1415
|
+
);
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
/** 读取BMS运行时长 */
|
|
1419
|
+
export const getDDA4F0Async = async (deviceId) => {
|
|
1420
|
+
// 指令:DD A4 F0 00 FF 0B 77
|
|
1421
|
+
const command = ['0xDD', '0xA4', '0xF0', '0x00'];
|
|
1422
|
+
const checks = generateCrcCheckSum(command.slice(2)); // 只对命令码和长度做校验
|
|
1423
|
+
const fullCommand = [...command, ...checks, '0x77'];
|
|
1424
|
+
|
|
1425
|
+
return getData(
|
|
1426
|
+
deviceId,
|
|
1427
|
+
{
|
|
1428
|
+
command: fullCommand,
|
|
1429
|
+
commandVerifyHandler: (hexArr) => ({
|
|
1430
|
+
verified: hexArr[0] == 0xDD && hexArr[1] == 0xF0,
|
|
1431
|
+
pkgLen: hexArr[3] + 7
|
|
1432
|
+
}),
|
|
1433
|
+
pkgVerifyHandler: (pkg) => {
|
|
1434
|
+
const len = pkg.length;
|
|
1435
|
+
const [c1, c2] = generateCrcCheckSum(pkg.slice(2, len - 3));
|
|
1436
|
+
const [_c1, _c2] = [pkg[len - 3], pkg[len - 2]];
|
|
1437
|
+
return { verified: c1 == _c1 && c2 == _c2 };
|
|
1438
|
+
},
|
|
1439
|
+
},
|
|
1440
|
+
'DDA4_F0'
|
|
1441
|
+
);
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
/** 解析BMS运行时长 */
|
|
1445
|
+
export const resolveDDA4F0 = (data) => {
|
|
1446
|
+
if (!data) return null;
|
|
1447
|
+
// 响应格式:DD F0 状态 长度 运行时长[4字节] 校验 0x77
|
|
1448
|
+
if (data[1] == 0xF0 && data[3] == 4) {
|
|
1449
|
+
// 运行时长为4字节,单位一般为秒(具体以协议为准)
|
|
1450
|
+
const runTime =
|
|
1451
|
+
(data[4] << 24) |
|
|
1452
|
+
(data[5] << 16) |
|
|
1453
|
+
(data[6] << 8) |
|
|
1454
|
+
data[7];
|
|
1455
|
+
return {
|
|
1456
|
+
runTime, // 运行时长(秒)
|
|
1457
|
+
runTimeHour: (runTime / 3600).toFixed(2), // 转为小时
|
|
1458
|
+
raw: hexArr2string(data)
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
return null;
|
|
1462
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { decimalToHex,
|
|
1
|
+
import { decimalToHex, generateCrcCheckSum, hex2string, hexArr2string, hexToDecimal } from '../BleDataProcess';
|
|
2
2
|
import { getData } from './BleCmdAnalysis.js';
|
|
3
3
|
|
|
4
4
|
export const getDDA420Async = async (deviceId) => {
|
|
5
5
|
const _command = ['0x20', '0x00'];
|
|
6
|
-
const checks =
|
|
6
|
+
const checks = generateCrcCheckSum(_command);
|
|
7
7
|
const command = ['0xdd', '0xa4', ..._command, ...checks, '0x77'];
|
|
8
8
|
|
|
9
9
|
const response = 'DD03002313E10000199D27100000310F00000000000014410310060BB60BC60BC10BBA0BBD0BC1F89777';
|
|
@@ -15,7 +15,7 @@ export const getDDA420Async = async (deviceId) => {
|
|
|
15
15
|
commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0x20, pkgLen: hexArr[3] + 7 }),
|
|
16
16
|
pkgVerifyHandler: (pkg) => {
|
|
17
17
|
const len = pkg.length;
|
|
18
|
-
const [c1, c2] =
|
|
18
|
+
const [c1, c2] = generateCrcCheckSum(pkg.slice(2, len - 3));
|
|
19
19
|
const [_c1, _c2] = [pkg[len - 3], pkg[len - 2]];
|
|
20
20
|
return { verified: c1 == _c1 && c2 == _c2 };
|
|
21
21
|
},
|
|
@@ -29,7 +29,7 @@ export const getDDA420Async = async (deviceId) => {
|
|
|
29
29
|
* @param {number[]} data DDA420十六进制数据数组
|
|
30
30
|
* @returns {Object} 解析后的充电器工作信息对象
|
|
31
31
|
* @returns {string} dataStr 十六进制数据数组转换后的字符串
|
|
32
|
-
* @returns {number} workStatus 工作状态:1=待机,2=就绪,3=激活电池中,4=通讯充电中,5=调试充电中,6=盲充中,7=结束充电
|
|
32
|
+
* @returns {number} workStatus 工作状态:1=待机,2=就绪,3=激活电池中,4=通讯充电中,5=调试充电中,6=盲充中,7=结束充电 8=停止充电(异常) 9=充电比对中 10=校准中 11=老化中 12=握手充电中 13=小电流充电中
|
|
33
33
|
* @returns {number} chargeStatus 充电状态:1=恒流,2=恒压,3=涓流
|
|
34
34
|
* @returns {number} chargeVoltage 充电电压,单位毫伏(mV)
|
|
35
35
|
* @returns {number} chargeElectricity 充电电流,单位毫安(mA)
|
|
@@ -51,7 +51,7 @@ export const getDDA420Async = async (deviceId) => {
|
|
|
51
51
|
* @returns {number} ratedPower 充电器额定功率,单位瓦特(W)
|
|
52
52
|
* @returns {number} inputVoltage 输入电压,单位毫伏(mV)
|
|
53
53
|
*/
|
|
54
|
-
export const resolveDDA420 =
|
|
54
|
+
export const resolveDDA420 = (data) => {
|
|
55
55
|
if (!data) return null;
|
|
56
56
|
const dataStr = hexArr2string(data);
|
|
57
57
|
let n = 4; // 起始偏移
|
|
@@ -251,7 +251,7 @@ export const getDDA420Async = async (deviceId) => {
|
|
|
251
251
|
* @param {number[]} data DDA421十六进制数据数组
|
|
252
252
|
* @returns {Object} 解析后的充电电池信息对象
|
|
253
253
|
*/
|
|
254
|
-
export const resolveDDA421 =
|
|
254
|
+
export const resolveDDA421 = (data) => {
|
|
255
255
|
if (!data) return null;
|
|
256
256
|
const dataStr = hexArr2string(data);
|
|
257
257
|
// 电池电压 4BYTE [4,5,6,7]
|
|
@@ -335,7 +335,7 @@ export const getDDA420Async = async (deviceId) => {
|
|
|
335
335
|
'DDA425'
|
|
336
336
|
);
|
|
337
337
|
}
|
|
338
|
-
export const resolveDDA425 =
|
|
338
|
+
export const resolveDDA425 = (data) => {
|
|
339
339
|
if (!data) return null;
|
|
340
340
|
const dataStr = hexArr2string(data);
|
|
341
341
|
return {
|
|
@@ -384,7 +384,7 @@ export const getDDA420Async = async (deviceId) => {
|
|
|
384
384
|
* @param {number[]} data DDA422响应数据
|
|
385
385
|
* @returns {Object} 解析结果
|
|
386
386
|
*/
|
|
387
|
-
export const resolveDDA422 =
|
|
387
|
+
export const resolveDDA422 = (data) => {
|
|
388
388
|
if (!data) return null;
|
|
389
389
|
const dataStr = hexArr2string(data);
|
|
390
390
|
// 起始地址 2BYTE [4,5]
|
|
@@ -447,14 +447,77 @@ export const getDDA420Async = async (deviceId) => {
|
|
|
447
447
|
'DDA423'
|
|
448
448
|
);
|
|
449
449
|
}
|
|
450
|
-
export const resolveDDA423 =
|
|
450
|
+
export const resolveDDA423 = (data) => {
|
|
451
451
|
if (!data) return null;
|
|
452
452
|
const dataStr = hexArr2string(data);
|
|
453
453
|
return {
|
|
454
454
|
dataStr,
|
|
455
455
|
status: hex2string(data[2])
|
|
456
456
|
};
|
|
457
|
+
}
|
|
458
|
+
/** 充电器充电测试 26 指令
|
|
459
|
+
* 发送: DD A4 26 09 <测试模式1B> <输出电压4B mV> <输出电流4B mA> CRC_H CRC_L 77
|
|
460
|
+
* 响应: DD 26 <状态位1B> 00 CRC_H CRC_L 77 (或: DD 26 <状态位> 00 ...)
|
|
461
|
+
* @param {string} deviceId 设备ID
|
|
462
|
+
* @param {number} testMode 测试模式 1=调试模式 2=老化模式
|
|
463
|
+
* @param {number} outputVoltage 输出目标电压(mV) 0~4294967295
|
|
464
|
+
* @param {number} outputCurrent 输出目标电流(mA) 0~4294967295
|
|
465
|
+
* @returns {Promise<number[]|null>} 原始响应数据数组; 失败返回 null
|
|
466
|
+
*/
|
|
467
|
+
export const getDDA426Async = async (deviceId, testMode = 0, outputVoltage = 0, outputCurrent = 0) => {
|
|
468
|
+
// 保护参数范围(简单防御,防止生成溢出字节/异常写入)
|
|
469
|
+
const clamp32 = (v) => {
|
|
470
|
+
v = Number(v) || 0; if (v < 0) v = 0; if (v > 0xFFFFFFFF) v = 0xFFFFFFFF; return v;
|
|
471
|
+
};
|
|
472
|
+
testMode = testMode === 2 ? 2 : 0; // 只允许 0 / 2
|
|
473
|
+
outputVoltage = clamp32(outputVoltage);
|
|
474
|
+
outputCurrent = clamp32(outputCurrent);
|
|
475
|
+
|
|
476
|
+
// 转 4 字节 (大端) 十六进制 -> 数组
|
|
477
|
+
const to4Bytes = (val) => {
|
|
478
|
+
const hex = commonfun.decimalToHex(val, 8); // 8位十六进制字符串
|
|
479
|
+
return [0, 2, 4, 6].map(i => parseInt(hex.slice(i, i + 2), 16));
|
|
480
|
+
};
|
|
481
|
+
const voltageArr = to4Bytes(outputVoltage);
|
|
482
|
+
const currentArr = to4Bytes(outputCurrent);
|
|
483
|
+
|
|
484
|
+
// 长度 = 1(模式) +4(电压)+4(电流) = 9
|
|
485
|
+
const lengthHex = commonfun.decimalToHex(9, 2); // '09'
|
|
486
|
+
const _command = ['0x26', `0x${lengthHex}`, testMode & 0xFF, ...voltageArr, ...currentArr].map(o => typeof o === 'number' ? `0x${('00' + o.toString(16)).slice(-2)}` : o);
|
|
487
|
+
// 去掉 0x 前缀转成数值数组生成 CRC
|
|
488
|
+
const _commandNums = _command.map(h => parseInt(h, 16));
|
|
489
|
+
const checks = generateCrcCheckSum(_commandNums);
|
|
490
|
+
const command = ['0xDD', '0xA4', ..._command, ...checks, '0x77'];
|
|
491
|
+
|
|
492
|
+
return getData(
|
|
493
|
+
deviceId,
|
|
494
|
+
{
|
|
495
|
+
command,
|
|
496
|
+
commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0x26, pkgLen: hexArr[3] + 7 }),
|
|
497
|
+
pkgVerifyHandler: (pkg) => {
|
|
498
|
+
// const len = pkg.length;
|
|
499
|
+
// const [c1, c2] = this.generateCrcCheckSum(pkg.slice(2, len - 3));
|
|
500
|
+
// const [_c1, _c2] = [pkg[len - 3], pkg[len - 2]];
|
|
501
|
+
// return { verified: c1 == _c1 && c2 == _c2 };
|
|
502
|
+
return { verified: true }
|
|
503
|
+
},
|
|
504
|
+
},
|
|
505
|
+
'DDA426(充电测试)',
|
|
506
|
+
3000
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/** 解析充电器充电测试 26 指令响应
|
|
511
|
+
* @param {number[]} data
|
|
512
|
+
* @returns {{dataStr:string,status:string}|null}
|
|
513
|
+
*/
|
|
514
|
+
|
|
515
|
+
export const resolveDDA426 = (data) => {
|
|
516
|
+
if (!data) return null;
|
|
517
|
+
const dataStr = hexArr2string(data);
|
|
518
|
+
return { dataStr, status: hex2string(data[2]) };
|
|
457
519
|
}
|
|
520
|
+
|
|
458
521
|
/** 查询充电历史数据27指令
|
|
459
522
|
* @param {*} deviceId
|
|
460
523
|
* @param {number} startTime 充电起始时间(秒,4字节)
|
|
@@ -509,7 +572,7 @@ export const getDDA420Async = async (deviceId) => {
|
|
|
509
572
|
* @param {number[]} data DDA427响应数据
|
|
510
573
|
* @returns {Object} 解析结果
|
|
511
574
|
*/
|
|
512
|
-
export const resolveDDA427 =
|
|
575
|
+
export const resolveDDA427 = (data) => {
|
|
513
576
|
if (!data) return null;
|
|
514
577
|
const dataStr = hexArr2string(data);
|
|
515
578
|
// 充电起始时间 4BYTE [4,5,6,7]
|
|
@@ -605,7 +668,7 @@ export const getDDA420Async = async (deviceId) => {
|
|
|
605
668
|
'DDA429'
|
|
606
669
|
);
|
|
607
670
|
}
|
|
608
|
-
export const resolveDDA429 =
|
|
671
|
+
export const resolveDDA429 = (data) => {
|
|
609
672
|
if (!data) return null;
|
|
610
673
|
const dataStr = hexArr2string(data);
|
|
611
674
|
let n = 4; // 起始偏移
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
export * from './BaseParamProtocol';
|
|
1
2
|
export * from './BleCmdAnalysis';
|
|
2
|
-
export * from './BleCmdFFAA';
|
|
3
3
|
export * from './BleCmdDD';
|
|
4
|
-
export * from './
|
|
5
|
-
export * from './
|
|
6
|
-
export * from './BleCmdHVES'
|
|
7
|
-
export * from './ESHostProtocol'
|
|
4
|
+
export * from './BleCmdDDA4';
|
|
5
|
+
export * from './BleCmdFFAA';
|
|
6
|
+
export * from './BleCmdHVES';
|
|
7
|
+
export * from './ESHostProtocol';
|
|
8
|
+
export * from './readAndSetParam';
|
|
@@ -353,3 +353,43 @@
|
|
|
353
353
|
return binaryString;
|
|
354
354
|
}
|
|
355
355
|
|
|
356
|
+
|
|
357
|
+
/**转BCD*/
|
|
358
|
+
export const fromBCD = (bcd) => {
|
|
359
|
+
// 确保只取低 8 位(安全)
|
|
360
|
+
bcd = bcd & 0xFF;
|
|
361
|
+
const tens = (bcd >> 4) & 0x0F; // 高4位
|
|
362
|
+
const units = bcd & 0x0F; // 低4位
|
|
363
|
+
return tens * 10 + units;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export const parseDateTime = (str) => {
|
|
367
|
+
const reg = /^(\d{4})-(\d{1,2})-(\d{1,2})\s+(\d{1,2}):(\d{1,2}):(\d{1,2})$/;
|
|
368
|
+
const match = str.match(reg);
|
|
369
|
+
if (!match) return null;
|
|
370
|
+
const [, y, m, d, h, i, s] = match.map(Number);
|
|
371
|
+
return new Date(y, m - 1, d, h, i, s).getTime();
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// 判断是否在30分钟内
|
|
375
|
+
export const isWithin30Minutes = (timeStr) => {
|
|
376
|
+
const now = Date.now(); // 手机当前时间(毫秒)
|
|
377
|
+
const targetTime = parseDateTime(timeStr);
|
|
378
|
+
// console.log('targetTime: ', targetTime);
|
|
379
|
+
if (targetTime === null) {
|
|
380
|
+
console.error('时间字符串格式错误:', timeStr);
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
const diff = Math.abs(now - targetTime); // 毫秒差
|
|
384
|
+
const thirtyMinutes = 30 * 60 * 1000; // 30分钟对应的毫秒数
|
|
385
|
+
return diff >= thirtyMinutes;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
export const toBCD = (num) => {
|
|
389
|
+
if (num < 0 || num > 99) {
|
|
390
|
+
throw new Error('BCD only supports 0-99');
|
|
391
|
+
}
|
|
392
|
+
const tens = Math.floor(num / 10); // 十位(0~9)
|
|
393
|
+
const units = num % 10; // 个位(0~9)
|
|
394
|
+
return (tens << 4) | units; // 高4位 + 低4位
|
|
395
|
+
}
|
package/src/core/OtaUpgrade.js
CHANGED
|
@@ -40,7 +40,9 @@ export class OTAUpgrade {
|
|
|
40
40
|
this.macAddr = macAddr;
|
|
41
41
|
this.platform = platform; // 'APP' | 'MP' | 'H5'
|
|
42
42
|
// 自动判断是否Telink,入参为macAddr
|
|
43
|
-
this.isTeLink = TelinkApi.isTeLink ? TelinkApi.isTeLink(
|
|
43
|
+
this.isTeLink = TelinkApi.isTeLink ? TelinkApi.isTeLink({
|
|
44
|
+
macAddr
|
|
45
|
+
}) : false;
|
|
44
46
|
this.onProgress = onProgress;
|
|
45
47
|
this.onSuccess = onSuccess;
|
|
46
48
|
this.onError = onError;
|
|
@@ -52,6 +54,7 @@ export class OTAUpgrade {
|
|
|
52
54
|
this.ready = true;
|
|
53
55
|
this.timer = null;
|
|
54
56
|
this.s_progress = 0;
|
|
57
|
+
this.otaStarting = false;
|
|
55
58
|
this.progressType = 'download'; // 当前进度类型: 'download' | 'upgrade'
|
|
56
59
|
}
|
|
57
60
|
|
|
@@ -70,6 +73,7 @@ export class OTAUpgrade {
|
|
|
70
73
|
const downloadTask = uni.downloadFile({
|
|
71
74
|
url: that.filePath,
|
|
72
75
|
success: ({ tempFilePath }) => {
|
|
76
|
+
this.addBLECharValueChangeListener();
|
|
73
77
|
that.resolve(tempFilePath).then(resolve).catch(reject);
|
|
74
78
|
},
|
|
75
79
|
fail: (res) => {
|
|
@@ -158,7 +162,6 @@ export class OTAUpgrade {
|
|
|
158
162
|
normalUpgrade() {
|
|
159
163
|
setTimeout(() => {
|
|
160
164
|
BLE.writeATCmd(this.otaInfo, this.deviceId, this.fail.bind(this));
|
|
161
|
-
this.addBLECharValueChangeListener();
|
|
162
165
|
}, 2600);
|
|
163
166
|
}
|
|
164
167
|
|
|
@@ -236,6 +239,7 @@ export class OTAUpgrade {
|
|
|
236
239
|
}
|
|
237
240
|
|
|
238
241
|
addBLECharValueChangeListener() {
|
|
242
|
+
console.log('添加蓝牙特征值变化监听');
|
|
239
243
|
const that = this;
|
|
240
244
|
uni.notifyBLECharacteristicValueChange({
|
|
241
245
|
deviceId: that.deviceId,
|
|
@@ -273,13 +277,19 @@ export class OTAUpgrade {
|
|
|
273
277
|
}
|
|
274
278
|
|
|
275
279
|
async doWithResponse(intArr) {
|
|
280
|
+
console.log('收到设备响应: ', intArr[2]);
|
|
276
281
|
if (intArr[2] == 0x80) {
|
|
277
282
|
let str = String.fromCharCode(...intArr.slice(4, -1));
|
|
283
|
+
console.log('doWithResponse otaStart1', str);
|
|
278
284
|
if (str.indexOf(this.otaInfo) > -1) {
|
|
279
285
|
this.finishedTimes = 0;
|
|
280
286
|
this.transferFirmwareFile();
|
|
281
287
|
}
|
|
282
|
-
if (str.indexOf(this.otaStart) > -1) {
|
|
288
|
+
if (str.indexOf(this.otaStart) > -1 || this.otaStarting) {
|
|
289
|
+
if (str.indexOf(this.otaStart) > -1) {
|
|
290
|
+
this.otaStarting = true;
|
|
291
|
+
}
|
|
292
|
+
console.log('doWithResponse otaStart2', str);
|
|
283
293
|
if (str.toUpperCase().includes('ERROR')) {
|
|
284
294
|
this.fail(str);
|
|
285
295
|
return;
|
|
@@ -313,10 +323,12 @@ export class OTAUpgrade {
|
|
|
313
323
|
if (timeFor51) {
|
|
314
324
|
const pkg = [0x00];
|
|
315
325
|
BLE.transferFirmwareFileCmd(this.deviceId, pkg, true, this.fail.bind(this));
|
|
326
|
+
console.log('[OTA]', '=== Send 51 ===', this.finishedTimes, this.totalTimes, pkg);
|
|
316
327
|
} else {
|
|
317
328
|
const pkg = this.fileHexArray.slice(this.finishedTimes * max, nextTime * max);
|
|
318
|
-
const index = Transfer.decimalToTwoByteHexArray(
|
|
329
|
+
const index = Transfer.decimalToTwoByteHexArray(this.finishedTimes);
|
|
319
330
|
BLE.transferFirmwareFileCmd(this.deviceId, index.concat(pkg), false, this.fail.bind(this));
|
|
331
|
+
console.log('[OTA]', `S50-${this.finishedTimes}/${this.totalTimes}`);
|
|
320
332
|
}
|
|
321
333
|
this.onProgress && this.onProgress({ type: 'upgrade', percent: Math.floor((this.finishedTimes * 100) / this.totalTimes) });
|
|
322
334
|
}
|
package/src/core/Transfer.js
CHANGED
|
@@ -252,7 +252,7 @@ export const BLE = {
|
|
|
252
252
|
readUUID: '0000FF01-0000-1000-8000-00805F9B34FB',
|
|
253
253
|
TAG: '[BLE_OTA]',
|
|
254
254
|
WRITE_DELAY: 25,
|
|
255
|
-
PACKAGE_MAX_LENGTH:
|
|
255
|
+
PACKAGE_MAX_LENGTH: 237,
|
|
256
256
|
// 分包发送
|
|
257
257
|
sendMsgToKey(buffer, deviceId, fail) {
|
|
258
258
|
const { isAndroid, isIOS } = getOS();
|
package/src/core/commonfun.js
CHANGED
|
@@ -34,7 +34,8 @@ export function getOS() {
|
|
|
34
34
|
const os = uni.getSystemInfoSync()?.osName;
|
|
35
35
|
return {
|
|
36
36
|
isIOS: os == 'ios',
|
|
37
|
-
isAndroid: os == 'android',
|
|
37
|
+
isAndroid: os == 'android' || os == 'openharmonyos',
|
|
38
|
+
isHarmony: os === 'harmony' || os === 'openharmonyos',
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
41
|
export function getPlatform() {
|