mini_program_gizwits_sdk 3.0.2-beta → 3.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.
Files changed (53) hide show
  1. package/dist/index.js +3 -20
  2. package/dist/src/errorCode.d.ts +5 -0
  3. package/dist/src/globalData.d.ts +2 -0
  4. package/dist/src/openApiRequest.d.ts +9 -0
  5. package/dist/src/productConfigFileManage.d.ts +12 -0
  6. package/dist/src/protocol/Bind.d.ts +7 -0
  7. package/dist/src/protocol/DataPoint.d.ts +52 -0
  8. package/dist/src/protocol/GetDeviceStatus.d.ts +5 -0
  9. package/dist/src/protocol/Login.d.ts +12 -0
  10. package/dist/src/protocol/ProtocolBase.d.ts +11 -0
  11. package/dist/src/protocol/WifiConfig.d.ts +6 -0
  12. package/dist/src/protocol/tool.d.ts +9 -0
  13. package/dist/src/randomCode.d.ts +7 -0
  14. package/dist/src/request.d.ts +1 -0
  15. package/dist/src/services/devices.d.ts +53 -0
  16. package/dist/src/services/login.d.ts +8 -0
  17. package/dist/src/services/tool.d.ts +4 -0
  18. package/dist/src/sleep.d.ts +2 -0
  19. package/dist/src/socket.d.ts +107 -0
  20. package/dist/src/utils.d.ts +29 -0
  21. package/dist/src/wechatApi.d.ts +33 -0
  22. package/dist/src/wifiConfig/ConfigBase.d.ts +26 -0
  23. package/dist/src/wifiConfig/ap.d.ts +21 -0
  24. package/dist/src/wifiConfig/ble.d.ts +40 -0
  25. package/global.d.ts +28 -0
  26. package/index.ts +7 -0
  27. package/package.json +6 -3
  28. package/src/ble.ts +566 -0
  29. package/src/errorCode.ts +60 -0
  30. package/src/global.d.ts +42 -0
  31. package/src/globalData.ts +9 -0
  32. package/src/openApiRequest.ts +103 -0
  33. package/src/productConfigFileManage.ts +44 -0
  34. package/src/protocol/Bind.ts +22 -0
  35. package/src/protocol/GetDeviceStatus.ts +61 -0
  36. package/src/protocol/Login.ts +43 -0
  37. package/src/protocol/ProtocolBase.ts +53 -0
  38. package/src/protocol/WifiConfig.ts +41 -0
  39. package/src/protocol/dataPoint.ts +663 -0
  40. package/src/protocol/tool.ts +91 -0
  41. package/src/randomCode.ts +36 -0
  42. package/src/request.ts +22 -0
  43. package/src/sdk.ts +811 -0
  44. package/src/services/devices.ts +210 -0
  45. package/src/services/login.ts +15 -0
  46. package/src/services/tool.ts +10 -0
  47. package/src/sleep.ts +2 -0
  48. package/src/socket.ts +449 -0
  49. package/src/utils.ts +215 -0
  50. package/src/wechatApi.ts +179 -0
  51. package/src/wifiConfig/ConfigBase.ts +183 -0
  52. package/src/wifiConfig/ap.ts +193 -0
  53. package/src/wifiConfig/ble.ts +417 -0
@@ -0,0 +1,663 @@
1
+ import productConfigFileManage from "../productConfigFileManage";
2
+ import { arrayToString, checkHeader, fillString, getProtocolLen } from "./tool";
3
+
4
+ export interface IDataPointConfig {
5
+ name: string;
6
+ protocolType: 'var_len' | 'standard';
7
+ entities: IDataPointEntitie[];
8
+ }
9
+
10
+
11
+
12
+ interface IDataPointEntitie {
13
+ display_name: string;
14
+ attrs: IDataPointAttr[];
15
+ }
16
+
17
+ interface IDataPointPosition {
18
+ byte_offset: number;
19
+ unit: 'bit' | 'byte';
20
+ len: number;
21
+ bit_offset: number;
22
+ }
23
+
24
+ type TDataType = 'bool' | 'uint8' | 'uint16' | 'uint32' | 'binary' | 'enum' | 'number';
25
+
26
+
27
+ interface IUnitSpec {
28
+ addition: number;
29
+ max: number;
30
+ ratio: number;
31
+ min: number;
32
+ }
33
+
34
+ type TDataOptionType = 'status_writable' | 'status_readonly' | 'alert' | 'fault' | 'ALL';
35
+ export interface IDataPointAttr {
36
+ display_name: string;
37
+ uint_spec: IUnitSpec;
38
+ name:string;
39
+ data_type: TDataType;
40
+ position: IDataPointPosition;
41
+ type: TDataOptionType;
42
+ id: number;
43
+ enum: string[];
44
+ desc: string;
45
+ }
46
+
47
+ // 从协议计算一个区块的数据
48
+ const completeBlock = (cmd: string) => {
49
+ // 补0到8的倍数
50
+ const newCmd = fillString(cmd, Math.ceil(cmd.length / 8) * 8);
51
+ const data: number[] = [];
52
+ for (let i = 0; i < newCmd.length; i += 8) {
53
+ data.push(parseInt(newCmd.substring(i, i + 8), 2));
54
+ }
55
+ return data;
56
+ };
57
+ const fixType = (type: TDataType) => {
58
+ return type.indexOf('uint') !== -1 ? 'number' : type;
59
+ };
60
+
61
+ // 从数据点转换到二进制
62
+ const getData = (type: TDataType, data: any, item: IDataPointAttr) => {
63
+ let cmd = '';
64
+ switch (type) {
65
+ case 'bool': {
66
+ const value = data[item.name] === true ? 1 : 0;
67
+ cmd = `${value}`;
68
+ break;
69
+ }
70
+ case 'enum': {
71
+ const index = item.enum.findIndex(itemEnum => data[item.name] === itemEnum);
72
+ const value = index === -1 ? 0 : index;
73
+ cmd = fillString(value.toString(2), item.position.len);
74
+ break;
75
+ }
76
+ case 'number': {
77
+ // 加上增量
78
+ let value = 0;
79
+ if (data[item.name] != undefined) {
80
+ value = Math.round(((data[item.name]) - item.uint_spec.addition) / item.uint_spec.ratio);
81
+ }
82
+ // 还有偏移
83
+ cmd = fillString(value.toString(2), item.position.len * 8);
84
+ break;
85
+ }
86
+ case 'binary': {
87
+ const value = data[item.name] || '';
88
+ // 数量不够在后面补0
89
+ const newValue = fillString(value, item.position.len * 2, true);
90
+ for (let i = 0; i < newValue.length / 2; i++) {
91
+ const newI = i * 2;
92
+ const string = newValue[newI] + newValue[newI + 1];
93
+ cmd += fillString(parseInt(string, 16).toString(2), 8);
94
+ }
95
+ break;
96
+ }
97
+ default: {
98
+ break;
99
+ }
100
+ }
101
+ // 补全长度
102
+ const length = item.position.len * (item.position.unit === 'byte' ? 8 : 1);
103
+ const offset = length - cmd.length;
104
+ if (offset > 0) {
105
+ for (let i = 0; i < offset; i++) {
106
+ cmd = `0${cmd}`;
107
+ }
108
+ }
109
+ return `${cmd}`;
110
+ };
111
+
112
+ // 从p0转换到数据点
113
+ const getPData = (type: TDataType, valueString: string, item: IDataPointAttr) => {
114
+ switch (type) {
115
+ case 'bool': {
116
+ return valueString === '1';
117
+ }
118
+ case 'enum': {
119
+ const enumIndex = parseInt(valueString, 2);
120
+ return enumIndex;
121
+ }
122
+ case 'binary': {
123
+ // 补全长度
124
+ const length = item.position.len;
125
+ // 8个来解
126
+ let newValue = '';
127
+ for (let i = 0; i < valueString.length / 8; i++) {
128
+ const realI = i * 8;
129
+ const string = valueString.substring(realI, realI + 8);
130
+ newValue += fillString(parseInt(string, 2).toString(16), 2);
131
+ }
132
+ return fillString(newValue, length * 2, true);
133
+ }
134
+ case 'number': {
135
+ // 增量
136
+ // 还有偏移
137
+ // 浮点运算问题,先换成整数
138
+ return (parseInt(valueString, 2) / (1 / item.uint_spec.ratio) + item.uint_spec.addition);
139
+ }
140
+ default: {
141
+ return '';
142
+ }
143
+ }
144
+ };
145
+
146
+
147
+ interface IDataPointToP0Params {
148
+ config: IDataPointAttr[];
149
+ data: any;
150
+ isAdaptiveDatapoint: boolean;
151
+ }
152
+ /**
153
+ * json转 p0
154
+ * @param {*} config
155
+ * @param {*} data
156
+ * @param {boolean} isAdaptiveDatapoint // 定长 或着 变长
157
+ */
158
+ const DataPointToP = ({ config, data, isAdaptiveDatapoint }: IDataPointToP0Params) => {
159
+ const handleBoolEnum = (item, boolEnumString) => {
160
+ const type = fixType(item.data_type);
161
+ const cmdString = getData(type, data, item);
162
+ boolEnumString = cmdString + boolEnumString;
163
+ return boolEnumString;
164
+ };
165
+ const handleOther = (item, cmd) => {
166
+ const type = fixType(item.data_type);
167
+ const cmdString = getData(type, data, item);
168
+ cmd = cmd.concat(completeBlock(cmdString));
169
+ return cmd;
170
+ };
171
+
172
+ let attrsConfig = config;
173
+
174
+ /**
175
+ * 包头
176
+ */
177
+ const header = [0, 0, 0, 3];
178
+
179
+ /**
180
+ * 固定包头的headerCmd 和 flag
181
+ */
182
+ const flag = [0];
183
+ const headerCmd = [0, 147]; // cmd
184
+ const sn = [0,0,0,0];
185
+
186
+ // 业务指令命令字 定长上报是4,变长上报是14
187
+ let cmd = [0x1];
188
+
189
+ let flagString = '';
190
+ // 根据传入的数据算出flag
191
+
192
+ // 记录有效的数据点
193
+ const activeAttrs: IDataPointAttr[] = [];
194
+
195
+ // 找到可写
196
+ if (!isAdaptiveDatapoint) {
197
+ attrsConfig = attrsConfig.filter(item => item.type ==='status_writable')
198
+ }
199
+
200
+ attrsConfig.map((item) => {
201
+ if (data[item.name] !== undefined) {
202
+ flagString = `1${flagString}`;
203
+ activeAttrs.push(item);
204
+ } else {
205
+ flagString = `0${flagString}`;
206
+ }
207
+ });
208
+
209
+ if (isAdaptiveDatapoint) {
210
+ cmd = [0x11];
211
+ attrsConfig = activeAttrs;
212
+ }
213
+ // 补全
214
+ flagString = fillString(flagString, Math.ceil(flagString.length / 8) * 8);
215
+ for (let i = 0; i < (flagString.length / 8); i++) {
216
+ cmd.push(parseInt(flagString.substring(i * 8, (i + 1) * 8), 2));
217
+ }
218
+
219
+ let boolEnumString = '';
220
+ let preItem: IDataPointAttr;
221
+ try {
222
+ preItem = attrsConfig[0];
223
+ } catch (error) {
224
+ //
225
+ }
226
+
227
+ attrsConfig.map((item) => {
228
+ if (item.data_type === 'bool' || item.data_type === 'enum') {
229
+ // 只读、可写、alert、fault的字节都要分开
230
+ if (preItem.type !== item.type) {
231
+ // 先合并一次数据,再重新计算当前的bool和枚举
232
+ cmd = cmd.concat(completeBlock(boolEnumString));
233
+ boolEnumString = '';
234
+ }
235
+
236
+ boolEnumString = handleBoolEnum(item, boolEnumString);
237
+ } else {
238
+ if (boolEnumString.length > 0) {
239
+ cmd = cmd.concat(completeBlock(boolEnumString));
240
+ boolEnumString = '';
241
+ }
242
+ cmd = handleOther(item, cmd);
243
+ }
244
+
245
+ preItem = item;
246
+ });
247
+
248
+ if (boolEnumString.length > 0) {
249
+ cmd = cmd.concat(completeBlock(boolEnumString));
250
+ boolEnumString = '';
251
+ }
252
+
253
+ const flagToCmd = flag.concat(headerCmd).concat(sn).concat(cmd);
254
+ const flagToCmdLength = flagToCmd.length.toString(2);
255
+
256
+ /**
257
+ * 2进制 如果后面还有数据,最高位为1,没有数据的时候最高位为0
258
+ * 先把10进制转2进制,然后从右边开始
259
+ * 取7位,如果还有数据,flag为1 没有则0
260
+ * 以此类推
261
+ */
262
+
263
+ const lengthArr: number[] = [];
264
+ for (let i = flagToCmdLength.length; i > 0; i -= 7) {
265
+ const start = i - 7;
266
+ const end = i;
267
+ let lengthValue = flagToCmdLength.substring(start, end);
268
+ lengthValue = `${start > 0 ? '1' : '0'}${lengthValue}`;
269
+ lengthArr.push(parseInt(lengthValue, 2));
270
+ }
271
+
272
+ header.push(...lengthArr);
273
+ const packageData = header.concat(flagToCmd);
274
+ return packageData;
275
+ };
276
+
277
+ /**
278
+ * p0 转json
279
+ * @param {*} config
280
+ * @param {*} data
281
+ * 设备到app
282
+ * header len flag cmd sn action data
283
+ * action 0x04定长上报 0x05定长下发 0x11变长下发 0x14变长上报 0x12变长下发读数据点 0x02定长读数据点
284
+ */
285
+
286
+ interface IPToDataPointParams {
287
+ config: IDataPointAttr[];
288
+ data: number[];
289
+ }
290
+ interface IRawData {
291
+ header: string;
292
+ len: string;
293
+ flag: string;
294
+ cmd: string;
295
+ sn: string;
296
+ action: string;
297
+ payload: string;
298
+ }
299
+
300
+ type messageType = 'APP2DEV' | 'DEV2APP' | 'UNKNOW';
301
+
302
+ function PToDataPoint({ config = [], data }: IPToDataPointParams) {
303
+ let action: number;
304
+ let message = '';
305
+ let messageType: messageType;
306
+ const rawData: IRawData = { header: arrayToString(data.slice(0, 4)), flag: '', len: '', cmd: '', sn: '',action: '', payload: '' };
307
+
308
+ // 获取数据长度 0,0,0,3 到 0 这一段都是长度 校验长度可以忽略
309
+ const attrs = config;
310
+
311
+ let pointer = checkHeader(data);
312
+ // 先识别固定包头
313
+ if (pointer === false) {
314
+ // 数据不合法
315
+ return;
316
+ }
317
+
318
+ /**
319
+ * 插入len
320
+ * 计算方法,从第一位开始往下算,直到找到一个字节的最高位不为1
321
+ */
322
+ const nextData = data.slice(pointer, data.length);
323
+
324
+ const lengthIndex = getProtocolLen(nextData);
325
+ pointer += lengthIndex;
326
+
327
+ rawData.len = arrayToString(nextData.slice(0, lengthIndex));
328
+
329
+ // 跳过flag
330
+ pointer += 1;
331
+
332
+ rawData.flag = arrayToString(data.slice(pointer - 1, pointer));
333
+
334
+ // 跳过命令字
335
+ pointer += 2;
336
+ rawData.cmd = arrayToString(data.slice(pointer - 2, pointer));
337
+
338
+ rawData.sn = '';
339
+ // cmd 是93 的带sn
340
+ if (rawData.cmd === '0093' || rawData.cmd === '0094') {
341
+ rawData.sn = arrayToString(data.slice(pointer, pointer + 4));
342
+ // 跳过sn
343
+ pointer += 4;
344
+ }
345
+
346
+ rawData.action = arrayToString(data.slice(pointer, pointer + 1));
347
+
348
+ action = data[pointer];
349
+
350
+ // 跳过action
351
+ pointer += 1;
352
+
353
+ rawData.payload = arrayToString(data.slice(pointer, data.length));
354
+
355
+ // 开始处理数据
356
+ const businessData = data.slice(pointer, data.length);
357
+
358
+ let activeAttrs = attrs;
359
+
360
+ /**
361
+ * 定长下发时是可写数据点 上报是所有
362
+ */
363
+ if (action === 0x01) {
364
+ activeAttrs = attrs.filter(item => item.type === 'status_writable');
365
+ }
366
+
367
+ const flagAttrs = JSON.parse(JSON.stringify(activeAttrs));
368
+ const flagLen = Math.ceil(activeAttrs.length / 8);
369
+ let flag = businessData.slice(0, flagLen);
370
+ let cmdData = businessData.slice(flagLen, businessData.length);
371
+
372
+ // 设备定长上报才需要填充这段数据处理 这样就可以和变长统一行为,都有flag位
373
+ if (action === 0x03 || action === 0x04) {
374
+ flag = new Array(flagLen).fill(255);
375
+ cmdData = businessData;
376
+ }
377
+ // flag 转换成2进制,开始读取数据
378
+ let flagString = '';
379
+ flag.map((item) => {
380
+ flagString += fillString(item.toString(2), 8);
381
+ return null;
382
+ });
383
+
384
+ // 临时保存 如果是变长 需要过滤有效数据点
385
+ if (action >= 0x11 && action <= 0x14) {
386
+ activeAttrs = activeAttrs.filter((_item, index) => {
387
+ const flagLenTmp = (flagString.length - 1) - index;
388
+ return flagString[flagLenTmp] === '1';
389
+ });
390
+ }
391
+
392
+ // 写入默认值
393
+ if (rawData.cmd === '0090' || rawData.cmd === '0093') {
394
+ message = 'App 透传数据到 Dev';
395
+ messageType = 'APP2DEV';
396
+ } else if (rawData.cmd === '0091' || rawData.cmd === '0094') {
397
+ // 特殊处理 上报如果数据是空 就是应答
398
+ message = 'Dev 收到控制命令后应答到 App';
399
+ messageType = 'DEV2APP';
400
+ } else {
401
+ message = '非法数据';
402
+ messageType = 'UNKNOW';
403
+ }
404
+
405
+
406
+ let cmd = {};
407
+
408
+ /**
409
+ * 定长分三段计算
410
+ * 可读写
411
+ * 只读
412
+ * 故障
413
+ *
414
+ * 变长直接计算
415
+ */
416
+ switch (action) {
417
+ case 0x01: {
418
+ message = 'App 下发数据到 Dev';
419
+ cmd = getCmd({ attrs: flagAttrs, activeAttrs, flagString: flagString.split('').reverse().join(''), cmdData, accumulate: true });
420
+ break;
421
+ }
422
+ case 0x02: {
423
+ message = 'App 下发查询指令到 Dev';
424
+ // 直接返回
425
+ return { kvData: null, rawData, message, messageType };
426
+ }
427
+ case 0x03: {
428
+ message = 'Dev 回复查询指令到 App';
429
+ cmd = getCmd({ attrs: flagAttrs, activeAttrs, flagString: flagString.split('').reverse().join(''), cmdData, accumulate: true });
430
+ break;
431
+ }
432
+ case 0x04: {
433
+ message = 'Dev 上报状态到 App';
434
+ cmd = getCmd({ attrs: flagAttrs, activeAttrs, flagString: flagString.split('').reverse().join(''), cmdData, accumulate: true });
435
+ break;
436
+ }
437
+ case 0x05: {
438
+ message = 'App 透传数据到 Dev';
439
+ return { kvData: null, rawData, message, messageType };
440
+ }
441
+ case 0x06: {
442
+ message = 'Dev 透传数据到 App';
443
+ return { kvData: null, rawData, message, messageType };
444
+ }
445
+ case 0x07: {
446
+ message = 'App 下发控制子设备';
447
+ return { kvData: null, rawData, message, messageType };
448
+ }
449
+ case 0x08: {
450
+ message = 'App 读取子设备数据';
451
+ return { kvData: null, rawData, message, messageType };
452
+ }
453
+ case 0x09: {
454
+ message = 'Dev 中控回复ACK';
455
+ return { kvData: null, rawData, message, messageType };
456
+ }
457
+ case 0x0a: {
458
+ message = '子设备上报状态到 App';
459
+ return { kvData: null, rawData, message, messageType };
460
+ }
461
+ case 0x0b: {
462
+ message = 'App 下发添加子设备指令';
463
+ return { kvData: null, rawData, message, messageType };
464
+ }
465
+ case 0x0c: {
466
+ message = 'App 下发删除子设备';
467
+ return { kvData: null, rawData, message, messageType };
468
+ }
469
+ case 0x0d: {
470
+ message = 'App 获取中控子设备列表';
471
+ return { kvData: null, rawData, message, messageType };
472
+ }
473
+ case 0x0e: {
474
+ message = '中控响应字设备查询到 App';
475
+ return { kvData: null, rawData, message, messageType };
476
+ }
477
+ case 0x0f: {
478
+ message = '子设备列表变更通知到 App';
479
+ return { kvData: null, rawData, message, messageType };
480
+ }
481
+ case 0x10: {
482
+ message = 'Dev 子设备上下线状态变更通知';
483
+ return { kvData: null, rawData, message, messageType };
484
+ }
485
+ case 0x11: {
486
+ message = 'App 下发变长数据到 Dev';
487
+ cmd = calculationForType({ type: 'ALL', attrs: flagAttrs, activeAttrs, flagString: flagString.split('').reverse().join(''), cmdData }).cmd;
488
+ break;
489
+ }
490
+ case 0x12: {
491
+ message = 'App 下发变长查询到 Dev';
492
+ // 直接返回
493
+ return { kvData: null, rawData, message, messageType };
494
+ }
495
+ case 0x13: {
496
+ message = 'Dev 变长回复查询指令到 App';
497
+ cmd = calculationForType({ type: 'ALL', attrs: flagAttrs, activeAttrs, flagString: flagString.split('').reverse().join(''), cmdData }).cmd;
498
+ break;
499
+ }
500
+ case 0x14: {
501
+ message = 'Dev 变长上报状态到 App';
502
+ cmd = calculationForType({ type: 'ALL', attrs: flagAttrs, activeAttrs, flagString: flagString.split('').reverse().join(''), cmdData }).cmd;
503
+ break;
504
+ }
505
+ case 0x72: {
506
+ message = 'App 向网关发送数据';
507
+ return { kvData: null, rawData, message, messageType };
508
+ }
509
+ case 0x73: {
510
+ message = 'Dev 网关上报数据到 App';
511
+ return { kvData: null, rawData, message, messageType };
512
+ }
513
+ case 0x74: {
514
+ message = 'App 通知网关删除子设备';
515
+ return { kvData: null, rawData, message, messageType };
516
+ }
517
+ default: {
518
+ // 如果都不匹配
519
+ return { kvData: null, rawData, message, messageType };
520
+ }
521
+ }
522
+
523
+ if (attrs.length === 0) {
524
+ // 没有数据点直接返回
525
+ return { kvData: null, rawData, message, messageType };
526
+ }
527
+ return { kvData: cmd, rawData, message, messageType };
528
+ }
529
+
530
+ function isMatchType(type, targetType) {
531
+ return type === targetType || type === 'ALL';
532
+ }
533
+
534
+ function getCmd({ attrs, activeAttrs, flagString, cmdData, accumulate }) {
535
+ const list: TDataOptionType[] = ['status_writable', 'status_readonly', 'alert', 'fault'];
536
+ let cmdDataConsumeLenght = 0;
537
+ let kv = {};
538
+ let flagStart = 0;
539
+ list.map((item) => {
540
+ const flagLength = attrs.filter(attrItem => isMatchType(item, attrItem.type)).length;
541
+ const { cmd, cmdDataLength } = calculationForType({
542
+ type: item,
543
+ attrs: attrs.slice(flagStart, flagStart + flagLength),
544
+ activeAttrs,
545
+ flagString: flagString.substring(flagStart, flagStart + flagLength),
546
+ cmdData: cmdData.slice(cmdDataConsumeLenght, cmdData.length),
547
+ accumulate,
548
+ });
549
+ cmdDataConsumeLenght += cmdDataLength;
550
+ kv = { ...kv, ...cmd };
551
+ flagStart += flagLength;
552
+ return null;
553
+ });
554
+ return kv;
555
+ }
556
+
557
+ /**
558
+ * 根据类型
559
+ * status_writable
560
+ * status_readonly
561
+ * alert fault
562
+ */
563
+ interface ICalculationForTypeParams {
564
+ type: TDataOptionType;
565
+ attrs: IDataPointAttr[];
566
+ activeAttrs: IDataPointAttr[];
567
+ cmdData: number[];
568
+ flagString: string;
569
+ accumulate?: boolean;
570
+ }
571
+ function calculationForType({ type, attrs, activeAttrs, cmdData, flagString, accumulate }: ICalculationForTypeParams) {
572
+ let cmdDataLength = 0;
573
+ let boolEnumLength = 0;
574
+ let otherLength = 0;
575
+ activeAttrs.map((item) => {
576
+ // 合并布尔和枚举的长度
577
+ const isMatch = isMatchType(type, item.type);
578
+ if (isMatch) {
579
+ const bitLength = item.position.len * (item.position.unit === 'bit' ? 1 : 8);
580
+ if (item.data_type === 'bool' || item.data_type === 'enum') {
581
+ boolEnumLength += bitLength;
582
+ } else {
583
+ otherLength += bitLength;
584
+ }
585
+ }
586
+ return null;
587
+ });
588
+ cmdDataLength = Math.ceil(otherLength / 8) + Math.ceil(boolEnumLength / 8);
589
+ const cmd = calculationCmdData({
590
+ attrs,
591
+ flagString,
592
+ boolEnumLength: Math.ceil(boolEnumLength / 8),
593
+ cmdData,
594
+ accumulate,
595
+ });
596
+ return { cmdDataLength, cmd };
597
+ }
598
+
599
+ /**
600
+ * 根据 accumulate 判断是定长还是变成 true 定长
601
+ * 变长的解析顺序不同
602
+ */
603
+ function calculationCmdData({ attrs, flagString, boolEnumLength, cmdData, accumulate }) {
604
+ const cmd = {};
605
+ let bitOffset = 0;
606
+ for (let i = 0; i < flagString.length; i++) {
607
+ if (attrs[i] && flagString[i] === '1') {
608
+ const { data_type, position: { len } } = attrs[i];
609
+ let valueString = '';
610
+ // 有效 如果是布尔或者枚举 需要特别计算
611
+ if (data_type === 'bool' || data_type === 'enum') {
612
+ let boolEnumString = '';
613
+ cmdData.slice(0, boolEnumLength).map((item) => {
614
+ boolEnumString += fillString(item.toString(2), 8);
615
+ return null;
616
+ });
617
+ const end = boolEnumString.length - bitOffset;
618
+ valueString = boolEnumString.substring(end - len, end);
619
+ bitOffset += len;
620
+ } else {
621
+ // 普通的值
622
+ const start = boolEnumLength;
623
+ const end = boolEnumLength + len;
624
+ cmdData.slice(start, end).map((item) => {
625
+ valueString += fillString(item.toString(2), 8);
626
+ return null;
627
+ });
628
+ boolEnumLength += len;
629
+ }
630
+ // 再根据不同的数据格式,进行转换
631
+ const type = fixType(data_type);
632
+ cmd[attrs[i].name] = getPData(type, valueString, attrs[i]);
633
+ } else if (accumulate) {
634
+ // 定长需要累加
635
+ const attr = attrs[i] || { position: { len: 0 } };
636
+ if (attr.position.unit === 'byte') {
637
+ boolEnumLength += attr.position.len;
638
+ } else {
639
+ bitOffset += attr.position.len;
640
+ }
641
+ }
642
+ }
643
+ return cmd;
644
+ }
645
+
646
+
647
+ const unpack = async (data: number[], pk: string) => {
648
+ const productConfig = await productConfigFileManage.getConfigFile(pk);
649
+ if (productConfig) {
650
+ return PToDataPoint({config: (await productConfig).entities[0].attrs, data})
651
+ }
652
+ return null;
653
+ }
654
+ const pack = async (data: object, pk: string) => {
655
+ const productConfig = await productConfigFileManage.getConfigFile(pk);
656
+ if (productConfig) {
657
+ const isAdaptiveDatapoint = productConfig.protocolType === 'var_len';
658
+ return DataPointToP({data, config: (await productConfig).entities[0].attrs, isAdaptiveDatapoint});
659
+ }
660
+ return null;
661
+ }
662
+
663
+ export {pack, unpack};