@jiabaida/tools 1.0.2 → 1.0.3

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.
@@ -1,762 +1,762 @@
1
- import { decimalToHex, generateCheckSum, generateCrcCheckSum, hex2string, hexArr2string, hexToDecimal } from '../BleDataProcess';
2
- import { getData } from './BleCmdAnalysis.js';
3
-
4
- export const getDDA420Async = async (deviceId) => {
5
- const _command = ['0x20', '0x00'];
6
- const checks = generateCheckSum(_command);
7
- const command = ['0xdd', '0xa4', ..._command, ...checks, '0x77'];
8
-
9
- const response = 'DD03002313E10000199D27100000310F00000000000014410310060BB60BC60BC10BBA0BBD0BC1F89777';
10
-
11
- return getData(
12
- deviceId,
13
- {
14
- command,
15
- commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0x20, pkgLen: hexArr[3] + 7 }),
16
- pkgVerifyHandler: (pkg) => {
17
- const len = pkg.length;
18
- const [c1, c2] = generateCheckSum(pkg.slice(2, len - 3));
19
- const [_c1, _c2] = [pkg[len - 3], pkg[len - 2]];
20
- return { verified: c1 == _c1 && c2 == _c2 };
21
- },
22
- },
23
- 'DDA420'
24
- );
25
- }
26
-
27
- /** 解析充电器工作信息20指令
28
- *
29
- * @param {number[]} data DDA420十六进制数据数组
30
- * @returns {Object} 解析后的充电器工作信息对象
31
- * @returns {string} dataStr 十六进制数据数组转换后的字符串
32
- * @returns {number} workStatus 工作状态:1=待机,2=就绪,3=激活电池中,4=通讯充电中,5=调试充电中,6=盲充中,7=结束充电
33
- * @returns {number} chargeStatus 充电状态:1=恒流,2=恒压,3=涓流
34
- * @returns {number} chargeVoltage 充电电压,单位毫伏(mV)
35
- * @returns {number} chargeElectricity 充电电流,单位毫安(mA)
36
- * @returns {number} chargePower 充电功率,单位瓦特(W)
37
- * @returns {number} chargeTemperature 充电器温度,单位摄氏度,保留一位小数
38
- * @returns {number} chargeCapacity 已充电量,单位毫安时(mAh)
39
- * @returns {number} chargeTime 充电时长,单位分钟(min)
40
- * @returns {number} chargeRemainTime 充电剩余时间,单位分钟(min)
41
- * @returns {number} outputVoltagePercent 输出电压占空比
42
- * @returns {number} outputElectricityPercent 输出电流占空比
43
- * @returns {number} outputVoltage 检测输出电压,单位毫伏(mV)
44
- * @returns {number} outputElectricity 检测输出电流,单位毫安(mA)
45
- * @returns {number} batteryVoltage 检测电池电压,单位毫伏(mV)
46
- * @returns {boolean} chargeSwitch 充电开关状态,true=打开,false=关闭
47
- * @returns {boolean} preChargeSwitch 预充开关状态,true=打开,false=关闭
48
- * @returns {boolean} fanSwitch 风扇开关状态,true=打开,false=关闭
49
- * @returns {number[]} protectStatusIndexs 保护状态索引数组,0=充电器过压,1=充电器过温,2=充电器过流,3=充电器短路
50
- * @returns {number[]} alarmStatusIndexs 告警状态索引数组,0=充电器继电器故障,1=充电器输出电压异常,2=充电器输出电流异常,3=充电器散热器故障
51
- * @returns {number} ratedPower 充电器额定功率,单位瓦特(W)
52
- * @returns {number} inputVoltage 输入电压,单位毫伏(mV)
53
- */
54
- export const resolveDDA420 = async (data) => {
55
- if (!data) return null;
56
- const dataStr = hexArr2string(data);
57
- let n = 4; // 起始偏移
58
-
59
- // 1. 工作状态
60
- const workStatus = data[n++];
61
-
62
- // 2. 充电状态
63
- const chargeStatus = data[n++];
64
-
65
- // 3. 充电电压(4字节)
66
- const chargeVoltage = hexToDecimal(
67
- decimalToHex(data[n++]) +
68
- decimalToHex(data[n++]) +
69
- decimalToHex(data[n++]) +
70
- decimalToHex(data[n++])
71
- );
72
-
73
- // 4. 充电电流(4字节)
74
- const chargeElectricity = hexToDecimal(
75
- decimalToHex(data[n++]) +
76
- decimalToHex(data[n++]) +
77
- decimalToHex(data[n++]) +
78
- decimalToHex(data[n++])
79
- );
80
-
81
- // 5. 充电功率(2字节)
82
- const chargePower = hexToDecimal(
83
- decimalToHex(data[n++]) +
84
- decimalToHex(data[n++])
85
- );
86
-
87
- // 6. 充电器温度(2字节)
88
- const chargeTemperature = hexToDecimal(
89
- decimalToHex(data[n++]) +
90
- decimalToHex(data[n++])
91
- ) / 10;
92
-
93
- // 7. 已充电量(4字节)
94
- const chargeCapacity = hexToDecimal(
95
- decimalToHex(data[n++]) +
96
- decimalToHex(data[n++]) +
97
- decimalToHex(data[n++]) +
98
- decimalToHex(data[n++])
99
- );
100
-
101
- // 8. 充电时长(2字节)
102
- const chargeTime = hexToDecimal(
103
- decimalToHex(data[n++]) +
104
- decimalToHex(data[n++])
105
- );
106
-
107
- // 9. 充电剩余时间(2字节)
108
- const chargeRemainTime = hexToDecimal(
109
- decimalToHex(data[n++]) +
110
- decimalToHex(data[n++])
111
- );
112
-
113
- // 10. 充电完成时长(2字节)
114
- const chargeCompleteTime = hexToDecimal(
115
- decimalToHex(data[n++]) +
116
- decimalToHex(data[n++])
117
- );
118
-
119
- // 输出电压占空比(4字节)
120
- const outputVoltagePercent = hexToDecimal(
121
- decimalToHex(data[n++]) +
122
- decimalToHex(data[n++]) +
123
- decimalToHex(data[n++]) +
124
- decimalToHex(data[n++])
125
- );
126
-
127
- // 输出电流占空比(4字节)
128
- const outputElectricityPercent = hexToDecimal(
129
- decimalToHex(data[n++]) +
130
- decimalToHex(data[n++]) +
131
- decimalToHex(data[n++]) +
132
- decimalToHex(data[n++])
133
- );
134
-
135
- // 检测输出电压(4字节)
136
- const outputVoltage = hexToDecimal(
137
- decimalToHex(data[n++]) +
138
- decimalToHex(data[n++]) +
139
- decimalToHex(data[n++]) +
140
- decimalToHex(data[n++])
141
- );
142
-
143
- // 检测输出电流(4字节)
144
- const outputElectricity = hexToDecimal(
145
- decimalToHex(data[n++]) +
146
- decimalToHex(data[n++]) +
147
- decimalToHex(data[n++]) +
148
- decimalToHex(data[n++])
149
- );
150
-
151
- // 检测电池电压(4字节)
152
- const batteryVoltage = hexToDecimal(
153
- decimalToHex(data[n++]) +
154
- decimalToHex(data[n++]) +
155
- decimalToHex(data[n++]) +
156
- decimalToHex(data[n++])
157
- );
158
-
159
- // 开关状态(2字节)
160
- const switchStatus = hexToDecimal(
161
- decimalToHex(data[n++]) +
162
- decimalToHex(data[n++])
163
- );
164
- const swtichStatusArr = switchStatus.toString(2).padStart(16, '0').split('').reverse();
165
- const chargeSwitch = swtichStatusArr[0] == '1';
166
- const preChargeSwitch = swtichStatusArr[1] == '1';
167
- const fanSwitch = swtichStatusArr[2] == '1';
168
-
169
- // 保护状态(4字节)
170
- const protectStatus = hexToDecimal(
171
- decimalToHex(data[n++]) +
172
- decimalToHex(data[n++]) +
173
- decimalToHex(data[n++]) +
174
- decimalToHex(data[n++])
175
- );
176
- const protectStatusArr = protectStatus.toString(2).padStart(32, '0').split('').reverse();
177
- let protectStatusIndexs = [];
178
- for (let i = 0; i < protectStatusArr.length; i++) {
179
- if (protectStatusArr[i] == '1') protectStatusIndexs.push(i);
180
- }
181
-
182
- // 告警状态(4字节)
183
- const alarmStatus = hexToDecimal(
184
- decimalToHex(data[n++]) +
185
- decimalToHex(data[n++]) +
186
- decimalToHex(data[n++]) +
187
- decimalToHex(data[n++])
188
- );
189
- const alarmStatusArr = alarmStatus.toString(2).padStart(32, '0').split('').reverse();
190
- let alarmStatusIndexs = [];
191
- for (let i = 0; i < alarmStatusArr.length; i++) {
192
- if (alarmStatusArr[i] == '1') alarmStatusIndexs.push(i);
193
- }
194
-
195
- // 通讯方式(1字节)
196
- const communicationMode = data[n++];
197
-
198
- return {
199
- dataStr,
200
- workStatus,
201
- chargeStatus,
202
- chargeVoltage,
203
- chargeElectricity,
204
- chargePower,
205
- chargeTemperature,
206
- chargeCapacity,
207
- chargeTime,
208
- chargeRemainTime,
209
- chargeCompleteTime,
210
- outputVoltagePercent,
211
- outputElectricityPercent,
212
- outputVoltage,
213
- outputElectricity,
214
- batteryVoltage,
215
- chargeSwitch,
216
- preChargeSwitch,
217
- fanSwitch,
218
- protectStatusIndexs,
219
- alarmStatusIndexs,
220
- communicationMode
221
- };
222
- }
223
-
224
- /** 获取充电电池信息21指令
225
- *
226
- * @param {*} deviceId
227
- * @returns
228
- */
229
- export const getDDA421Async = async (deviceId) => {
230
- const _command = ['0x21', '0x00'];
231
- const checks = generateCrcCheckSum(_command);
232
- const command = ['0xdd', '0xa4', ..._command, ...checks, '0x77'];
233
-
234
- return this.getData(
235
- deviceId,
236
- {
237
- command,
238
- commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0x21, pkgLen: hexArr[3] + 7 }),
239
- pkgVerifyHandler: (pkg) => {
240
- const len = pkg.length;
241
- const [c1, c2] = generateCrcCheckSum(pkg.slice(2, len - 3));
242
- const [_c1, _c2] = [pkg[len - 3], pkg[len - 2]];
243
- return { verified: c1 == _c1 && c2 == _c2 };
244
- },
245
- },
246
- 'DDA421'
247
- );
248
- }
249
- /** 解析充电电池信息21指令
250
- *
251
- * @param {number[]} data DDA421十六进制数据数组
252
- * @returns {Object} 解析后的充电电池信息对象
253
- */
254
- export const resolveDDA421 = async (data) => {
255
- if (!data) return null;
256
- const dataStr = hexArr2string(data);
257
- // 电池电压 4BYTE [4,5,6,7]
258
- const batteryVoltageHex = decimalToHex(data[4]) + decimalToHex(data[5]) + decimalToHex(data[6]) + decimalToHex(data[7]);
259
- const batteryVoltage = hexToDecimal(batteryVoltageHex); // mV
260
- // 电池电流 4BYTE [8,9,10,11]
261
- const batteryCurrentHex = decimalToHex(data[8]) + decimalToHex(data[9]) + decimalToHex(data[10]) + decimalToHex(data[11]);
262
- const batteryCurrent = hexToDecimal(batteryCurrentHex); // mA
263
- // 电池类型 1BYTE [12]
264
- const batteryType = data[12];
265
- // 电池串数 1BYTE [13]
266
- const batterySeries = data[13];
267
- // 电池容量 4BYTE [14,15,16,17]
268
- const batteryCapacityHex = decimalToHex(data[14]) + decimalToHex(data[15]) + decimalToHex(data[16]) + decimalToHex(data[17]);
269
- const batteryCapacity = hexToDecimal(batteryCapacityHex); // mAH
270
- // 电池SOC 1BYTE [18]
271
- const batterySOC = data[18]; // %
272
- // 电池温度 2BYTE [19,20]
273
- const batteryTempHex = decimalToHex(data[19]) + decimalToHex(data[20]);
274
- const batteryTemperature = hexToDecimal(batteryTempHex) / 10; // 0.1摄氏度
275
- // const batteryTemperature = [data[19] ?? 0, [data[20] ?? 0]] // 摄氏度,保留一位小数
276
- // 加热状态 1BYTE [21]
277
- const heatingStatus = data[21]; // 0未加热 1加热中
278
- // 加热电流 4BYTE [22,23,24,25]
279
- const heatingCurrentHex = decimalToHex(data[22]) + decimalToHex(data[23]) + decimalToHex(data[24]) + decimalToHex(data[25]);
280
- const heatingCurrent = hexToDecimal(heatingCurrentHex); // mA
281
- // 保护状态 2BYTE [26,27]
282
- const protectStatusHex = decimalToHex(data[26]) + decimalToHex(data[27]);
283
- const protectStatus = hexToDecimal(protectStatusHex);
284
- const protectStatusArr = protectStatus.toString(2).padStart(16, '0').split('').reverse();
285
- let protectStatusIndexs = [];
286
- for (let i = 0; i < protectStatusArr.length; i++) {
287
- if (protectStatusArr[i] == '1') {
288
- protectStatusIndexs.push(i);
289
- }
290
- }
291
- // 告警状态 2BYTE [28,29]
292
- const alarmStatusHex = decimalToHex(data[28]) + decimalToHex(data[29]);
293
- const alarmStatus = hexToDecimal(alarmStatusHex);
294
- const alarmStatusArr = alarmStatus.toString(2).padStart(16, '0').split('').reverse();
295
- let alarmStatusIndexs = [];
296
- for (let i = 0; i < alarmStatusArr.length; i++) {
297
- if (alarmStatusArr[i] == '1') {
298
- alarmStatusIndexs.push(i);
299
- }
300
- }
301
- return {
302
- dataStr,
303
- batteryVoltage,
304
- batteryCurrent,
305
- batteryType,
306
- batterySeries,
307
- batteryCapacity,
308
- batterySOC,
309
- batteryTemperature,
310
- heatingStatus,
311
- heatingCurrent,
312
- protectStatusIndexs,
313
- alarmStatusIndexs
314
- };
315
- }
316
- /**充电器激活电池
317
- * type:
318
- * 0x00 - 取消激活
319
- * 0x01 - 激活
320
- */
321
- export const getDDA425Async = async (deviceId, type) => {
322
- const _command = ['0x25', '0x01', type];
323
- const checks = generateCrcCheckSum(_command);
324
- const command = ['0xDD', '0xA4', ..._command, ...checks, '0x77'];
325
- console.log('command: ', command);
326
- return getData(
327
- deviceId,
328
- {
329
- command,
330
- commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0x25, pkgLen: hexArr[3] + 7 }),
331
- pkgVerifyHandler: (pkg) => {
332
- return { verified: true };
333
- },
334
- },
335
- 'DDA425'
336
- );
337
- }
338
- export const resolveDDA425 = async (data) => {
339
- if (!data) return null;
340
- const dataStr = hexArr2string(data);
341
- return {
342
- dataStr,
343
- status: hex2string(data[2])
344
- };
345
- }
346
- /** 查询充电器参数22指令
347
- * @param {*} deviceId
348
- * @param {number} startReg 寄存器起始地址(2字节,十进制或十六进制均可)
349
- * @param {number} endReg 寄存器结束地址(2字节,十进制或十六进制均可)
350
- * @returns
351
- */
352
- export const getDDA422Async = async (deviceId, startReg, endReg) => {
353
- // 转为2字节十六进制字符串
354
- const startRegHex = decimalToHex(startReg, 4);
355
- const endRegHex = decimalToHex(endReg, 4);
356
- // 拆分为高低字节
357
- const startRegArr = [
358
- parseInt(startRegHex.slice(0, 2), 16),
359
- parseInt(startRegHex.slice(2, 4), 16)
360
- ];
361
- const endRegArr = [
362
- parseInt(endRegHex.slice(0, 2), 16),
363
- parseInt(endRegHex.slice(2, 4), 16)
364
- ];
365
- const _command = ['0x22', '0x04', ...startRegArr, ...endRegArr];
366
- const checks = generateCrcCheckSum(_command);
367
- const command = ['0xDD', '0xA4', ..._command, ...checks, '0x77'];
368
- return getData(
369
- deviceId,
370
- {
371
- command,
372
- commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0x22, pkgLen: hexArr[3] + 7 }),
373
- pkgVerifyHandler: (pkg) => {
374
- const len = pkg.length;
375
- const [c1, c2] = generateCrcCheckSum(pkg.slice(2, len - 3));
376
- const [_c1, _c2] = [pkg[len - 3], pkg[len - 2]];
377
- return { verified: c1 == _c1 && c2 == _c2 };
378
- },
379
- },
380
- 'DDA422'
381
- );
382
- }
383
- /** 解析充电器参数22指令响应
384
- * @param {number[]} data DDA422响应数据
385
- * @returns {Object} 解析结果
386
- */
387
- export const resolveDDA422 = async (data) => {
388
- if (!data) return null;
389
- const dataStr = hexArr2string(data);
390
- // 起始地址 2BYTE [4,5]
391
- const startRegHex = decimalToHex(data[4]) + decimalToHex(data[5]);
392
- const startReg = hexToDecimal(startRegHex);
393
- // 结束地址 2BYTE [6,7]
394
- const endRegHex = decimalToHex(data[6]) + decimalToHex(data[7]);
395
- const endReg = hexToDecimal(endRegHex);
396
- // 寄存器数据 [8, ...]
397
- const regData = data.slice(8, data.length - 3); // 去掉校验和和停止位
398
- return {
399
- dataStr,
400
- startReg,
401
- endReg,
402
- regData
403
- };
404
- }
405
- /**
406
- * 设置充电器参数23指令
407
- */
408
- 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);
431
-
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 };
445
- },
446
- },
447
- 'DDA423'
448
- );
449
- }
450
- export const resolveDDA423 = async (data) => {
451
- if (!data) return null;
452
- const dataStr = hexArr2string(data);
453
- return {
454
- dataStr,
455
- status: hex2string(data[2])
456
- };
457
- }
458
- /** 查询充电历史数据27指令
459
- * @param {*} deviceId
460
- * @param {number} startTime 充电起始时间(秒,4字节)
461
- * @param {number} endTime 充电结束时间(秒,4字节)
462
- * @param {number} granularity 数据颗粒度(1:一分钟,2:五分钟)
463
- * @returns
464
- */
465
- export const getDDA427Async = async (deviceId, startTime, endTime, granularity = 2, type = 1) => {
466
- // 4字节起始时间 - 将十进制时间直接转换为4字节的十六进制数组
467
- // 首先将十进制数转为十六进制字符串,然后拆分成4个字节
468
- const startTimeHex = startTime.toString(16).padStart(8, '0');
469
- const endTimeHex = endTime.toString(16).padStart(8, '0');
470
-
471
- // 拆分为4字节,并转换为十六进制数值
472
- const startTimeArr = [
473
- parseInt(startTimeHex.slice(0, 2), 16),
474
- parseInt(startTimeHex.slice(2, 4), 16),
475
- parseInt(startTimeHex.slice(4, 6), 16),
476
- parseInt(startTimeHex.slice(6, 8), 16)
477
- ];
478
- const endTimeArr = [
479
- parseInt(endTimeHex.slice(0, 2), 16),
480
- parseInt(endTimeHex.slice(2, 4), 16),
481
- parseInt(endTimeHex.slice(4, 6), 16),
482
- parseInt(endTimeHex.slice(6, 8), 16)
483
- ];
484
- // 历史数据类型
485
- const historyType = decimalToHex(type, 2); // 0x00:充电历史数据
486
- // 数据颗粒度1字节
487
- const granularityArr = decimalToHex(granularity, 2);
488
- const _command = ['0x27', '0x0A', ...startTimeArr, ...endTimeArr, historyType, granularityArr];
489
- const checks = generateCrcCheckSum(_command);
490
- const command = ['0xDD', '0xA4', ..._command, ...checks, '0x77'];
491
- console.log('getDDA427Async getDDA427Async', startTimeHex, endTimeHex, startTimeArr, endTimeArr, granularity, command);
492
- return getData(
493
- deviceId,
494
- {
495
- command,
496
- commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0x27, pkgLen: hexArr[3] + 7 }),
497
- pkgVerifyHandler: (pkg) => {
498
- const len = pkg.length;
499
- const [c1, c2] = generateCrcCheckSum(pkg.slice(2, len - 3));
500
- const [_c1, _c2] = [pkg[len - 3], pkg[len - 2]];
501
- return { verified: c1 == _c1 && c2 == _c2 };
502
- },
503
- },
504
- 'DDA427',
505
- 3000
506
- );
507
- }
508
- /** 解析充电历史数据27指令响应
509
- * @param {number[]} data DDA427响应数据
510
- * @returns {Object} 解析结果
511
- */
512
- export const resolveDDA427 = async (data) => {
513
- if (!data) return null;
514
- const dataStr = hexArr2string(data);
515
- // 充电起始时间 4BYTE [4,5,6,7]
516
- const startTimeHex = decimalToHex(data[4]) + decimalToHex(data[5]) + decimalToHex(data[6]) + decimalToHex(data[7]);
517
- const startTime = hexToDecimal(startTimeHex);
518
- // 充电结束时间 4BYTE [8,9,10,11]
519
- const endTimeHex = decimalToHex(data[8]) + decimalToHex(data[9]) + decimalToHex(data[10]) + decimalToHex(data[11]);
520
- const endTime = hexToDecimal(endTimeHex);
521
- // 历史数据类型 1BYTE [12]
522
- const historyType = data[12]; // 0x00:充电历史数据
523
- // 数据颗粒度 1BYTE [13]
524
- const granularity = data[13];
525
- // 实际数量N 1BYTE [14]
526
- const count = data[14];
527
- // 历史数据 [15, ...] 每条8BYTE
528
- let history = [];
529
- for (let i = 0; i < count; i++) {
530
- const base = 15 + i * 8;
531
- // 充电电压 4BYTE
532
- const voltageHex = decimalToHex(data[base]) + decimalToHex(data[base+1]) + decimalToHex(data[base+2]) + decimalToHex(data[base+3]);
533
- const voltage = hexToDecimal(voltageHex);
534
- // 充电电流 4BYTE
535
- const currentHex = decimalToHex(data[base+4]) + decimalToHex(data[base+5]) + decimalToHex(data[base+6]) + decimalToHex(data[base+7]);
536
- const current = hexToDecimal(currentHex);
537
- history.push({ current, voltage });
538
- }
539
- console.log('historyType', historyType)
540
- return {
541
- dataStr,
542
- startTime,
543
- endTime,
544
- historyType,
545
- granularity,
546
- count,
547
- history
548
- };
549
- }
550
- /** 充电器测试指令
551
- *
552
- * @param {*} deviceId
553
- * @returns
554
- */
555
- export const getDDA429Async = async (deviceId, id) => {
556
- // id、是四个bites
557
- const idHex = decimalToHex(id, 8);
558
- // 拆分为4字节
559
- const idArr = [
560
- parseInt(idHex.slice(0, 2), 16),
561
- parseInt(idHex.slice(2, 4), 16),
562
- parseInt(idHex.slice(4, 6), 16),
563
- parseInt(idHex.slice(4, 6), 16),
564
- parseInt(idHex.slice(6, 8), 16)
565
- ];
566
- const _command = ['0x29', '0x04', ...idArr];
567
- const checks = generateCrcCheckSum(_command);
568
- const command = ['0xdd', '0xa4', ..._command, ...checks, '0x77'];
569
-
570
-
571
- return getData(
572
- deviceId,
573
- {
574
- command,
575
- commandVerifyHandler: (hexArr) => {
576
- // 基本头部验证
577
- if (hexArr[0] != 0xdd || hexArr[1] != 0x29) return { verified: false, pkgLen: null };
578
-
579
- // 验证数据包长度是否合理
580
- if (hexArr.length < 8) return { verified: false, pkgLen: null };
581
-
582
- // 根据resolveDDA429的解析结构,ID在响应偏移32位置
583
- // 实际协议中可能有所不同,需要根据协议规范调整
584
- if (hexArr.length >= 36) {
585
- // 从resolveDDA429可知,ID位于n=32处的4个字节
586
- const respIdHex = decimalToHex(hexArr[32]) +
587
- decimalToHex(hexArr[33]) +
588
- decimalToHex(hexArr[34]) +
589
- decimalToHex(hexArr[35]);
590
- const respId = hexToDecimal(respIdHex);
591
-
592
- // 如果ID不匹配,则拒绝该数据包
593
- if (respId !== id) return { verified: false, pkgLen: null };
594
- }
595
-
596
- return { verified: true, pkgLen: hexArr[3] + 7 };
597
- },
598
- pkgVerifyHandler: (pkg) => {
599
- const len = pkg.length;
600
- const [c1, c2] = generateCrcCheckSum(pkg.slice(2, len - 3));
601
- const [_c1, _c2] = [pkg[len - 3], pkg[len - 2]];
602
- return { verified: c1 == _c1 && c2 == _c2 };
603
- },
604
- },
605
- 'DDA429'
606
- );
607
- }
608
- export const resolveDDA429 = async (data) => {
609
- if (!data) return null;
610
- const dataStr = hexArr2string(data);
611
- let n = 4; // 起始偏移
612
-
613
- // 1. 工作状态
614
- const workStatus = data[n++];
615
-
616
- // 2. 充电状态
617
- const chargeStatus = data[n++];
618
-
619
- // 3. 充电电压(4字节)
620
- const chargeVoltage = hexToDecimal(
621
- decimalToHex(data[n++]) +
622
- decimalToHex(data[n++]) +
623
- decimalToHex(data[n++]) +
624
- decimalToHex(data[n++])
625
- );
626
-
627
- // 4. 充电电流(4字节)
628
- const chargeElectricity = hexToDecimal(
629
- decimalToHex(data[n++]) +
630
- decimalToHex(data[n++]) +
631
- decimalToHex(data[n++]) +
632
- decimalToHex(data[n++])
633
- );
634
-
635
- // 5. 充电功率(2字节)
636
- const chargePower = hexToDecimal(
637
- decimalToHex(data[n++]) +
638
- decimalToHex(data[n++])
639
- );
640
-
641
- // 6. 充电器温度(2字节)
642
- const chargeTemperature = hexToDecimal(
643
- decimalToHex(data[n++]) +
644
- decimalToHex(data[n++])
645
- ) / 10;
646
-
647
- // 7. 已充电量(4字节)
648
- const chargeCapacity = hexToDecimal(
649
- decimalToHex(data[n++]) +
650
- decimalToHex(data[n++]) +
651
- decimalToHex(data[n++]) +
652
- decimalToHex(data[n++])
653
- );
654
-
655
- // 8. 充电时长(2字节)
656
- const chargeTime = hexToDecimal(
657
- decimalToHex(data[n++]) +
658
- decimalToHex(data[n++])
659
- );
660
-
661
- // 9. 充电剩余时间(2字节)
662
- const chargeRemainTime = hexToDecimal(
663
- decimalToHex(data[n++]) +
664
- decimalToHex(data[n++])
665
- );
666
-
667
- // 10. 充电完成时长(2字节)
668
- const chargeCompleteTime = hexToDecimal(
669
- decimalToHex(data[n++]) +
670
- decimalToHex(data[n++])
671
- );
672
-
673
- // 输出电压占空比
674
- const outputVoltagePercent = data[n++];
675
-
676
- // 输出电流占空比
677
- const outputElectricityPercent = data[n++];
678
-
679
- // id(4字节)
680
- const id1 = hexToDecimal(
681
- decimalToHex(data[n++]) +
682
- decimalToHex(data[n++]) +
683
- decimalToHex(data[n++]) +
684
- decimalToHex(data[n++])
685
- );
686
-
687
- // 检测输出电流(4字节)
688
- const outputElectricity = hexToDecimal(
689
- decimalToHex(data[n++]) +
690
- decimalToHex(data[n++]) +
691
- decimalToHex(data[n++]) +
692
- decimalToHex(data[n++])
693
- );
694
-
695
- // 检测电池电压(4字节)
696
- const id = hexToDecimal(
697
- decimalToHex(data[n++]) +
698
- decimalToHex(data[n++]) +
699
- decimalToHex(data[n++]) +
700
- decimalToHex(data[n++])
701
- );
702
-
703
- // 开关状态(2字节)
704
- const switchStatus = hexToDecimal(
705
- decimalToHex(data[n++]) +
706
- decimalToHex(data[n++])
707
- );
708
- const swtichStatusArr = switchStatus.toString(2).padStart(16, '0').split('').reverse();
709
- const chargeSwitch = swtichStatusArr[0] == '1';
710
- const preChargeSwitch = swtichStatusArr[1] == '1';
711
- const fanSwitch = swtichStatusArr[2] == '1';
712
-
713
- // 保护状态(4字节)
714
- const protectStatus = hexToDecimal(
715
- decimalToHex(data[n++]) +
716
- decimalToHex(data[n++]) +
717
- decimalToHex(data[n++]) +
718
- decimalToHex(data[n++])
719
- );
720
- const protectStatusArr = protectStatus.toString(2).padStart(32, '0').split('').reverse();
721
- let protectStatusIndexs = [];
722
- for (let i = 0; i < protectStatusArr.length; i++) {
723
- if (protectStatusArr[i] == '1') protectStatusIndexs.push(i);
724
- }
725
-
726
- // 告警状态(4字节)
727
- const alarmStatus = hexToDecimal(
728
- decimalToHex(data[n++]) +
729
- decimalToHex(data[n++]) +
730
- decimalToHex(data[n++]) +
731
- decimalToHex(data[n++])
732
- );
733
- const alarmStatusArr = alarmStatus.toString(2).padStart(32, '0').split('').reverse();
734
- let alarmStatusIndexs = [];
735
- for (let i = 0; i < alarmStatusArr.length; i++) {
736
- if (alarmStatusArr[i] == '1') alarmStatusIndexs.push(i);
737
- }
738
-
739
- return {
740
- dataStr,
741
- workStatus,
742
- chargeStatus,
743
- chargeVoltage,
744
- chargeElectricity,
745
- chargePower,
746
- chargeTemperature,
747
- chargeCapacity,
748
- chargeTime,
749
- chargeRemainTime,
750
- chargeCompleteTime,
751
- outputVoltagePercent,
752
- outputElectricityPercent,
753
- id,
754
- outputElectricity,
755
- id1,
756
- chargeSwitch,
757
- preChargeSwitch,
758
- fanSwitch,
759
- protectStatusIndexs,
760
- alarmStatusIndexs,
761
- };
1
+ import { decimalToHex, generateCheckSum, generateCrcCheckSum, hex2string, hexArr2string, hexToDecimal } from '../BleDataProcess';
2
+ import { getData } from './BleCmdAnalysis.js';
3
+
4
+ export const getDDA420Async = async (deviceId) => {
5
+ const _command = ['0x20', '0x00'];
6
+ const checks = generateCheckSum(_command);
7
+ const command = ['0xdd', '0xa4', ..._command, ...checks, '0x77'];
8
+
9
+ const response = 'DD03002313E10000199D27100000310F00000000000014410310060BB60BC60BC10BBA0BBD0BC1F89777';
10
+
11
+ return getData(
12
+ deviceId,
13
+ {
14
+ command,
15
+ commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0x20, pkgLen: hexArr[3] + 7 }),
16
+ pkgVerifyHandler: (pkg) => {
17
+ const len = pkg.length;
18
+ const [c1, c2] = generateCheckSum(pkg.slice(2, len - 3));
19
+ const [_c1, _c2] = [pkg[len - 3], pkg[len - 2]];
20
+ return { verified: c1 == _c1 && c2 == _c2 };
21
+ },
22
+ },
23
+ 'DDA420'
24
+ );
25
+ }
26
+
27
+ /** 解析充电器工作信息20指令
28
+ *
29
+ * @param {number[]} data DDA420十六进制数据数组
30
+ * @returns {Object} 解析后的充电器工作信息对象
31
+ * @returns {string} dataStr 十六进制数据数组转换后的字符串
32
+ * @returns {number} workStatus 工作状态:1=待机,2=就绪,3=激活电池中,4=通讯充电中,5=调试充电中,6=盲充中,7=结束充电
33
+ * @returns {number} chargeStatus 充电状态:1=恒流,2=恒压,3=涓流
34
+ * @returns {number} chargeVoltage 充电电压,单位毫伏(mV)
35
+ * @returns {number} chargeElectricity 充电电流,单位毫安(mA)
36
+ * @returns {number} chargePower 充电功率,单位瓦特(W)
37
+ * @returns {number} chargeTemperature 充电器温度,单位摄氏度,保留一位小数
38
+ * @returns {number} chargeCapacity 已充电量,单位毫安时(mAh)
39
+ * @returns {number} chargeTime 充电时长,单位分钟(min)
40
+ * @returns {number} chargeRemainTime 充电剩余时间,单位分钟(min)
41
+ * @returns {number} outputVoltagePercent 输出电压占空比
42
+ * @returns {number} outputElectricityPercent 输出电流占空比
43
+ * @returns {number} outputVoltage 检测输出电压,单位毫伏(mV)
44
+ * @returns {number} outputElectricity 检测输出电流,单位毫安(mA)
45
+ * @returns {number} batteryVoltage 检测电池电压,单位毫伏(mV)
46
+ * @returns {boolean} chargeSwitch 充电开关状态,true=打开,false=关闭
47
+ * @returns {boolean} preChargeSwitch 预充开关状态,true=打开,false=关闭
48
+ * @returns {boolean} fanSwitch 风扇开关状态,true=打开,false=关闭
49
+ * @returns {number[]} protectStatusIndexs 保护状态索引数组,0=充电器过压,1=充电器过温,2=充电器过流,3=充电器短路
50
+ * @returns {number[]} alarmStatusIndexs 告警状态索引数组,0=充电器继电器故障,1=充电器输出电压异常,2=充电器输出电流异常,3=充电器散热器故障
51
+ * @returns {number} ratedPower 充电器额定功率,单位瓦特(W)
52
+ * @returns {number} inputVoltage 输入电压,单位毫伏(mV)
53
+ */
54
+ export const resolveDDA420 = async (data) => {
55
+ if (!data) return null;
56
+ const dataStr = hexArr2string(data);
57
+ let n = 4; // 起始偏移
58
+
59
+ // 1. 工作状态
60
+ const workStatus = data[n++];
61
+
62
+ // 2. 充电状态
63
+ const chargeStatus = data[n++];
64
+
65
+ // 3. 充电电压(4字节)
66
+ const chargeVoltage = hexToDecimal(
67
+ decimalToHex(data[n++]) +
68
+ decimalToHex(data[n++]) +
69
+ decimalToHex(data[n++]) +
70
+ decimalToHex(data[n++])
71
+ );
72
+
73
+ // 4. 充电电流(4字节)
74
+ const chargeElectricity = hexToDecimal(
75
+ decimalToHex(data[n++]) +
76
+ decimalToHex(data[n++]) +
77
+ decimalToHex(data[n++]) +
78
+ decimalToHex(data[n++])
79
+ );
80
+
81
+ // 5. 充电功率(2字节)
82
+ const chargePower = hexToDecimal(
83
+ decimalToHex(data[n++]) +
84
+ decimalToHex(data[n++])
85
+ );
86
+
87
+ // 6. 充电器温度(2字节)
88
+ const chargeTemperature = hexToDecimal(
89
+ decimalToHex(data[n++]) +
90
+ decimalToHex(data[n++])
91
+ ) / 10;
92
+
93
+ // 7. 已充电量(4字节)
94
+ const chargeCapacity = hexToDecimal(
95
+ decimalToHex(data[n++]) +
96
+ decimalToHex(data[n++]) +
97
+ decimalToHex(data[n++]) +
98
+ decimalToHex(data[n++])
99
+ );
100
+
101
+ // 8. 充电时长(2字节)
102
+ const chargeTime = hexToDecimal(
103
+ decimalToHex(data[n++]) +
104
+ decimalToHex(data[n++])
105
+ );
106
+
107
+ // 9. 充电剩余时间(2字节)
108
+ const chargeRemainTime = hexToDecimal(
109
+ decimalToHex(data[n++]) +
110
+ decimalToHex(data[n++])
111
+ );
112
+
113
+ // 10. 充电完成时长(2字节)
114
+ const chargeCompleteTime = hexToDecimal(
115
+ decimalToHex(data[n++]) +
116
+ decimalToHex(data[n++])
117
+ );
118
+
119
+ // 输出电压占空比(4字节)
120
+ const outputVoltagePercent = hexToDecimal(
121
+ decimalToHex(data[n++]) +
122
+ decimalToHex(data[n++]) +
123
+ decimalToHex(data[n++]) +
124
+ decimalToHex(data[n++])
125
+ );
126
+
127
+ // 输出电流占空比(4字节)
128
+ const outputElectricityPercent = hexToDecimal(
129
+ decimalToHex(data[n++]) +
130
+ decimalToHex(data[n++]) +
131
+ decimalToHex(data[n++]) +
132
+ decimalToHex(data[n++])
133
+ );
134
+
135
+ // 检测输出电压(4字节)
136
+ const outputVoltage = hexToDecimal(
137
+ decimalToHex(data[n++]) +
138
+ decimalToHex(data[n++]) +
139
+ decimalToHex(data[n++]) +
140
+ decimalToHex(data[n++])
141
+ );
142
+
143
+ // 检测输出电流(4字节)
144
+ const outputElectricity = hexToDecimal(
145
+ decimalToHex(data[n++]) +
146
+ decimalToHex(data[n++]) +
147
+ decimalToHex(data[n++]) +
148
+ decimalToHex(data[n++])
149
+ );
150
+
151
+ // 检测电池电压(4字节)
152
+ const batteryVoltage = hexToDecimal(
153
+ decimalToHex(data[n++]) +
154
+ decimalToHex(data[n++]) +
155
+ decimalToHex(data[n++]) +
156
+ decimalToHex(data[n++])
157
+ );
158
+
159
+ // 开关状态(2字节)
160
+ const switchStatus = hexToDecimal(
161
+ decimalToHex(data[n++]) +
162
+ decimalToHex(data[n++])
163
+ );
164
+ const swtichStatusArr = switchStatus.toString(2).padStart(16, '0').split('').reverse();
165
+ const chargeSwitch = swtichStatusArr[0] == '1';
166
+ const preChargeSwitch = swtichStatusArr[1] == '1';
167
+ const fanSwitch = swtichStatusArr[2] == '1';
168
+
169
+ // 保护状态(4字节)
170
+ const protectStatus = hexToDecimal(
171
+ decimalToHex(data[n++]) +
172
+ decimalToHex(data[n++]) +
173
+ decimalToHex(data[n++]) +
174
+ decimalToHex(data[n++])
175
+ );
176
+ const protectStatusArr = protectStatus.toString(2).padStart(32, '0').split('').reverse();
177
+ let protectStatusIndexs = [];
178
+ for (let i = 0; i < protectStatusArr.length; i++) {
179
+ if (protectStatusArr[i] == '1') protectStatusIndexs.push(i);
180
+ }
181
+
182
+ // 告警状态(4字节)
183
+ const alarmStatus = hexToDecimal(
184
+ decimalToHex(data[n++]) +
185
+ decimalToHex(data[n++]) +
186
+ decimalToHex(data[n++]) +
187
+ decimalToHex(data[n++])
188
+ );
189
+ const alarmStatusArr = alarmStatus.toString(2).padStart(32, '0').split('').reverse();
190
+ let alarmStatusIndexs = [];
191
+ for (let i = 0; i < alarmStatusArr.length; i++) {
192
+ if (alarmStatusArr[i] == '1') alarmStatusIndexs.push(i);
193
+ }
194
+
195
+ // 通讯方式(1字节)
196
+ const communicationMode = data[n++];
197
+
198
+ return {
199
+ dataStr,
200
+ workStatus,
201
+ chargeStatus,
202
+ chargeVoltage,
203
+ chargeElectricity,
204
+ chargePower,
205
+ chargeTemperature,
206
+ chargeCapacity,
207
+ chargeTime,
208
+ chargeRemainTime,
209
+ chargeCompleteTime,
210
+ outputVoltagePercent,
211
+ outputElectricityPercent,
212
+ outputVoltage,
213
+ outputElectricity,
214
+ batteryVoltage,
215
+ chargeSwitch,
216
+ preChargeSwitch,
217
+ fanSwitch,
218
+ protectStatusIndexs,
219
+ alarmStatusIndexs,
220
+ communicationMode
221
+ };
222
+ }
223
+
224
+ /** 获取充电电池信息21指令
225
+ *
226
+ * @param {*} deviceId
227
+ * @returns
228
+ */
229
+ export const getDDA421Async = async (deviceId) => {
230
+ const _command = ['0x21', '0x00'];
231
+ const checks = generateCrcCheckSum(_command);
232
+ const command = ['0xdd', '0xa4', ..._command, ...checks, '0x77'];
233
+
234
+ return this.getData(
235
+ deviceId,
236
+ {
237
+ command,
238
+ commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0x21, pkgLen: hexArr[3] + 7 }),
239
+ pkgVerifyHandler: (pkg) => {
240
+ const len = pkg.length;
241
+ const [c1, c2] = generateCrcCheckSum(pkg.slice(2, len - 3));
242
+ const [_c1, _c2] = [pkg[len - 3], pkg[len - 2]];
243
+ return { verified: c1 == _c1 && c2 == _c2 };
244
+ },
245
+ },
246
+ 'DDA421'
247
+ );
248
+ }
249
+ /** 解析充电电池信息21指令
250
+ *
251
+ * @param {number[]} data DDA421十六进制数据数组
252
+ * @returns {Object} 解析后的充电电池信息对象
253
+ */
254
+ export const resolveDDA421 = async (data) => {
255
+ if (!data) return null;
256
+ const dataStr = hexArr2string(data);
257
+ // 电池电压 4BYTE [4,5,6,7]
258
+ const batteryVoltageHex = decimalToHex(data[4]) + decimalToHex(data[5]) + decimalToHex(data[6]) + decimalToHex(data[7]);
259
+ const batteryVoltage = hexToDecimal(batteryVoltageHex); // mV
260
+ // 电池电流 4BYTE [8,9,10,11]
261
+ const batteryCurrentHex = decimalToHex(data[8]) + decimalToHex(data[9]) + decimalToHex(data[10]) + decimalToHex(data[11]);
262
+ const batteryCurrent = hexToDecimal(batteryCurrentHex); // mA
263
+ // 电池类型 1BYTE [12]
264
+ const batteryType = data[12];
265
+ // 电池串数 1BYTE [13]
266
+ const batterySeries = data[13];
267
+ // 电池容量 4BYTE [14,15,16,17]
268
+ const batteryCapacityHex = decimalToHex(data[14]) + decimalToHex(data[15]) + decimalToHex(data[16]) + decimalToHex(data[17]);
269
+ const batteryCapacity = hexToDecimal(batteryCapacityHex); // mAH
270
+ // 电池SOC 1BYTE [18]
271
+ const batterySOC = data[18]; // %
272
+ // 电池温度 2BYTE [19,20]
273
+ const batteryTempHex = decimalToHex(data[19]) + decimalToHex(data[20]);
274
+ const batteryTemperature = hexToDecimal(batteryTempHex) / 10; // 0.1摄氏度
275
+ // const batteryTemperature = [data[19] ?? 0, [data[20] ?? 0]] // 摄氏度,保留一位小数
276
+ // 加热状态 1BYTE [21]
277
+ const heatingStatus = data[21]; // 0未加热 1加热中
278
+ // 加热电流 4BYTE [22,23,24,25]
279
+ const heatingCurrentHex = decimalToHex(data[22]) + decimalToHex(data[23]) + decimalToHex(data[24]) + decimalToHex(data[25]);
280
+ const heatingCurrent = hexToDecimal(heatingCurrentHex); // mA
281
+ // 保护状态 2BYTE [26,27]
282
+ const protectStatusHex = decimalToHex(data[26]) + decimalToHex(data[27]);
283
+ const protectStatus = hexToDecimal(protectStatusHex);
284
+ const protectStatusArr = protectStatus.toString(2).padStart(16, '0').split('').reverse();
285
+ let protectStatusIndexs = [];
286
+ for (let i = 0; i < protectStatusArr.length; i++) {
287
+ if (protectStatusArr[i] == '1') {
288
+ protectStatusIndexs.push(i);
289
+ }
290
+ }
291
+ // 告警状态 2BYTE [28,29]
292
+ const alarmStatusHex = decimalToHex(data[28]) + decimalToHex(data[29]);
293
+ const alarmStatus = hexToDecimal(alarmStatusHex);
294
+ const alarmStatusArr = alarmStatus.toString(2).padStart(16, '0').split('').reverse();
295
+ let alarmStatusIndexs = [];
296
+ for (let i = 0; i < alarmStatusArr.length; i++) {
297
+ if (alarmStatusArr[i] == '1') {
298
+ alarmStatusIndexs.push(i);
299
+ }
300
+ }
301
+ return {
302
+ dataStr,
303
+ batteryVoltage,
304
+ batteryCurrent,
305
+ batteryType,
306
+ batterySeries,
307
+ batteryCapacity,
308
+ batterySOC,
309
+ batteryTemperature,
310
+ heatingStatus,
311
+ heatingCurrent,
312
+ protectStatusIndexs,
313
+ alarmStatusIndexs
314
+ };
315
+ }
316
+ /**充电器激活电池
317
+ * type:
318
+ * 0x00 - 取消激活
319
+ * 0x01 - 激活
320
+ */
321
+ export const getDDA425Async = async (deviceId, type) => {
322
+ const _command = ['0x25', '0x01', type];
323
+ const checks = generateCrcCheckSum(_command);
324
+ const command = ['0xDD', '0xA4', ..._command, ...checks, '0x77'];
325
+ console.log('command: ', command);
326
+ return getData(
327
+ deviceId,
328
+ {
329
+ command,
330
+ commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0x25, pkgLen: hexArr[3] + 7 }),
331
+ pkgVerifyHandler: (pkg) => {
332
+ return { verified: true };
333
+ },
334
+ },
335
+ 'DDA425'
336
+ );
337
+ }
338
+ export const resolveDDA425 = async (data) => {
339
+ if (!data) return null;
340
+ const dataStr = hexArr2string(data);
341
+ return {
342
+ dataStr,
343
+ status: hex2string(data[2])
344
+ };
345
+ }
346
+ /** 查询充电器参数22指令
347
+ * @param {*} deviceId
348
+ * @param {number} startReg 寄存器起始地址(2字节,十进制或十六进制均可)
349
+ * @param {number} endReg 寄存器结束地址(2字节,十进制或十六进制均可)
350
+ * @returns
351
+ */
352
+ export const getDDA422Async = async (deviceId, startReg, endReg) => {
353
+ // 转为2字节十六进制字符串
354
+ const startRegHex = decimalToHex(startReg, 4);
355
+ const endRegHex = decimalToHex(endReg, 4);
356
+ // 拆分为高低字节
357
+ const startRegArr = [
358
+ parseInt(startRegHex.slice(0, 2), 16),
359
+ parseInt(startRegHex.slice(2, 4), 16)
360
+ ];
361
+ const endRegArr = [
362
+ parseInt(endRegHex.slice(0, 2), 16),
363
+ parseInt(endRegHex.slice(2, 4), 16)
364
+ ];
365
+ const _command = ['0x22', '0x04', ...startRegArr, ...endRegArr];
366
+ const checks = generateCrcCheckSum(_command);
367
+ const command = ['0xDD', '0xA4', ..._command, ...checks, '0x77'];
368
+ return getData(
369
+ deviceId,
370
+ {
371
+ command,
372
+ commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0x22, pkgLen: hexArr[3] + 7 }),
373
+ pkgVerifyHandler: (pkg) => {
374
+ const len = pkg.length;
375
+ const [c1, c2] = generateCrcCheckSum(pkg.slice(2, len - 3));
376
+ const [_c1, _c2] = [pkg[len - 3], pkg[len - 2]];
377
+ return { verified: c1 == _c1 && c2 == _c2 };
378
+ },
379
+ },
380
+ 'DDA422'
381
+ );
382
+ }
383
+ /** 解析充电器参数22指令响应
384
+ * @param {number[]} data DDA422响应数据
385
+ * @returns {Object} 解析结果
386
+ */
387
+ export const resolveDDA422 = async (data) => {
388
+ if (!data) return null;
389
+ const dataStr = hexArr2string(data);
390
+ // 起始地址 2BYTE [4,5]
391
+ const startRegHex = decimalToHex(data[4]) + decimalToHex(data[5]);
392
+ const startReg = hexToDecimal(startRegHex);
393
+ // 结束地址 2BYTE [6,7]
394
+ const endRegHex = decimalToHex(data[6]) + decimalToHex(data[7]);
395
+ const endReg = hexToDecimal(endRegHex);
396
+ // 寄存器数据 [8, ...]
397
+ const regData = data.slice(8, data.length - 3); // 去掉校验和和停止位
398
+ return {
399
+ dataStr,
400
+ startReg,
401
+ endReg,
402
+ regData
403
+ };
404
+ }
405
+ /**
406
+ * 设置充电器参数23指令
407
+ */
408
+ 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);
431
+
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 };
445
+ },
446
+ },
447
+ 'DDA423'
448
+ );
449
+ }
450
+ export const resolveDDA423 = async (data) => {
451
+ if (!data) return null;
452
+ const dataStr = hexArr2string(data);
453
+ return {
454
+ dataStr,
455
+ status: hex2string(data[2])
456
+ };
457
+ }
458
+ /** 查询充电历史数据27指令
459
+ * @param {*} deviceId
460
+ * @param {number} startTime 充电起始时间(秒,4字节)
461
+ * @param {number} endTime 充电结束时间(秒,4字节)
462
+ * @param {number} granularity 数据颗粒度(1:一分钟,2:五分钟)
463
+ * @returns
464
+ */
465
+ export const getDDA427Async = async (deviceId, startTime, endTime, granularity = 2, type = 1) => {
466
+ // 4字节起始时间 - 将十进制时间直接转换为4字节的十六进制数组
467
+ // 首先将十进制数转为十六进制字符串,然后拆分成4个字节
468
+ const startTimeHex = startTime.toString(16).padStart(8, '0');
469
+ const endTimeHex = endTime.toString(16).padStart(8, '0');
470
+
471
+ // 拆分为4字节,并转换为十六进制数值
472
+ const startTimeArr = [
473
+ parseInt(startTimeHex.slice(0, 2), 16),
474
+ parseInt(startTimeHex.slice(2, 4), 16),
475
+ parseInt(startTimeHex.slice(4, 6), 16),
476
+ parseInt(startTimeHex.slice(6, 8), 16)
477
+ ];
478
+ const endTimeArr = [
479
+ parseInt(endTimeHex.slice(0, 2), 16),
480
+ parseInt(endTimeHex.slice(2, 4), 16),
481
+ parseInt(endTimeHex.slice(4, 6), 16),
482
+ parseInt(endTimeHex.slice(6, 8), 16)
483
+ ];
484
+ // 历史数据类型
485
+ const historyType = decimalToHex(type, 2); // 0x00:充电历史数据
486
+ // 数据颗粒度1字节
487
+ const granularityArr = decimalToHex(granularity, 2);
488
+ const _command = ['0x27', '0x0A', ...startTimeArr, ...endTimeArr, historyType, granularityArr];
489
+ const checks = generateCrcCheckSum(_command);
490
+ const command = ['0xDD', '0xA4', ..._command, ...checks, '0x77'];
491
+ console.log('getDDA427Async getDDA427Async', startTimeHex, endTimeHex, startTimeArr, endTimeArr, granularity, command);
492
+ return getData(
493
+ deviceId,
494
+ {
495
+ command,
496
+ commandVerifyHandler: (hexArr) => ({ verified: hexArr[0] == 0xdd && hexArr[1] == 0x27, pkgLen: hexArr[3] + 7 }),
497
+ pkgVerifyHandler: (pkg) => {
498
+ const len = pkg.length;
499
+ const [c1, c2] = generateCrcCheckSum(pkg.slice(2, len - 3));
500
+ const [_c1, _c2] = [pkg[len - 3], pkg[len - 2]];
501
+ return { verified: c1 == _c1 && c2 == _c2 };
502
+ },
503
+ },
504
+ 'DDA427',
505
+ 3000
506
+ );
507
+ }
508
+ /** 解析充电历史数据27指令响应
509
+ * @param {number[]} data DDA427响应数据
510
+ * @returns {Object} 解析结果
511
+ */
512
+ export const resolveDDA427 = async (data) => {
513
+ if (!data) return null;
514
+ const dataStr = hexArr2string(data);
515
+ // 充电起始时间 4BYTE [4,5,6,7]
516
+ const startTimeHex = decimalToHex(data[4]) + decimalToHex(data[5]) + decimalToHex(data[6]) + decimalToHex(data[7]);
517
+ const startTime = hexToDecimal(startTimeHex);
518
+ // 充电结束时间 4BYTE [8,9,10,11]
519
+ const endTimeHex = decimalToHex(data[8]) + decimalToHex(data[9]) + decimalToHex(data[10]) + decimalToHex(data[11]);
520
+ const endTime = hexToDecimal(endTimeHex);
521
+ // 历史数据类型 1BYTE [12]
522
+ const historyType = data[12]; // 0x00:充电历史数据
523
+ // 数据颗粒度 1BYTE [13]
524
+ const granularity = data[13];
525
+ // 实际数量N 1BYTE [14]
526
+ const count = data[14];
527
+ // 历史数据 [15, ...] 每条8BYTE
528
+ let history = [];
529
+ for (let i = 0; i < count; i++) {
530
+ const base = 15 + i * 8;
531
+ // 充电电压 4BYTE
532
+ const voltageHex = decimalToHex(data[base]) + decimalToHex(data[base+1]) + decimalToHex(data[base+2]) + decimalToHex(data[base+3]);
533
+ const voltage = hexToDecimal(voltageHex);
534
+ // 充电电流 4BYTE
535
+ const currentHex = decimalToHex(data[base+4]) + decimalToHex(data[base+5]) + decimalToHex(data[base+6]) + decimalToHex(data[base+7]);
536
+ const current = hexToDecimal(currentHex);
537
+ history.push({ current, voltage });
538
+ }
539
+ console.log('historyType', historyType)
540
+ return {
541
+ dataStr,
542
+ startTime,
543
+ endTime,
544
+ historyType,
545
+ granularity,
546
+ count,
547
+ history
548
+ };
549
+ }
550
+ /** 充电器测试指令
551
+ *
552
+ * @param {*} deviceId
553
+ * @returns
554
+ */
555
+ export const getDDA429Async = async (deviceId, id) => {
556
+ // id、是四个bites
557
+ const idHex = decimalToHex(id, 8);
558
+ // 拆分为4字节
559
+ const idArr = [
560
+ parseInt(idHex.slice(0, 2), 16),
561
+ parseInt(idHex.slice(2, 4), 16),
562
+ parseInt(idHex.slice(4, 6), 16),
563
+ parseInt(idHex.slice(4, 6), 16),
564
+ parseInt(idHex.slice(6, 8), 16)
565
+ ];
566
+ const _command = ['0x29', '0x04', ...idArr];
567
+ const checks = generateCrcCheckSum(_command);
568
+ const command = ['0xdd', '0xa4', ..._command, ...checks, '0x77'];
569
+
570
+
571
+ return getData(
572
+ deviceId,
573
+ {
574
+ command,
575
+ commandVerifyHandler: (hexArr) => {
576
+ // 基本头部验证
577
+ if (hexArr[0] != 0xdd || hexArr[1] != 0x29) return { verified: false, pkgLen: null };
578
+
579
+ // 验证数据包长度是否合理
580
+ if (hexArr.length < 8) return { verified: false, pkgLen: null };
581
+
582
+ // 根据resolveDDA429的解析结构,ID在响应偏移32位置
583
+ // 实际协议中可能有所不同,需要根据协议规范调整
584
+ if (hexArr.length >= 36) {
585
+ // 从resolveDDA429可知,ID位于n=32处的4个字节
586
+ const respIdHex = decimalToHex(hexArr[32]) +
587
+ decimalToHex(hexArr[33]) +
588
+ decimalToHex(hexArr[34]) +
589
+ decimalToHex(hexArr[35]);
590
+ const respId = hexToDecimal(respIdHex);
591
+
592
+ // 如果ID不匹配,则拒绝该数据包
593
+ if (respId !== id) return { verified: false, pkgLen: null };
594
+ }
595
+
596
+ return { verified: true, pkgLen: hexArr[3] + 7 };
597
+ },
598
+ pkgVerifyHandler: (pkg) => {
599
+ const len = pkg.length;
600
+ const [c1, c2] = generateCrcCheckSum(pkg.slice(2, len - 3));
601
+ const [_c1, _c2] = [pkg[len - 3], pkg[len - 2]];
602
+ return { verified: c1 == _c1 && c2 == _c2 };
603
+ },
604
+ },
605
+ 'DDA429'
606
+ );
607
+ }
608
+ export const resolveDDA429 = async (data) => {
609
+ if (!data) return null;
610
+ const dataStr = hexArr2string(data);
611
+ let n = 4; // 起始偏移
612
+
613
+ // 1. 工作状态
614
+ const workStatus = data[n++];
615
+
616
+ // 2. 充电状态
617
+ const chargeStatus = data[n++];
618
+
619
+ // 3. 充电电压(4字节)
620
+ const chargeVoltage = hexToDecimal(
621
+ decimalToHex(data[n++]) +
622
+ decimalToHex(data[n++]) +
623
+ decimalToHex(data[n++]) +
624
+ decimalToHex(data[n++])
625
+ );
626
+
627
+ // 4. 充电电流(4字节)
628
+ const chargeElectricity = hexToDecimal(
629
+ decimalToHex(data[n++]) +
630
+ decimalToHex(data[n++]) +
631
+ decimalToHex(data[n++]) +
632
+ decimalToHex(data[n++])
633
+ );
634
+
635
+ // 5. 充电功率(2字节)
636
+ const chargePower = hexToDecimal(
637
+ decimalToHex(data[n++]) +
638
+ decimalToHex(data[n++])
639
+ );
640
+
641
+ // 6. 充电器温度(2字节)
642
+ const chargeTemperature = hexToDecimal(
643
+ decimalToHex(data[n++]) +
644
+ decimalToHex(data[n++])
645
+ ) / 10;
646
+
647
+ // 7. 已充电量(4字节)
648
+ const chargeCapacity = hexToDecimal(
649
+ decimalToHex(data[n++]) +
650
+ decimalToHex(data[n++]) +
651
+ decimalToHex(data[n++]) +
652
+ decimalToHex(data[n++])
653
+ );
654
+
655
+ // 8. 充电时长(2字节)
656
+ const chargeTime = hexToDecimal(
657
+ decimalToHex(data[n++]) +
658
+ decimalToHex(data[n++])
659
+ );
660
+
661
+ // 9. 充电剩余时间(2字节)
662
+ const chargeRemainTime = hexToDecimal(
663
+ decimalToHex(data[n++]) +
664
+ decimalToHex(data[n++])
665
+ );
666
+
667
+ // 10. 充电完成时长(2字节)
668
+ const chargeCompleteTime = hexToDecimal(
669
+ decimalToHex(data[n++]) +
670
+ decimalToHex(data[n++])
671
+ );
672
+
673
+ // 输出电压占空比
674
+ const outputVoltagePercent = data[n++];
675
+
676
+ // 输出电流占空比
677
+ const outputElectricityPercent = data[n++];
678
+
679
+ // id(4字节)
680
+ const id1 = hexToDecimal(
681
+ decimalToHex(data[n++]) +
682
+ decimalToHex(data[n++]) +
683
+ decimalToHex(data[n++]) +
684
+ decimalToHex(data[n++])
685
+ );
686
+
687
+ // 检测输出电流(4字节)
688
+ const outputElectricity = hexToDecimal(
689
+ decimalToHex(data[n++]) +
690
+ decimalToHex(data[n++]) +
691
+ decimalToHex(data[n++]) +
692
+ decimalToHex(data[n++])
693
+ );
694
+
695
+ // 检测电池电压(4字节)
696
+ const id = hexToDecimal(
697
+ decimalToHex(data[n++]) +
698
+ decimalToHex(data[n++]) +
699
+ decimalToHex(data[n++]) +
700
+ decimalToHex(data[n++])
701
+ );
702
+
703
+ // 开关状态(2字节)
704
+ const switchStatus = hexToDecimal(
705
+ decimalToHex(data[n++]) +
706
+ decimalToHex(data[n++])
707
+ );
708
+ const swtichStatusArr = switchStatus.toString(2).padStart(16, '0').split('').reverse();
709
+ const chargeSwitch = swtichStatusArr[0] == '1';
710
+ const preChargeSwitch = swtichStatusArr[1] == '1';
711
+ const fanSwitch = swtichStatusArr[2] == '1';
712
+
713
+ // 保护状态(4字节)
714
+ const protectStatus = hexToDecimal(
715
+ decimalToHex(data[n++]) +
716
+ decimalToHex(data[n++]) +
717
+ decimalToHex(data[n++]) +
718
+ decimalToHex(data[n++])
719
+ );
720
+ const protectStatusArr = protectStatus.toString(2).padStart(32, '0').split('').reverse();
721
+ let protectStatusIndexs = [];
722
+ for (let i = 0; i < protectStatusArr.length; i++) {
723
+ if (protectStatusArr[i] == '1') protectStatusIndexs.push(i);
724
+ }
725
+
726
+ // 告警状态(4字节)
727
+ const alarmStatus = hexToDecimal(
728
+ decimalToHex(data[n++]) +
729
+ decimalToHex(data[n++]) +
730
+ decimalToHex(data[n++]) +
731
+ decimalToHex(data[n++])
732
+ );
733
+ const alarmStatusArr = alarmStatus.toString(2).padStart(32, '0').split('').reverse();
734
+ let alarmStatusIndexs = [];
735
+ for (let i = 0; i < alarmStatusArr.length; i++) {
736
+ if (alarmStatusArr[i] == '1') alarmStatusIndexs.push(i);
737
+ }
738
+
739
+ return {
740
+ dataStr,
741
+ workStatus,
742
+ chargeStatus,
743
+ chargeVoltage,
744
+ chargeElectricity,
745
+ chargePower,
746
+ chargeTemperature,
747
+ chargeCapacity,
748
+ chargeTime,
749
+ chargeRemainTime,
750
+ chargeCompleteTime,
751
+ outputVoltagePercent,
752
+ outputElectricityPercent,
753
+ id,
754
+ outputElectricity,
755
+ id1,
756
+ chargeSwitch,
757
+ preChargeSwitch,
758
+ fanSwitch,
759
+ protectStatusIndexs,
760
+ alarmStatusIndexs,
761
+ };
762
762
  }