@atelieruldetehnologii/node-red-custome-solutions 0.62.22

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 (107) hide show
  1. package/NOTICE +56 -0
  2. package/PROPRIETARY-LICENSE.txt +157 -0
  3. package/README.md +105 -0
  4. package/TERMS-AND-CONDITIONS.md +311 -0
  5. package/advantech-read/advantech-read.html +775 -0
  6. package/advantech-read/advantech-read.js +449 -0
  7. package/advantech-write/advantech-write.html +413 -0
  8. package/advantech-write/advantech-write.js +338 -0
  9. package/bess-control/bess-control.html +569 -0
  10. package/bess-control/bess-control.js +541 -0
  11. package/bess-control/lib/allocation.js +149 -0
  12. package/bess-control/lib/batteries.js +86 -0
  13. package/bess-control/lib/helpers.js +157 -0
  14. package/bess-control/lib/messages.js +131 -0
  15. package/bess-control/lib/runtime.js +156 -0
  16. package/carlo-gavazzi/carlo-gavazzi.html +4327 -0
  17. package/carlo-gavazzi/carlo-gavazzi.js +3081 -0
  18. package/control-export/control-export.html +3644 -0
  19. package/control-export/control-export.js +2192 -0
  20. package/control-reactive/control-reactive.html +3136 -0
  21. package/control-reactive/control-reactive.js +2124 -0
  22. package/fronius-emulator/README.md +258 -0
  23. package/fronius-emulator/fronius-emulator.html +170 -0
  24. package/fronius-emulator/fronius-emulator.js +520 -0
  25. package/fronius-emulator/lib/binary-codec.js +65 -0
  26. package/fronius-emulator/lib/fronius-register-map.js +185 -0
  27. package/fronius-emulator/lib/modbus-parser.js +61 -0
  28. package/fronius-emulator/lib/modbus-tcp-server.js +224 -0
  29. package/fronius-emulator/lib/validation.js +206 -0
  30. package/fronius-emulator/lib/virtual-meter.js +132 -0
  31. package/fronius-read/fronius-read.html +3944 -0
  32. package/fronius-read/fronius-read.js +1466 -0
  33. package/fronius-read/lib/inverter-profiles.js +711 -0
  34. package/fronius-read/lib/sunspec-core.js +303 -0
  35. package/fronius-read/lib/sunspec-model-parsers.js +845 -0
  36. package/fronius-write/fronius-write.html +1789 -0
  37. package/fronius-write/fronius-write.js +2531 -0
  38. package/influxdb/influxdb.html +1077 -0
  39. package/influxdb/influxdb.js +1487 -0
  40. package/janitza/janitza.html +2562 -0
  41. package/janitza/janitza.js +1500 -0
  42. package/janitza/lib/janitza-profiles.js +371 -0
  43. package/lib/a3-test-server.js +199 -0
  44. package/lib/adam-6000-profiles.js +173 -0
  45. package/lib/licensing/constants.js +103 -0
  46. package/lib/licensing/device-id.js +251 -0
  47. package/lib/licensing/errors.js +21 -0
  48. package/lib/licensing/license-client.js +377 -0
  49. package/lib/licensing/license-state.js +50 -0
  50. package/lib/licensing/node-guard.js +150 -0
  51. package/lib/licensing/package-integrity.js +167 -0
  52. package/lib/licensing/package-integrity.json +513 -0
  53. package/lib/licensing/public-key.pem +3 -0
  54. package/lib/licensing/public-key.pem.example +2 -0
  55. package/lib/licensing/public-keys.js +18 -0
  56. package/lib/licensing/storage.js +63 -0
  57. package/lib/licensing/token-verifier.js +84 -0
  58. package/lib/numbers.js +26 -0
  59. package/license/atelier-license.html +88 -0
  60. package/license/atelier-license.js +170 -0
  61. package/modbus-tcp-discover/modbus-tcp-discover.html +190 -0
  62. package/modbus-tcp-discover/modbus-tcp-discover.js +706 -0
  63. package/multi-battery/multi-battery.html +649 -0
  64. package/multi-battery/multi-battery.js +668 -0
  65. package/multi-grid/multi-grid.html +745 -0
  66. package/multi-grid/multi-grid.js +1392 -0
  67. package/multi-inverter/lib/engine-core.js +237 -0
  68. package/multi-inverter/multi-inverter.html +2674 -0
  69. package/multi-inverter/multi-inverter.js +1393 -0
  70. package/package.json +109 -0
  71. package/phoenix-contact/lib/eem-ma370-advanced.js +175 -0
  72. package/phoenix-contact/lib/eem-ma370.js +138 -0
  73. package/phoenix-contact/lib/integrations.js +149 -0
  74. package/phoenix-contact/lib/phoenix-contact-profile.js +35030 -0
  75. package/phoenix-contact/phoenix-contact.html +840 -0
  76. package/phoenix-contact/phoenix-contact.js +679 -0
  77. package/pv-generator/pv-generator.html +284 -0
  78. package/pv-generator/pv-generator.js +387 -0
  79. package/pylontech-read/pylontech-read.html +763 -0
  80. package/pylontech-read/pylontech-read.js +518 -0
  81. package/pylontech-write/pylontech-write.html +405 -0
  82. package/pylontech-write/pylontech-write.js +546 -0
  83. package/scada-aggregator/lib/aggregate.js +72 -0
  84. package/scada-aggregator/lib/groups.js +39 -0
  85. package/scada-aggregator/scada-aggregator.html +108 -0
  86. package/scada-aggregator/scada-aggregator.js +117 -0
  87. package/scada-server/lib/aggregator-map.js +58 -0
  88. package/scada-server/lib/encoding.js +235 -0
  89. package/scada-server/lib/modbus-server.js +492 -0
  90. package/scada-server/lib/object-path.js +18 -0
  91. package/scada-server/lib/register-map.js +288 -0
  92. package/scada-server/scada-server.html +1419 -0
  93. package/scada-server/scada-server.js +704 -0
  94. package/scripts/check-syntax.js +66 -0
  95. package/scripts/package-integrity.js +46 -0
  96. package/scripts/package-release.js +116 -0
  97. package/scripts/run-tests.js +2178 -0
  98. package/scripts/tgz-integrity.js +74 -0
  99. package/sma-read/lib/sunspec-core.js +83 -0
  100. package/sma-read/lib/sunspec-model-parsers.js +853 -0
  101. package/sma-read/sma-read.html +659 -0
  102. package/sma-read/sma-read.js +458 -0
  103. package/sma-write/sma-write.html +105 -0
  104. package/sma-write/sma-write.js +270 -0
  105. package/victron-read/lib/mqtt-state.js +176 -0
  106. package/victron-read/victron-read.html +1074 -0
  107. package/victron-read/victron-read.js +1222 -0
@@ -0,0 +1,853 @@
1
+ function toSigned16(v) {
2
+
3
+ return v > 32767 ? v - 65536 : v;
4
+
5
+ }
6
+
7
+
8
+ function round2(v) {
9
+
10
+ if (v === null || v === undefined || Number.isNaN(v)) return null;
11
+
12
+ return Math.round(v * 100) / 100;
13
+
14
+ }
15
+
16
+
17
+ function scaleValue(raw, sf) {
18
+
19
+ if (raw === null || raw === undefined || sf === null || sf === undefined) return null;
20
+
21
+ if (sf === -32768) return null;
22
+
23
+ return raw * Math.pow(10, sf);
24
+
25
+ }
26
+
27
+
28
+ function decodeSunSpecString(registers) {
29
+
30
+ let out = "";
31
+
32
+
33
+ for (const reg of registers) {
34
+
35
+ out += String.fromCharCode((reg >> 8) & 0xff);
36
+
37
+ out += String.fromCharCode(reg & 0xff);
38
+
39
+ }
40
+
41
+
42
+ return out.replace(/\0/g, "").trim();
43
+
44
+ }
45
+
46
+
47
+ function safeGet(arr, idx, def = null) {
48
+
49
+ return idx >= 0 && idx < arr.length ? arr[idx] : def;
50
+
51
+ }
52
+
53
+
54
+ function u16ToFloat(regHi, regLo) {
55
+
56
+ const buf = Buffer.allocUnsafe(4);
57
+
58
+ buf.writeUInt16BE(regHi >>> 0, 0);
59
+
60
+ buf.writeUInt16BE(regLo >>> 0, 2);
61
+
62
+ return buf.readFloatBE(0);
63
+
64
+ }
65
+
66
+ function u32(hi, lo) {
67
+
68
+ return (((hi || 0) << 16) | (lo || 0)) >>> 0;
69
+
70
+ }
71
+
72
+
73
+ function readScaledS16(d, index, sf) {
74
+
75
+ const raw = safeGet(d, index, null);
76
+
77
+ if (raw === null || raw === 0x8000 || raw === 0xFFFF) return null;
78
+
79
+ return round2(scaleValue(toSigned16(raw), sf));
80
+
81
+ }
82
+
83
+
84
+ function readScaledU32(d, index, sf) {
85
+
86
+ if (index + 1 >= d.length) return null;
87
+
88
+ const raw = u32(safeGet(d, index, 0), safeGet(d, index + 1, 0));
89
+
90
+ if (raw === 0xFFFFFFFF) return null;
91
+
92
+ return round2(scaleValue(raw, sf));
93
+
94
+ }
95
+
96
+
97
+ function readFloat32(d, index) {
98
+
99
+ if (index + 1 >= d.length) return null;
100
+
101
+ const hi = safeGet(d, index, null);
102
+
103
+ const lo = safeGet(d, index + 1, null);
104
+
105
+ if (hi === null || lo === null || (hi === 0xFFFF && lo === 0xFFFF)) return null;
106
+
107
+ const value = u16ToFloat(hi, lo);
108
+
109
+ return Number.isFinite(value) ? round2(value) : null;
110
+
111
+ }
112
+
113
+
114
+ function parseCommon(model) {
115
+
116
+ const d = model.raw;
117
+
118
+
119
+ return {
120
+
121
+
122
+ manufacturer: decodeSunSpecString(d.slice(0, 16)),
123
+
124
+ model: decodeSunSpecString(d.slice(16, 32)),
125
+
126
+ options: decodeSunSpecString(d.slice(32, 40)),
127
+
128
+ version: decodeSunSpecString(d.slice(40, 48)),
129
+
130
+ serial: decodeSunSpecString(d.slice(48, 64)),
131
+
132
+ device_address: safeGet(d, 64, null)
133
+
134
+ };
135
+
136
+ }
137
+
138
+
139
+ function parseInverterInt(model) {
140
+
141
+ const d = model.raw;
142
+
143
+
144
+ const A_SF = toSigned16(safeGet(d, 4, 0));
145
+
146
+ const V_SF = toSigned16(safeGet(d, 11, 0));
147
+
148
+ const W_SF = toSigned16(safeGet(d, 13, 0));
149
+
150
+ const HZ_SF = toSigned16(safeGet(d, 15, 0));
151
+
152
+ const VA_SF = toSigned16(safeGet(d, 17, 0));
153
+
154
+ const VAR_SF = toSigned16(safeGet(d, 19, 0));
155
+
156
+
157
+ return {
158
+
159
+ model_id: model.model_id,
160
+
161
+
162
+ current_total_a: round2(scaleValue(safeGet(d, 0, 0), A_SF)),
163
+
164
+ current_l1_a: round2(scaleValue(toSigned16(safeGet(d, 1, 0)), A_SF)),
165
+
166
+ current_l2_a: round2(scaleValue(toSigned16(safeGet(d, 2, 0)), A_SF)),
167
+
168
+ current_l3_a: round2(scaleValue(toSigned16(safeGet(d, 3, 0)), A_SF)),
169
+
170
+
171
+ voltage_ll_ab_v: round2(scaleValue(toSigned16(safeGet(d, 5, 0)), V_SF)),
172
+
173
+ voltage_ll_bc_v: round2(scaleValue(toSigned16(safeGet(d, 6, 0)), V_SF)),
174
+
175
+ voltage_ll_ca_v: round2(scaleValue(toSigned16(safeGet(d, 7, 0)), V_SF)),
176
+
177
+
178
+ voltage_l1_v: round2(scaleValue(toSigned16(safeGet(d, 8, 0)), V_SF)),
179
+
180
+ voltage_l2_v: round2(scaleValue(toSigned16(safeGet(d, 9, 0)), V_SF)),
181
+
182
+ voltage_l3_v: round2(scaleValue(toSigned16(safeGet(d, 10, 0)), V_SF)),
183
+
184
+
185
+ power_w: round2(scaleValue(toSigned16(safeGet(d, 12, 0)), W_SF)),
186
+
187
+ frequency_hz: round2(scaleValue(toSigned16(safeGet(d, 14, 0)), HZ_SF)),
188
+
189
+ apparent_power_va: round2(scaleValue(toSigned16(safeGet(d, 16, 0)), VA_SF)),
190
+
191
+ reactive_power_var: round2(scaleValue(toSigned16(safeGet(d, 18, 0)), VAR_SF)),
192
+
193
+
194
+ raw_sf: {
195
+
196
+ A_SF,
197
+
198
+ V_SF,
199
+
200
+ W_SF,
201
+
202
+ HZ_SF,
203
+
204
+ VA_SF,
205
+
206
+ VAR_SF
207
+
208
+ }
209
+
210
+ };
211
+
212
+ }
213
+
214
+
215
+ function parseInverterFloat(model) {
216
+
217
+ const d = model.raw;
218
+
219
+
220
+ function f(idx) {
221
+
222
+ if (idx + 1 >= d.length) return null;
223
+
224
+ return round2(u16ToFloat(d[idx], d[idx + 1]));
225
+
226
+ }
227
+
228
+
229
+ return {
230
+
231
+ model_id: model.model_id,
232
+
233
+
234
+ current_total_a: f(0),
235
+
236
+ current_l1_a: f(2),
237
+
238
+ current_l2_a: f(4),
239
+
240
+ current_l3_a: f(6),
241
+
242
+
243
+
244
+ voltage_ll_ab_v: f(8),
245
+
246
+ voltage_ll_bc_v: f(10),
247
+
248
+ voltage_ll_ca_v: f(12),
249
+
250
+
251
+ voltage_l1_v: f(14),
252
+
253
+ voltage_l2_v: f(16),
254
+
255
+ voltage_l3_v: f(18),
256
+
257
+
258
+ power_w: f(20),
259
+
260
+ frequency_hz: f(22),
261
+
262
+ apparent_power_va: f(24),
263
+
264
+ reactive_power_var: f(26)
265
+
266
+ };
267
+
268
+ }
269
+
270
+
271
+ function parseMeterInt(model) {
272
+
273
+ const d = model.raw;
274
+
275
+ const A_SF = toSigned16(safeGet(d, 4, 0));
276
+
277
+ const V_SF = toSigned16(safeGet(d, 13, 0));
278
+
279
+ const HZ_SF = toSigned16(safeGet(d, 15, 0));
280
+
281
+ const W_SF = toSigned16(safeGet(d, 20, 0));
282
+
283
+ const VA_SF = toSigned16(safeGet(d, 25, 0));
284
+
285
+ const VAR_SF = toSigned16(safeGet(d, 30, 0));
286
+
287
+ const PF_SF = toSigned16(safeGet(d, 35, 0));
288
+
289
+ const WH_SF = toSigned16(safeGet(d, 52, 0));
290
+
291
+ const VAH_SF = toSigned16(safeGet(d, 69, 0));
292
+
293
+ const VARH_SF = toSigned16(safeGet(d, 102, 0));
294
+
295
+
296
+ return {
297
+
298
+ model_id: model.model_id,
299
+
300
+ meter_model: getMeterModelName(model.model_id),
301
+
302
+ current_total_a: readScaledS16(d, 0, A_SF),
303
+
304
+ current_l1_a: readScaledS16(d, 1, A_SF),
305
+
306
+ current_l2_a: readScaledS16(d, 2, A_SF),
307
+
308
+ current_l3_a: readScaledS16(d, 3, A_SF),
309
+
310
+ voltage_ln_avg_v: readScaledS16(d, 5, V_SF),
311
+
312
+ voltage_l1_v: readScaledS16(d, 6, V_SF),
313
+
314
+ voltage_l2_v: readScaledS16(d, 7, V_SF),
315
+
316
+ voltage_l3_v: readScaledS16(d, 8, V_SF),
317
+
318
+ voltage_ll_avg_v: readScaledS16(d, 9, V_SF),
319
+
320
+ voltage_ll_ab_v: readScaledS16(d, 10, V_SF),
321
+
322
+ voltage_ll_bc_v: readScaledS16(d, 11, V_SF),
323
+
324
+ voltage_ll_ca_v: readScaledS16(d, 12, V_SF),
325
+
326
+ frequency_hz: readScaledS16(d, 14, HZ_SF),
327
+
328
+ power_w: readScaledS16(d, 16, W_SF),
329
+
330
+ power_l1_w: readScaledS16(d, 17, W_SF),
331
+
332
+ power_l2_w: readScaledS16(d, 18, W_SF),
333
+
334
+ power_l3_w: readScaledS16(d, 19, W_SF),
335
+
336
+ apparent_power_va: readScaledS16(d, 21, VA_SF),
337
+
338
+ apparent_power_l1_va: readScaledS16(d, 22, VA_SF),
339
+
340
+ apparent_power_l2_va: readScaledS16(d, 23, VA_SF),
341
+
342
+ apparent_power_l3_va: readScaledS16(d, 24, VA_SF),
343
+
344
+ reactive_power_var: readScaledS16(d, 26, VAR_SF),
345
+
346
+ reactive_power_l1_var: readScaledS16(d, 27, VAR_SF),
347
+
348
+ reactive_power_l2_var: readScaledS16(d, 28, VAR_SF),
349
+
350
+ reactive_power_l3_var: readScaledS16(d, 29, VAR_SF),
351
+
352
+ power_factor: readScaledS16(d, 31, PF_SF),
353
+
354
+ power_factor_l1: readScaledS16(d, 32, PF_SF),
355
+
356
+ power_factor_l2: readScaledS16(d, 33, PF_SF),
357
+
358
+ power_factor_l3: readScaledS16(d, 34, PF_SF),
359
+
360
+ energy_export_wh: readScaledU32(d, 36, WH_SF),
361
+
362
+ energy_export_l1_wh: readScaledU32(d, 38, WH_SF),
363
+
364
+
365
+ energy_export_l2_wh: readScaledU32(d, 40, WH_SF),
366
+
367
+ energy_export_l3_wh: readScaledU32(d, 42, WH_SF),
368
+
369
+ energy_import_wh: readScaledU32(d, 44, WH_SF),
370
+
371
+ energy_import_l1_wh: readScaledU32(d, 46, WH_SF),
372
+
373
+ energy_import_l2_wh: readScaledU32(d, 48, WH_SF),
374
+
375
+ energy_import_l3_wh: readScaledU32(d, 50, WH_SF),
376
+
377
+ apparent_energy_export_vah: readScaledU32(d, 53, VAH_SF),
378
+
379
+ apparent_energy_import_vah: readScaledU32(d, 61, VAH_SF),
380
+
381
+ reactive_energy_import_q1_varh: readScaledU32(d, 70, VARH_SF),
382
+
383
+ reactive_energy_import_q2_varh: readScaledU32(d, 78, VARH_SF),
384
+
385
+ reactive_energy_export_q3_varh: readScaledU32(d, 86, VARH_SF),
386
+
387
+ reactive_energy_export_q4_varh: readScaledU32(d, 94, VARH_SF),
388
+
389
+ event_flags: u32(safeGet(d, 103, 0), safeGet(d, 104, 0)),
390
+
391
+ raw_sf: {
392
+
393
+ A_SF,
394
+
395
+ V_SF,
396
+
397
+ HZ_SF,
398
+
399
+ W_SF,
400
+
401
+ VA_SF,
402
+
403
+ VAR_SF,
404
+
405
+ PF_SF,
406
+
407
+ WH_SF,
408
+
409
+ VAH_SF,
410
+
411
+ VARH_SF
412
+
413
+ }
414
+
415
+ };
416
+
417
+ }
418
+
419
+
420
+ function parseMeterFloat(model) {
421
+
422
+ const d = model.raw;
423
+
424
+ return {
425
+
426
+ model_id: model.model_id,
427
+
428
+ meter_model: getMeterModelName(model.model_id),
429
+
430
+ current_total_a: readFloat32(d, 0),
431
+
432
+ current_l1_a: readFloat32(d, 2),
433
+
434
+ current_l2_a: readFloat32(d, 4),
435
+
436
+ current_l3_a: readFloat32(d, 6),
437
+
438
+ voltage_ln_avg_v: readFloat32(d, 8),
439
+
440
+ voltage_l1_v: readFloat32(d, 10),
441
+
442
+ voltage_l2_v: readFloat32(d, 12),
443
+
444
+ voltage_l3_v: readFloat32(d, 14),
445
+
446
+ voltage_ll_avg_v: readFloat32(d, 16),
447
+
448
+ voltage_ll_ab_v: readFloat32(d, 18),
449
+
450
+ voltage_ll_bc_v: readFloat32(d, 20),
451
+
452
+ voltage_ll_ca_v: readFloat32(d, 22),
453
+
454
+ frequency_hz: readFloat32(d, 24),
455
+
456
+ power_w: readFloat32(d, 26),
457
+
458
+ power_l1_w: readFloat32(d, 28),
459
+
460
+ power_l2_w: readFloat32(d, 30),
461
+
462
+ power_l3_w: readFloat32(d, 32),
463
+
464
+ apparent_power_va: readFloat32(d, 34),
465
+
466
+ apparent_power_l1_va: readFloat32(d, 36),
467
+
468
+ apparent_power_l2_va: readFloat32(d, 38),
469
+
470
+ apparent_power_l3_va: readFloat32(d, 40),
471
+
472
+ reactive_power_var: readFloat32(d, 42),
473
+
474
+ reactive_power_l1_var: readFloat32(d, 44),
475
+
476
+ reactive_power_l2_var: readFloat32(d, 46),
477
+
478
+ reactive_power_l3_var: readFloat32(d, 48),
479
+
480
+ power_factor: readFloat32(d, 50),
481
+
482
+ power_factor_l1: readFloat32(d, 52),
483
+
484
+
485
+ power_factor_l2: readFloat32(d, 54),
486
+
487
+ power_factor_l3: readFloat32(d, 56),
488
+
489
+ energy_export_wh: readFloat32(d, 58),
490
+
491
+ energy_export_l1_wh: readFloat32(d, 60),
492
+
493
+ energy_export_l2_wh: readFloat32(d, 62),
494
+
495
+ energy_export_l3_wh: readFloat32(d, 64),
496
+
497
+ energy_import_wh: readFloat32(d, 66),
498
+
499
+ energy_import_l1_wh: readFloat32(d, 68),
500
+
501
+ energy_import_l2_wh: readFloat32(d, 70),
502
+
503
+ energy_import_l3_wh: readFloat32(d, 72),
504
+
505
+ apparent_energy_export_vah: readFloat32(d, 74),
506
+
507
+ apparent_energy_import_vah: readFloat32(d, 82),
508
+
509
+ reactive_energy_import_q1_varh: readFloat32(d, 90),
510
+
511
+ reactive_energy_import_q2_varh: readFloat32(d, 98),
512
+
513
+ reactive_energy_export_q3_varh: readFloat32(d, 106),
514
+
515
+ reactive_energy_export_q4_varh: readFloat32(d, 114),
516
+
517
+ event_flags: u32(safeGet(d, 122, 0), safeGet(d, 123, 0))
518
+
519
+ };
520
+
521
+ }
522
+
523
+
524
+ function getMeterModelName(modelId) {
525
+
526
+ if (modelId === 201 || modelId === 211) return "single_phase";
527
+
528
+ if (modelId === 202 || modelId === 212) return "split_phase";
529
+
530
+ if (modelId === 203 || modelId === 213) return "three_phase_wye";
531
+
532
+ if (modelId === 204 || modelId === 214) return "three_phase_delta";
533
+
534
+ return "unknown";
535
+
536
+ }
537
+
538
+
539
+ function parseControlRaw(model) {
540
+
541
+ return {
542
+
543
+ model_id: model.model_id,
544
+
545
+ len: model.len,
546
+
547
+ raw: model.raw
548
+
549
+ };
550
+
551
+ }
552
+
553
+
554
+ function parseMppt160(model) {
555
+
556
+ const d = model.raw;
557
+
558
+
559
+ const DCA_SF = toSigned16(safeGet(d, 0, 0));
560
+
561
+ const DCV_SF = toSigned16(safeGet(d, 1, 0));
562
+
563
+ const DCW_SF = toSigned16(safeGet(d, 2, 0));
564
+
565
+ const DCWH_SF = toSigned16(safeGet(d, 3, 0));
566
+
567
+
568
+ const global_evt =
569
+
570
+ ((safeGet(d, 4, 0) << 16) | safeGet(d, 5, 0)) >>> 0;
571
+
572
+
573
+ const moduleCount = safeGet(d, 6, 0);
574
+
575
+ const tmsPer = safeGet(d, 7, null);
576
+
577
+
578
+ const blocks = [];
579
+
580
+ const blockSize = 20;
581
+
582
+ const start = 8;
583
+
584
+
585
+ function notImplU16(v) {
586
+
587
+ return v === 0xFFFF;
588
+
589
+ }
590
+
591
+
592
+ function notImplS16(v) {
593
+
594
+ return v === 0x8000 || v === 0xFFFF;
595
+
596
+ }
597
+
598
+
599
+ function u32(hi, lo) {
600
+
601
+ return (((hi || 0) << 16) | (lo || 0)) >>> 0;
602
+
603
+ }
604
+
605
+
606
+
607
+ for (let i = 0; i < moduleCount; i++) {
608
+
609
+ const base = start + i * blockSize;
610
+
611
+ const block = d.slice(base, base + blockSize);
612
+
613
+
614
+ if (block.length < blockSize) {
615
+
616
+ break;
617
+
618
+ }
619
+
620
+
621
+ const mpptId = safeGet(block, 0, null);
622
+
623
+ const name = decodeSunSpecString(block.slice(1, 9)) || null;
624
+
625
+
626
+ const dcaRaw = safeGet(block, 9, null);
627
+
628
+ const dcvRaw = safeGet(block, 10, null);
629
+
630
+ const dcwRaw = safeGet(block, 11, null);
631
+
632
+
633
+ const dcwhRaw = u32(safeGet(block, 12, 0), safeGet(block, 13, 0));
634
+
635
+ const tmsRaw = u32(safeGet(block, 14, 0), safeGet(block, 15, 0));
636
+
637
+
638
+ const tmpRaw = safeGet(block, 16, null);
639
+
640
+ const dcStRaw = safeGet(block, 17, null);
641
+
642
+ const dcEvtRaw = u32(safeGet(block, 18, 0), safeGet(block, 19, 0));
643
+
644
+
645
+ const entry = {
646
+
647
+ mppt_id: mpptId,
648
+
649
+ name: name,
650
+
651
+ dc_current_a: notImplU16(dcaRaw) ? null : round2(scaleValue(dcaRaw, DCA_SF)),
652
+
653
+ dc_voltage_v: notImplU16(dcvRaw) ? null : round2(scaleValue(dcvRaw, DCV_SF)),
654
+
655
+ dc_power_w: notImplU16(dcwRaw) ? null : round2(scaleValue(dcwRaw, DCW_SF)),
656
+
657
+ dc_energy_wh: dcwhRaw === 0xFFFFFFFF ? null : round2(scaleValue(dcwhRaw, DCWH_SF)),
658
+
659
+ timestamp_s: tmsRaw === 0xFFFFFFFF ? null : tmsRaw,
660
+
661
+ temperature_c: notImplS16(tmpRaw) ? null : tmpRaw,
662
+
663
+ dc_state: dcStRaw === 0xFFFF ? null : dcStRaw,
664
+
665
+ dc_event: dcEvtRaw === 0xFFFFFFFF ? null : dcEvtRaw,
666
+
667
+ raw: block
668
+
669
+ };
670
+
671
+
672
+ blocks.push(entry);
673
+
674
+ }
675
+
676
+
677
+ const dcTotalPower = round2(
678
+
679
+ blocks.reduce((sum, b) => sum + (b.dc_power_w || 0), 0)
680
+
681
+ );
682
+
683
+
684
+ return {
685
+
686
+ model_id: model.model_id,
687
+
688
+ module_count: moduleCount,
689
+
690
+ tms_per: tmsPer === 0xFFFF ? null : tmsPer,
691
+
692
+ global_event: global_evt === 0xFFFFFFFF ? null : global_evt,
693
+
694
+ scale_factors: {
695
+
696
+ DCA_SF,
697
+
698
+ DCV_SF,
699
+
700
+ DCW_SF,
701
+
702
+ DCWH_SF
703
+
704
+ },
705
+
706
+ mppts: blocks,
707
+
708
+ dc_total_power_w: dcTotalPower
709
+
710
+ };
711
+
712
+ }
713
+
714
+
715
+ const MODEL_PARSERS = {
716
+
717
+ 1: parseCommon,
718
+
719
+ 101: parseInverterInt,
720
+
721
+ 102: parseInverterInt,
722
+
723
+ 103: parseInverterInt,
724
+
725
+ 111: parseInverterFloat,
726
+
727
+
728
+ 112: parseInverterFloat,
729
+
730
+ 113: parseInverterFloat,
731
+
732
+ 120: parseControlRaw,
733
+
734
+ 121: parseControlRaw,
735
+
736
+ 122: parseControlRaw,
737
+
738
+ 123: parseControlRaw,
739
+
740
+ 160: parseMppt160,
741
+
742
+ 201: parseMeterInt,
743
+
744
+ 202: parseMeterInt,
745
+
746
+ 203: parseMeterInt,
747
+
748
+ 204: parseMeterInt,
749
+
750
+ 211: parseMeterFloat,
751
+
752
+ 212: parseMeterFloat,
753
+
754
+ 213: parseMeterFloat,
755
+
756
+ 214: parseMeterFloat
757
+
758
+ };
759
+
760
+
761
+ function buildSummary(models) {
762
+
763
+ const summary = {
764
+
765
+ common: null,
766
+
767
+ ac: null,
768
+
769
+ dc: null,
770
+
771
+ meter: null,
772
+
773
+ controls: [],
774
+
775
+ unknown_models: []
776
+
777
+ };
778
+
779
+
780
+ for (const model of models) {
781
+
782
+ const parser = MODEL_PARSERS[model.model_id];
783
+
784
+
785
+ if (!parser) {
786
+
787
+ summary.unknown_models.push({
788
+
789
+ model_id: model.model_id,
790
+
791
+ addr: model.addr,
792
+
793
+ len: model.len
794
+
795
+ });
796
+
797
+ continue;
798
+
799
+ }
800
+
801
+
802
+ const parsed = parser(model);
803
+
804
+
805
+ if (model.model_id === 1) {
806
+
807
+ summary.common = parsed;
808
+
809
+ } else if ([101, 102, 103, 111, 112, 113].includes(model.model_id)) {
810
+
811
+ summary.ac = parsed;
812
+
813
+ } else if ([120, 121, 122, 123].includes(model.model_id)) {
814
+
815
+ summary.controls.push(parsed);
816
+
817
+ } else if (model.model_id === 160) {
818
+
819
+ summary.dc = parsed;
820
+
821
+ } else if ([201, 202, 203, 204, 211, 212, 213, 214].includes(model.model_id)) {
822
+
823
+ summary.meter = parsed;
824
+
825
+ }
826
+
827
+ }
828
+
829
+
830
+ return summary;
831
+
832
+ }
833
+
834
+
835
+ module.exports = {
836
+
837
+ MODEL_PARSERS,
838
+
839
+ buildSummary,
840
+
841
+ toSigned16,
842
+
843
+ round2,
844
+
845
+ scaleValue,
846
+
847
+
848
+ decodeSunSpecString,
849
+
850
+ safeGet
851
+
852
+ };
853
+