iobroker.bydhvs 1.2.3 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/main.js CHANGED
@@ -1,823 +1,953 @@
1
- "use strict";
2
-
3
- /*
4
- * Created with @iobroker/create-adapter v1.31.0
5
- */
6
-
7
- // battery icon from
8
- // https://freepsdfiles.net/graphics/battery-icon-psd
9
-
10
- // The adapter-core module gives you access to the core ioBroker functions
11
- // you need to create an adapter
12
- const utils = require("@iobroker/adapter-core"); // Get common adapter utils
13
- const crc = require("crc");
14
- //const ioBLib = require('strathcole/iob-lib').ioBLib;
15
- const net = require("net");
16
- const IPClient = new net.Socket();
17
-
18
-
19
- // Load your modules here, e.g.:
20
- // const fs = require("fs");
21
-
22
- /**
23
- * The adapter instance
24
- * @type {ioBroker.Adapter}
25
- */
26
- let adapter;
27
- const hvsBatteryVoltsperCell = [];
28
- const hvsBatteryTempperCell = [];
29
- // globale Variablen
30
- /** @type {number | any } */
31
- let myState; // Aktueller Status
32
- let hvsSOC;
33
- let hvsMaxVolt;
34
- let hvsMinVolt;
35
- let hvsMaxmVolt;
36
- let hvsMinmVolt;
37
- let hvsMaxmVoltCell;
38
- let hvsMinmVoltCell;
39
- let hvsA;
40
- let hvsBattVolt;
41
- let hvsMaxTemp;
42
- let hvsMinTemp;
43
- let hvsMaxTempCell;
44
- let hvsMinTempCell;
45
- let hvsBatTemp;
46
- let hvsOutVolt;
47
- let hvsError;
48
- let hvsModules;
49
- let hvsDiffVolt;
50
- let hvsPower;
51
- let hvsBattType;
52
- let hvsInvType;
53
- let hvsNumCells; //number of cells in system
54
- let hvsNumTemps; // number of temperatures to count with
55
- let ConfBatDetailshowoften;
56
- let confBatPollTime;
57
- let myNumberforDetails;
58
- let ConfTestMode;
59
- let FirstRun;
60
-
61
-
62
- /** @type {string} */
63
- let hvsSerial;
64
- let hvsBMU;
65
- let hvsBMUA;
66
- let hvsBMUB;
67
- let hvsBMS;
68
- let hvsGrid;
69
- let hvsErrorString;
70
- let hvsParamT;
71
-
72
- /** @type {boolean} */
73
- let ConfBatDetails;
74
-
75
- /*const myStates = [
76
- "no state",
77
- "waiting for initial connect",
78
- "waiting for 1st answer",
79
- "waiting for 2nd answer"
80
-
81
- ];*/
82
-
83
-
84
-
85
- /** @type {NodeJS.Timeout} */
86
- let idInterval1;
87
- let idTimeout1;
88
-
89
-
90
- const myRequests = [
91
- Buffer.from("010300000066c5e0", "hex"), //0
92
- Buffer.from("01030500001984cc", "hex"), //1
93
- Buffer.from("010300100003040e", "hex"), //2
94
- Buffer.from("0110055000020400018100f853", "hex"), //3
95
- Buffer.from("010305510001d517", "hex"), //4
96
- Buffer.from("01030558004104e5", "hex"), //5
97
- Buffer.from("01030558004104e5", "hex"), //6
98
- Buffer.from("01030558004104e5", "hex"), //7
99
- Buffer.from("01030558004104e5", "hex"), //8
100
- ];
101
-
102
-
103
- /* Während des Updates des BMS funktioniert das Auslesen offensichtlich nicht, hier die Antworten des Speichers (Seriennummer verfälscht und CRC des ersten Paketes nicht neu berechnet)
104
- 0103cc503030303030303030303030303030303030307878787878030d030f031401000312020101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000015040c12382b82b2
105
- 0103320043014a014a0063fff852a80015001400140000030f0000000000000902000252761703000013840000000209020000042c925b
106
- 010306031202010100c8ad
107
- 0190044dc3 <- Das scheint eine Fehlercondition zu sein.
108
- 5 min. später klappte es wieder und dann war auch die neue F/W-Version in der Antwort enthalten
109
- */
110
- const myErrors = [
111
- "High Temperature Charging (Cells)",
112
- "Low Temperature Charging (Cells)",
113
- "Over Current Discharging",
114
- "Over Current Charging",
115
- "Main circuit Failure",
116
- "Short Current Alarm",
117
- "Cells Imbalance",
118
- "Current Sensor Failure",
119
- "Battery Over Voltage",
120
- "Battery Under Voltage",
121
- "Cell Over Voltage",
122
- "Cell Under Voltage",
123
- "Voltage Sensor Failure",
124
- "Temperature Sensor Failure",
125
- "High Temperature Discharging (Cells)",
126
- "Low Temperature Discharging (Cells)"
127
- ];
128
-
129
- const myINVs = [
130
- "Fronius HV",
131
- "Goodwe HV",
132
- "Fronius HV",
133
- "Kostal HV",
134
- "Goodwe HV",
135
- "SMA SBS3.7/5.0",
136
- "Kostal HV",
137
- "SMA SBS3.7/5.0",
138
- "Sungrow HV",
139
- "Sungrow HV",
140
- "Kaco HV",
141
- "Kaco HV",
142
- "Ingeteam HV",
143
- "Ingeteam HV",
144
- "SMA SBS 2.5 HV",
145
- "",
146
- "SMA SBS 2.5 HV",
147
- "Fronius HV"
148
- ];
149
-
150
- const myBattTypes = [
151
- "HVL",
152
- "HVM",
153
- "HVS"
154
- ]
155
- /* HVM: 16 cells per module
156
- HVS: 32 cells per module
157
- HVL: unknown so I count 0 cells per module
158
- */
159
-
160
- /**
161
- * Starts the adapter instance
162
- * @param {Partial<utils.AdapterOptions>} [options]
163
- */
164
- function startAdapter(options) {
165
- // Create the adapter and define its methods
166
- return adapter = utils.adapter(Object.assign({}, options, {
167
- name: "bydhvs",
168
-
169
- // The ready callback is called when databases are connected and adapter received configuration.
170
- // start here!
171
- ready: main, // Main method defined below for readability
172
-
173
- // is called when adapter shuts down - callback has to be called under any circumstances!
174
- unload: (callback) => {
175
- adapter.log.silly("got unload event");
176
- try {
177
- clearInterval(idInterval1);
178
- clearTimeout(idTimeout1);
179
- stopPoll();
180
- IPClient.destroy();
181
-
182
- callback();
183
- } catch (e) {
184
- callback();
185
- }
186
- },
187
- }));
188
- }
189
-
190
-
191
- function setObjectsCells() {
192
- //Diagnose-data only if necessary.
193
- const myObjects = [
194
- ["Diagnosis.mVoltMax", "state", "Max Cell Voltage (mv)", "number", "value.voltage", true, false, "mV"],
195
- ["Diagnosis.mVoltMin", "state", "Min Cell Voltage (mv)", "number", "value.voltage", true, false, "mV"],
196
- ["Diagnosis.mVoltMaxCell", "state", "Max Cell Volt (Cellnr)", "number", "value.voltage", true, false, ""],
197
- ["Diagnosis.mVoltMinCell", "state", "Min Cell Volt (Cellnr)", "number", "value.voltage", true, false, ""],
198
- ["Diagnosis.TempMaxCell", "state", "Max Cell Temp (Cellnr)", "number", "value.temperature", true, false, ""],
199
- ["Diagnosis.TempMinCell", "state", "Min Cell Temp(Cellnr)", "number", "value.temperature", true, false, ""],
200
- ];
201
-
202
- for (let i = 0; i < myObjects.length; i++) {
203
- adapter.setObjectNotExists(myObjects[i][0], {
204
- type: myObjects[i][1],
205
- common: {
206
- name: myObjects[i][2],
207
- type: myObjects[i][3],
208
- role: myObjects[i][4],
209
- read: myObjects[i][5],
210
- write: myObjects[i][6],
211
- unit: myObjects[i][7],
212
- },
213
- native: {}
214
- });
215
- }
216
- for (let i = 0; i < myObjects.length; i++) {
217
- //console.log("****extend " + i + " " + myObjects[i][0] + " " + myObjects[i][7]);
218
- checkandrepairUnit(myObjects[i][0], myObjects[i][7], myObjects[i][5]);
219
- }
220
-
221
-
222
- for (let i = 1; i <= hvsNumCells; i++) {
223
- adapter.setObjectNotExists("CellDetails.CellVolt" + pad(i, 3), {
224
- type: "state",
225
- common: {
226
- name: "Voltage Cell: " + pad(i, 3),
227
- type: "number",
228
- role: "value.voltage",
229
- read: true,
230
- write: false,
231
- unit: "mV"
232
- },
233
- native: {}
234
- });
235
- checkandrepairUnit("CellDetails.CellVolt" + pad(i, 3), "mV", "value.voltage"); //repair forgotten units in first version
236
-
237
- for (let i = 1; i <= hvsNumTemps; i++) {
238
- adapter.setObjectNotExists("CellDetails.CellTemp" + pad(i, 3), {
239
- type: "state",
240
- common: {
241
- name: "Temp Cell: " + pad(i, 3),
242
- type: "number",
243
- role: "value.temperature",
244
- read: true,
245
- write: false,
246
- unit: "°C"
247
- },
248
- native: {}
249
- });
250
- checkandrepairUnit("CellDetails.CellTemp" + pad(i, 3), "°C", "value.temperature"); //repair forgotten units in first version
251
- }
252
- }
253
- }
254
-
255
- function setObjects() {
256
- const myObjects = [
257
- ["System.Serial", "state", "Serial number", "string", "text", true, false, ""],
258
- ["System.BMU", "state", "F/W BMU", "string", "text", true, false, ""],
259
- ["System.BMS", "state", "F/W BMS", "string", "text", true, false, ""],
260
- ["System.BMUBankA", "state", "F/W BMU-BankA", "string", "text", true, false, ""],
261
- ["System.BMUBankB", "state", "F/W BMU-BankB", "string", "text", true, false, ""],
262
- ["System.Modules", "state", "modules (count)", "number", "value", true, false, ""],
263
- ["System.Grid", "state", "Parameter Table", "string", "text", true, false, ""],
264
- ["System.ParamT", "state", "F/W BMU", "string", "text", true, false, ""],
265
- ["System.BattType", "state", "Battery Type", "string", "text", true, false, ""],
266
- ["System.InvType", "state", "Inverter Type", "string", "text", true, false, ""],
267
- ["State.SOC", "state", "SOC", "number", "value.battery", true, false, "%"],
268
- ["State.VoltMax", "state", "Max Cell Voltage", "number", "value.voltage", true, false, "V"],
269
- ["State.VoltMin", "state", "Min Cell Voltage", "number", "value.voltage", true, false, "V"],
270
- ["State.Current", "state", "Charge / Discharge Current", "number", "value.current", true, false, "A"],
271
- ["State.Power_Consumption", "state", "Discharge Power", "number", "value.power", true, false, "W"],
272
- ["State.Power_Delivery", "state", "Charge Power", "number", "value.power", true, false, "W"],
273
- ["State.VoltBatt", "state", "Battery Voltage", "number", "value.voltage", true, false, "V"],
274
- ["State.TempMax", "state", "Max Cell Temp", "number", "value.temperature", true, false, "°C"],
275
- ["State.TempMin", "state", "Min Cell Temp", "number", "value.temperature", true, false, "°C"],
276
- ["State.VoltDiff", "state", "Max - Min Cell Voltage", "number", "value.temperature", true, false, "V"],
277
- ["State.Power", "state", "Power", "number", "value.power", true, false, "W"],
278
- ["State.TempBatt", "state", "Battery Temperature", "number", "value.temperature", true, false, "°C"],
279
- ["State.VoltOut", "state", "Output Voltage", "number", "value.voltage", true, false, "V"],
280
- ["System.ErrorNum", "state", "Error (numeric)", "number", "value", true, false, ""],
281
- //["State.ErrorNum", "state", "Error (numeric)", "number", "", true, false, ""], // ERROR ERROR ERROR
282
- ["System.ErrorStr", "state", "Error (string)", "string", "text", true, false, ""],
283
- ];
284
-
285
- for (let i = 0; i < myObjects.length; i++) {
286
- adapter.setObjectNotExists(myObjects[i][0], {
287
- type: myObjects[i][1],
288
- common: {
289
- name: myObjects[i][2],
290
- type: myObjects[i][3],
291
- role: myObjects[i][4],
292
- read: myObjects[i][5],
293
- write: myObjects[i][6],
294
- unit: myObjects[i][7], //works only for new objects, so check later for existing objects
295
- },
296
- native: {}
297
- });
298
- }
299
- //repair forgotten units in first version and required roles
300
- for (let i = 0; i < myObjects.length; i++) {
301
- //console.log("****extend " + i + " " + myObjects[i][0] + " " + myObjects[i][7]);
302
- checkandrepairUnit(myObjects[i][0], myObjects[i][7], myObjects[i][4]);
303
- }
304
- }
305
-
306
- /* setTimeout(() => {
307
- adapter.log.error("deleting State State.ErrorNum");
308
- adapter.deleteState("State.ErrorNum", "", function (err, obj) {
309
- adapter.log.error("callback deletestate called: " + err + " " + obj);
310
- });
311
- }, 4000);*/
312
- //changeErrorNum(); //not a really good idea but I do not know how to delete -- did not work :-(
313
-
314
-
315
-
316
- /*async function changeErrorNum() {
317
- //did not work, this part created a state with "getObjectAsync"
318
- try {
319
- const obj = await adapter.getObjectAsync("State.ErrorNum");
320
- adapter.extendObject("State.ErrorNum", { common: { type: "string", name: "deprecated" } });
321
- setTimeout(() => {
322
- adapter.setState("State.ErrorNum", "moved to System.ErrorNum");
323
- }, 4000);
324
- }
325
- catch (err) {
326
- //dann eben nicht.
327
- }
328
- }*/
329
-
330
-
331
- async function checkandrepairUnit(id, NewUnit, NewRole) {
332
- //want to test and understand async and await, so it's introduced here.
333
- //check for forgotten unit in first version and if it's missing add unit.
334
- try {
335
- const obj = await adapter.getObjectAsync(id);
336
- if (NewUnit != "") {
337
- if (obj.common.unit != NewUnit) {
338
- adapter.extendObject(id, { common: { unit: NewUnit } });
339
- }
340
- }
341
- if (obj.common.role == "") {
342
- adapter.extendObject(id, { common: { role: NewRole } });
343
- }
344
- }
345
- catch (err) {
346
- //dann eben nicht.
347
- }
348
- }
349
-
350
- function checkPacket(data) {
351
- const byteArray = new Uint8Array(data);
352
- const packetLength = data[2] + 5;// 3 header, 2 crc
353
- if (byteArray[0] != 1) { return false; }
354
- if (byteArray[1] === 3) { //habe die Kodierung der Antwort mit 1 an zweiter Stelle nicht verstanden, daher hier keine Längenprüfung
355
- if (packetLength != byteArray.length) {
356
- return (false);
357
- }
358
- } else {
359
- if (byteArray[1] != 16) { return false; }
360
- }
361
- return (crc.crc16modbus(byteArray) === 0);
362
- }
363
-
364
- function pad(n, width, z) {
365
- z = z || "0";
366
- n = n + "";
367
- return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
368
- }
369
-
370
- function buf2int16SI(byteArray, pos) { //signed
371
- let result = 0;
372
- result = byteArray[pos] * 256 + byteArray[pos + 1];
373
- if (result > 32768) {
374
- result -= 65536;
375
- }
376
- return result;
377
- }
378
-
379
- function buf2int16US(byteArray, pos) { //unsigned
380
- let result = 0;
381
- result = byteArray[pos] * 256 + byteArray[pos + 1];
382
- return result;
383
- }
384
-
385
- function decodePacket1(data) {
386
- const byteArray = new Uint8Array(data);
387
- hvsSerial = "";
388
- for (let i = 3; i < 22; i++) {
389
- hvsSerial += String.fromCharCode(byteArray[i]);
390
- }
391
- hvsBMUA = "V" + byteArray[27].toString() + "." + byteArray[28].toString();
392
- hvsBMUB = "V" + byteArray[29].toString() + "." + byteArray[30].toString();
393
- if (byteArray[33] === 0) {
394
- hvsBMU = hvsBMUA + "-A";
395
- } else {
396
- hvsBMU = hvsBMUB + "-B";
397
- }
398
- hvsBMS = "V" + byteArray[31].toString() + "." + byteArray[32].toString() + "-" + String.fromCharCode(byteArray[34] + 65);
399
- hvsModules = parseInt((byteArray[36] - 16).toString());
400
- if (byteArray[38] === 1) {
401
- hvsGrid = "OnGrid";
402
- } else {
403
- hvsGrid = "OffGrid";
404
- }
405
- /* if ((ConfBatDetails) && (hvsModules > 2)) {
406
- adapter.log.error("Sorry, Details at the moment only for two modules. I need a wireshark dump from bigger systems to adjust the adapter.");
407
- ConfBatDetails = false;
408
- }*/
409
- }
410
-
411
- function decodePacket2(data) {
412
- const byteArray = new Uint8Array(data);
413
- hvsSOC = buf2int16SI(byteArray, 3);
414
- hvsMaxVolt = parseFloat((buf2int16SI(byteArray, 5) * 1.0 / 100.0).toFixed(2));
415
- hvsMinVolt = parseFloat((buf2int16SI(byteArray, 7) * 1.0 / 100.0).toFixed(2));
416
- hvsA = parseFloat((buf2int16SI(byteArray, 11) * 1.0 / 10.0).toFixed(1));
417
- hvsBattVolt = parseFloat((buf2int16US(byteArray, 13) * 1.0 / 100.0).toFixed(1));
418
- hvsMaxTemp = buf2int16SI(byteArray, 15);
419
- hvsMinTemp = buf2int16SI(byteArray, 17);
420
- hvsBatTemp = buf2int16SI(byteArray, 19);
421
- hvsError = buf2int16SI(byteArray, 29);
422
- hvsParamT = byteArray[31].toString() + "." + byteArray[32].toString();
423
- hvsOutVolt = parseFloat((buf2int16US(byteArray, 35) * 1.0 / 100.0).toFixed(1));
424
- hvsPower = Math.round((hvsA * hvsOutVolt) * 100) / 100;
425
- hvsDiffVolt = Math.round((hvsMaxVolt - hvsMinVolt) * 100) / 100;
426
- hvsErrorString = "";
427
- // hvsError = 65535;
428
- for (let j = 0; j < 16; j++) {
429
- if (((1 << j) & hvsError) !== 0) {
430
- if (hvsErrorString.length > 0) {
431
- hvsErrorString += "; ";
432
- }
433
- hvsErrorString += myErrors[j];
434
- }
435
- }
436
- if (hvsErrorString.length === 0) { hvsErrorString = "no Error"; }
437
- }
438
-
439
- function decodePacketNOP(data) {
440
- adapter.log.silly("Packet NOP");
441
- }
442
-
443
- function decodePacket3(data) {
444
- const byteArray = new Uint8Array(data);
445
- hvsBattType = byteArray[5];
446
- hvsInvType = byteArray[3];
447
- hvsNumCells = 0;
448
- hvsNumTemps = 0;
449
- switch (hvsBattType) {
450
- case 0: //HVL -> unknown specification, so 0 cells and 0 temps
451
- //hvsNumCells = 0;
452
- //hvsNumTemps = 0;
453
- //see above, is default
454
- break;
455
- case 1: //HVM 16 Cells per module
456
- hvsNumCells = hvsModules * 16;
457
- hvsNumTemps = hvsModules * 8;
458
- break;
459
- //crosscheck
460
- // 5 modules, 80 voltages, 40 temps
461
- case 2: //HVS 32 cells per module
462
- hvsNumCells = hvsModules * 32;
463
- hvsNumTemps = hvsModules * 12;
464
- break;
465
- //crosscheck:
466
- //Counts from real data:
467
- //mine: 2 modules, 64 voltages, 24 temps
468
- //4 modules, 128 voltages, 48 temps
469
- }
470
- if (hvsNumCells > 128) { hvsNumCells = 128; }
471
- if (hvsNumTemps > 60) { hvsNumTemps = 60; }
472
- if (ConfBatDetails && FirstRun) {
473
- FirstRun = false;
474
- setObjectsCells();
475
- }
476
- adapter.log.silly ("NumCells: " + hvsNumCells +" Numtemps: " + hvsNumTemps + " Modules: " + hvsModules);
477
- }
478
-
479
-
480
- function decodePacket6(data) {
481
- const byteArray = new Uint8Array(data);
482
- hvsMaxmVolt = buf2int16SI(byteArray, 5);
483
- hvsMinmVolt = buf2int16SI(byteArray, 7);
484
- hvsMaxmVoltCell = byteArray[9];
485
- hvsMinmVoltCell = byteArray[10];
486
- hvsMaxTempCell = byteArray[15];
487
- hvsMinTempCell = byteArray[16];
488
-
489
- //starting with byte 101, ending with 131, Cell voltage 1-16
490
- const MaxCells = 16;
491
- for (let i = 0; i < MaxCells; i++) {
492
- adapter.log.silly("Battery Voltage-" + pad((i + 1), 3) + " :" + buf2int16SI(byteArray, i * 2 + 101));
493
- hvsBatteryVoltsperCell[i + 1] = buf2int16SI(byteArray, i * 2 + 101);
494
- }
495
- }
496
-
497
- function decodePacket7(data) {
498
- const byteArray = new Uint8Array(data);
499
- // e.g. hvsNumCells = 80
500
- // first Voltage in byte 5+6
501
- // Count = 80-17 --> 63
502
- let MaxCells = hvsNumCells - 16; //0 to n-1 is the same like 1 to n
503
- if (MaxCells > 64) { MaxCells = 64; }
504
- for (let i = 0; i < MaxCells; i++) {
505
- adapter.log.silly("Battery Voltage-" + pad((i + 17), 3) + " :" + buf2int16SI(byteArray, i * 2 + 5));
506
- hvsBatteryVoltsperCell[i + 17] = buf2int16SI(byteArray, i * 2 + 5);
507
- }
508
- }
509
-
510
- function decodePacket8(data) {
511
- const byteArray = new Uint8Array(data);
512
- //starting with byte 5, ending 101, voltage for cell 81 to 128
513
- //starting with byte 103, ending 132, temp for cell 1 to 30
514
-
515
- // e.g. hvsNumCells = 128
516
- // first Voltage in byte 5+6
517
- // Count = 128-80 --> 48
518
- let MaxCells = hvsNumCells - 80; //0 to n-1 is the same like 1 to n
519
- if (MaxCells > 48) { MaxCells = 48; }
520
- adapter.log.silly("hvsModules =" + hvsModules + " maxCells= " + MaxCells);
521
- for (let i = 0; i < MaxCells; i++) {
522
- adapter.log.silly("Battery Voltage-" + pad((i + 81), 3) + " :" + buf2int16SI(byteArray, i * 2 + 5));
523
- hvsBatteryVoltsperCell[i + 81] = buf2int16SI(byteArray, i * 2 + 5);
524
- }
525
-
526
- let MaxTemps = hvsNumTemps - 0; //0 to n-1 is the same like 1 to n
527
- if (MaxTemps > 30) { MaxTemps = 30; }
528
- adapter.log.silly("hvsModules =" + hvsModules + " MaxTemps= " + MaxTemps);
529
- for (let i = 0; i < MaxTemps; i++) {
530
- adapter.log.silly("Battery Temp " + pad(i + 1, 3) + " :" + byteArray[i + 103]);
531
- hvsBatteryTempperCell[i + 1] = byteArray[i + 103];
532
- }
533
- }
534
-
535
- function decodePacket9(data) {
536
- const byteArray = new Uint8Array(data);
537
- let MaxTemps = hvsNumTemps - 30; //0 to n-1 is the same like 1 to n
538
- if (MaxTemps > 30) { MaxTemps = 30; }
539
- adapter.log.silly("hvsModules =" + hvsModules + " MaxTemps= " + MaxTemps);
540
- for (let i = 0; i < MaxTemps; i++) {
541
- adapter.log.silly("Battery Temp " + pad(i + 31, 3) + " :" + byteArray[i + 5]);
542
- hvsBatteryTempperCell[i + 31] = byteArray[i + 5];
543
- }
544
- }
545
-
546
- function setConnected(adapter, isConnected) {
547
- if (adapter._connected !== isConnected) {
548
- adapter._connected = isConnected;
549
- adapter.setState("info.connection", adapter._connected, true, err =>
550
- // analyse if the state could be set (because of permissions)
551
- err ? adapter.log.error("Can not update adapter._connected state: " + err) :
552
- adapter.log.debug("connected set to " + adapter._connected));
553
- }
554
- }
555
-
556
-
557
- function setStates() {
558
-
559
- adapter.log.silly("hvsSerial >" + hvsSerial + "<");
560
- adapter.log.silly("hvsBMU >" + hvsBMU + "<");
561
- adapter.log.silly("hvsBMUA >" + hvsBMUA + "<");
562
- adapter.log.silly("hvsBMUB >" + hvsBMUB + "<");
563
- adapter.log.silly("hvsBMS >" + hvsBMS + "<");
564
- adapter.log.silly("hvsModules >" + hvsModules + "<");
565
- adapter.log.silly("hvsGrid >" + hvsGrid + "<");
566
- adapter.log.silly("hvsSOC >" + hvsSOC + "<");
567
- adapter.log.silly("hvsMaxVolt >" + hvsMaxVolt + "<");
568
- adapter.log.silly("hvsMinVolt >" + hvsMinVolt + "<");
569
- adapter.log.silly("hvsA >" + hvsA + "<");
570
- adapter.log.silly("hvsBattVolt >" + hvsBattVolt + "<");
571
- adapter.log.silly("hvsMaxTemp >" + hvsMaxTemp + "<");
572
- adapter.log.silly("hvsMinTemp >" + hvsMinTemp + "<");
573
- adapter.log.silly("hvsDiffVolt >" + hvsDiffVolt + "<");
574
- adapter.log.silly("hvsPower >" + hvsPower + "<");
575
- adapter.log.silly("hvsParamT >" + hvsParamT + "<");
576
- adapter.log.silly("hvsBatTemp >" + hvsBatTemp + "<");
577
- adapter.log.silly("hvsOutVolt >" + hvsOutVolt + "<");
578
- adapter.log.silly("hvsError >" + hvsError + "<");
579
- adapter.log.silly("hvsErrorStr >" + hvsErrorString + "<");
580
-
581
- adapter.setState("System.Serial", hvsSerial, true);
582
- adapter.setState("System.BMU", hvsBMU, true);
583
- adapter.setState("System.BMUBankA", hvsBMUA, true);
584
- adapter.setState("System.BMUBankB", hvsBMUB, true);
585
- adapter.setState("System.BMS", hvsBMS, true);
586
- adapter.setState("System.Modules", hvsModules, true);
587
- adapter.setState("System.Grid", hvsGrid, true);
588
- adapter.setState("State.SOC", hvsSOC, true);
589
- adapter.setState("State.VoltMax", hvsMaxVolt, true);
590
- adapter.setState("State.VoltMin", hvsMinVolt, true);
591
- adapter.setState("State.Current", hvsA, true);
592
- adapter.setState("State.VoltBatt", hvsBattVolt, true);
593
- adapter.setState("State.TempMax", hvsMaxTemp, true);
594
- adapter.setState("State.TempMin", hvsMinTemp, true);
595
- adapter.setState("State.VoltDiff", hvsDiffVolt, true);
596
- adapter.setState("State.Power", hvsPower, true /*ack*/);
597
- adapter.setState("System.ParamT", hvsParamT, true);
598
- adapter.setState("State.TempBatt", hvsBatTemp, true);
599
- adapter.setState("State.VoltOut", hvsOutVolt, true);
600
- adapter.setState("System.ErrorNum", hvsError, true);
601
- adapter.setState("System.ErrorStr", hvsErrorString, true);
602
- if (hvsPower >= 0) {
603
- adapter.setState("State.Power_Consumption", hvsPower, true);
604
- adapter.setState("State.Power_Delivery", 0, true);
605
- } else {
606
- adapter.setState("State.Power_Consumption", 0, true);
607
- adapter.setState("State.Power_Delivery", -hvsPower, true);
608
- }
609
- adapter.setState("System.BattType", myBattTypes[hvsBattType], true);
610
- adapter.setState("System.InvType", myINVs[hvsInvType], true);
611
-
612
- if (myNumberforDetails == 0) {
613
- adapter.setState("Diagnosis.mVoltMax", hvsMaxmVolt, true);
614
- adapter.setState("Diagnosis.mVoltMin", hvsMinmVolt, true);
615
- adapter.setState("Diagnosis.mVoltMaxCell", hvsMaxmVoltCell, true);
616
- adapter.setState("Diagnosis.mVoltMinCell", hvsMinmVoltCell, true);
617
- adapter.setState("Diagnosis.TempMaxCell", hvsMaxTempCell, true);
618
- adapter.setState("Diagnosis.TempMinCell", hvsMinTempCell, true);
619
-
620
- for (let i = 1; i <= hvsNumCells; i++) {
621
- adapter.setState("CellDetails.CellVolt" + pad(i, 3), hvsBatteryVoltsperCell[i], true);
622
- }
623
- for (let i = 1; i <= hvsNumTemps; i++) {
624
- adapter.setState("CellDetails.CellTemp" + pad(i, 3), hvsBatteryTempperCell[i], true);
625
- }
626
- adapter.log.silly("hvsMaxmVolt >" + hvsMaxmVolt + "<");
627
- adapter.log.silly("hvsMinmVolt >" + hvsMinmVolt + "<");
628
- adapter.log.silly("hvsMaxmVoltCell >" + hvsMaxmVoltCell + "<");
629
- adapter.log.silly("hvsMinmVoltCell >" + hvsMinmVoltCell + "<");
630
- adapter.log.silly("hvsMaxTempCell >" + hvsMaxTempCell + "<");
631
- adapter.log.silly("hvsMinTempCell >" + hvsMinTempCell + "<");
632
- }
633
-
634
- }
635
-
636
- function startPoll(adapter) {
637
- //erster Start sofort (500ms), dann entsprechend der Config - dann muss man nicht beim Entwickeln warten bis der erste Timer durch ist.
638
- FirstRun = true;
639
- idTimeout1 = setTimeout(() => { Poll(adapter); }, 500);
640
- idInterval1 = setInterval(() => Poll(adapter), confBatPollTime * 1000);
641
- adapter.log.info("gestartet: " + adapter.config.ConfPollInterval + " " + idInterval1);
642
- }
643
-
644
- function stopPoll() {
645
- idInterval1 && clearInterval(idInterval1);
646
- }
647
-
648
- IPClient.on("data", function (data) {
649
- adapter.log.silly("Received, State: " + myState + " Data: " + data.toString("hex"));
650
- if (ConfTestMode) {
651
- const PacketNumber = myState - 1;
652
- adapter.log.error("Received, Packet: " + PacketNumber + " Data: " + data.toString("hex"));
653
- }
654
- if (checkPacket(data) == false) {
655
- adapter.log.error("error: no valid data");
656
- IPClient.destroy();
657
- setConnected(adapter, false);
658
- myState = 0;
659
- }
660
- setConnected(adapter, true);
661
- switch (myState) {
662
- case 2:
663
- decodePacket1(data);
664
- IPClient.setTimeout(1000);
665
- setTimeout(() => {
666
- myState = 3;
667
- IPClient.write(myRequests[1]);
668
- }, 200);
669
- break;
670
- case 3:
671
- decodePacket2(data);
672
- IPClient.setTimeout(1000);
673
- setTimeout(() => {
674
- myState = 4;
675
- IPClient.write(myRequests[2]);
676
- }, 200);
677
- break;
678
- case 4: //test if it is time for reading all data. If not stop here
679
- decodePacket3(data);
680
- if ((myNumberforDetails < ConfBatDetailshowoften) || (ConfBatDetails == false)) {
681
- setStates();
682
- IPClient.destroy();
683
- myState = 0;
684
- } else {
685
- myNumberforDetails = 0; //restart counting
686
- IPClient.setTimeout(1000);
687
- setTimeout(() => {
688
- myState = 5;
689
- IPClient.write(myRequests[3]);
690
- }, 200);
691
- }
692
- break;
693
- case 5:
694
- decodePacketNOP(data);
695
- IPClient.setTimeout(8000);
696
- myState = 6;
697
- adapter.log.silly("waiting 4 seconds to measure cells");
698
- setTimeout(() => {
699
- IPClient.write(myRequests[4]);
700
- }, 4000);
701
- break;
702
- case 6:
703
- decodePacketNOP(data);
704
- IPClient.setTimeout(1000);
705
- myState = 7;
706
- setTimeout(() => {
707
- IPClient.write(myRequests[5]);
708
- }, 200);
709
- break;
710
- case 7:
711
- decodePacket6(data);
712
- IPClient.setTimeout(1000);
713
- setTimeout(() => {
714
- myState = 8;
715
- IPClient.write(myRequests[6]);
716
- }, 200);
717
- break;
718
- case 8:
719
- decodePacket7(data);
720
- IPClient.setTimeout(1000);
721
- setTimeout(() => {
722
- myState = 9;
723
- IPClient.write(myRequests[7]);
724
- }, 200);
725
- break;
726
- case 9:
727
- decodePacket8(data);
728
- IPClient.setTimeout(1000);
729
- setTimeout(() => {
730
- myState = 10;
731
- IPClient.write(myRequests[8]);
732
- }, 200);
733
- break;
734
- case 10:
735
- decodePacket9(data);
736
- setStates();
737
- IPClient.destroy();
738
- myState = 0;
739
- break;
740
- default:
741
- IPClient.destroy();
742
- }
743
- });
744
-
745
-
746
- IPClient.on("timeout", function () {
747
- IPClient.destroy();
748
- setConnected(adapter, false);
749
- myState = 0;
750
- adapter.log.error("no connection to IP: " + adapter.config.ConfIPAdress);
751
- });
752
-
753
- IPClient.on("error", function () {
754
- IPClient.destroy();
755
- setConnected(adapter, false);
756
- myState = 0;
757
- adapter.log.error("Error connecting to " + adapter.config.ConfIPAdress);
758
- });
759
-
760
-
761
- function Poll(adapter) {
762
- myState = 1;
763
- IPClient.setTimeout(1000);
764
- myNumberforDetails += 1;
765
- adapter.log.silly("myNumberforDetails:" + myNumberforDetails);
766
- adapter.log.silly("Poll start, IP:" + adapter.config.ConfIPAdress);
767
- IPClient.connect(8080, adapter.config.ConfIPAdress, function () {
768
- myState = 2;
769
- setConnected(adapter, true);
770
- IPClient.write(myRequests[0]);
771
- });
772
- }
773
-
774
- async function main() {
775
-
776
- // Reset the connection indicator during startup
777
- // await this.setStateAsync("info.connection", false, true);
778
- setConnected(adapter, false);
779
- setObjects();
780
- myState = 0;
781
-
782
- // The adapters config (in the instance object everything under the attribute "native") is accessible via
783
- // adapter.config:
784
- adapter.log.info("Poll Interval: " + adapter.config.ConfPollInterval);
785
- confBatPollTime = parseInt(adapter.config.ConfPollInterval);
786
- if (confBatPollTime < 60) {
787
- confBatPollTime = 60;
788
- adapter.log.error("polling to often - max once per minute ");
789
- }
790
- adapter.log.info("BYD IP Adress: " + adapter.config.ConfIPAdress);
791
- ConfBatDetails = (adapter.config.ConfBatDetails ? true : false);
792
- adapter.log.info("Bat Details : " + adapter.config.ConfBatDetails);
793
- ConfBatDetailshowoften = parseInt(adapter.config.ConfDetailshowoften);
794
- if (ConfBatDetailshowoften < 10) {
795
- ConfBatDetails = false;
796
- adapter.log.error("Details polling to often - disabling ");
797
- }
798
- ConfTestMode = (adapter.config.ConfTestMode ? true : false);
799
- adapter.log.info("BatDetailshowoften: " + ConfBatDetailshowoften);
800
- adapter.log.silly("TestMode= " + ConfTestMode);
801
- myNumberforDetails = ConfBatDetailshowoften;
802
- // adapter.config.ConfPollInterval = parseInt(adapter.config.ConfPollInterval, 10) || 60;
803
-
804
- adapter.log.info("starte poll");
805
- startPoll(adapter);
806
-
807
- // examples for the checkPassword/checkGroup functions
808
- /* adapter.checkPassword("admin", "iobroker", (res) => {
809
- adapter.log.info("check user admin pw iobroker: " + res);
810
- });
811
- adapter.checkGroup("admin", "admin", (res) => {
812
- adapter.log.info("check group user admin group admin: " + res);
813
- });*/
814
- }
815
-
816
- // @ts-ignore parent is a valid property on module
817
- if (module.parent) {
818
- // Export startAdapter in compact mode
819
- module.exports = startAdapter;
820
- } else {
821
- // otherwise start the instance directly
822
- startAdapter();
823
- }
1
+ "use strict";
2
+
3
+ /*
4
+ * Created with @iobroker/create-adapter v1.31.0
5
+ */
6
+
7
+ // battery icon from
8
+ // https://freepsdfiles.net/graphics/battery-icon-psd
9
+
10
+ // The adapter-core module gives you access to the core ioBroker functions
11
+ // you need to create an adapter
12
+ const utils = require("@iobroker/adapter-core"); // Get common adapter utils
13
+ const crc = require("crc");
14
+ //const ioBLib = require('strathcole/iob-lib').ioBLib;
15
+ const net = require("net");
16
+ const IPClient = new net.Socket();
17
+
18
+
19
+ // Load your modules here, e.g.:
20
+ // const fs = require("fs");
21
+
22
+ /**
23
+ * The adapter instance
24
+ * @type {ioBroker.Adapter}
25
+ */
26
+ let adapter;
27
+ const hvsBatteryVoltsperCell = [];
28
+ const hvsBatteryTempperCell = [];
29
+ // globale Variablen
30
+ /** @type {number | any } */
31
+ let myState; // Aktueller Status
32
+ let hvsSOC;
33
+ let hvsSOCDiagnosis;
34
+ let hvsMaxVolt;
35
+ let hvsMinVolt;
36
+ let hvsSOH;
37
+ let hvsMaxmVolt;
38
+ let hvsMinmVolt;
39
+ let hvsMaxmVoltCell;
40
+ let hvsMinmVoltCell;
41
+ let hvsA;
42
+ let hvsBattVolt;
43
+ let hvsMaxTemp;
44
+ let hvsMinTemp;
45
+ let hvsMaxTempCell;
46
+ let hvsMinTempCell;
47
+ let hvsBatTemp;
48
+ let hvsOutVolt;
49
+ let hvsError;
50
+ let hvsModules;
51
+ let hvsDiffVolt;
52
+ let hvsPower;
53
+ let hvsBattType;
54
+ let hvsBattType_fromSerial;
55
+ let hvsInvType;
56
+ let hvsNumCells; //number of cells in system
57
+ let hvsNumTemps; // number of temperatures to count with
58
+ let ConfBatDetailshowoften;
59
+ let confBatPollTime;
60
+ let myNumberforDetails;
61
+ let ConfTestMode;
62
+ let FirstRun;
63
+
64
+
65
+ /** @type {string} */
66
+ let hvsSerial;
67
+ let hvsBMU;
68
+ let hvsBMUA;
69
+ let hvsBMUB;
70
+ let hvsBMS;
71
+ let hvsGrid;
72
+ let hvsErrorString;
73
+ let hvsParamT;
74
+
75
+ /** @type {boolean} */
76
+ let ConfBatDetails;
77
+
78
+ /*const myStates = [
79
+ "no state",
80
+ "waiting for initial connect",
81
+ "waiting for 1st answer",
82
+ "waiting for 2nd answer"
83
+
84
+ ];*/
85
+
86
+
87
+
88
+ /** @type {NodeJS.Timeout} */
89
+ let idInterval1;
90
+ let idTimeout1;
91
+
92
+
93
+ const myRequests = [
94
+ Buffer.from("010300000066c5e0", "hex"), //0
95
+ Buffer.from("01030500001984cc", "hex"), //1
96
+ Buffer.from("010300100003040e", "hex"), //2
97
+ Buffer.from("0110055000020400018100f853", "hex"), //3 start measuring
98
+ Buffer.from("010305510001d517", "hex"), //4
99
+ Buffer.from("01030558004104e5", "hex"), //5
100
+ Buffer.from("01030558004104e5", "hex"), //6
101
+ Buffer.from("01030558004104e5", "hex"), //7
102
+ Buffer.from("01030558004104e5", "hex"), //8
103
+ // to read the 5th module, the box must first be reconfigured
104
+ Buffer.from("01100100000306444542554700176f", "hex"), //9 switch to second turn for the last few cells
105
+ Buffer.from("0110055000020400018100f853", "hex"), //10 start measuring remaining cells (like 3)
106
+ Buffer.from("010305510001d517", "hex"), //11 (like 4)
107
+ Buffer.from("01030558004104e5", "hex"), //12 (like 5)
108
+ Buffer.from("01030558004104e5", "hex"), //13 (like 6)
109
+ // The BYD tool also issues two more requests, probably to gather even more cells in some larger setups
110
+ // Buffer.from("01030558004104e5", "hex"), //14 (like 7)
111
+ // Buffer.from("01030558004104e5", "hex"), //15 (like 8)
112
+ ];
113
+
114
+
115
+ /* Während des Updates des BMS funktioniert das Auslesen offensichtlich nicht, hier die Antworten des Speichers (Seriennummer verfälscht und CRC des ersten Paketes nicht neu berechnet)
116
+ 0103cc503030303030303030303030303030303030307878787878030d030f031401000312020101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000015040c12382b82b2
117
+ 0103320043014a014a0063fff852a80015001400140000030f0000000000000902000252761703000013840000000209020000042c925b
118
+ 010306031202010100c8ad
119
+ 0190044dc3 <- Das scheint eine Fehlercondition zu sein.
120
+ 5 min. später klappte es wieder und dann war auch die neue F/W-Version in der Antwort enthalten
121
+ */
122
+ const myErrors = [
123
+ "High Temperature Charging (Cells)",
124
+ "Low Temperature Charging (Cells)",
125
+ "Over Current Discharging",
126
+ "Over Current Charging",
127
+ "Main circuit Failure",
128
+ "Short Current Alarm",
129
+ "Cells Imbalance",
130
+ "Current Sensor Failure",
131
+ "Battery Over Voltage",
132
+ "Battery Under Voltage",
133
+ "Cell Over Voltage",
134
+ "Cell Under Voltage",
135
+ "Voltage Sensor Failure",
136
+ "Temperature Sensor Failure",
137
+ "High Temperature Discharging (Cells)",
138
+ "Low Temperature Discharging (Cells)"
139
+ ];
140
+
141
+ const myINVs = [
142
+ "Fronius HV",
143
+ "Goodwe HV",
144
+ "Fronius HV",
145
+ "Kostal HV",
146
+ "Goodwe HV",
147
+ "SMA SBS3.7/5.0",
148
+ "Kostal HV",
149
+ "SMA SBS3.7/5.0",
150
+ "Sungrow HV",
151
+ "Sungrow HV",
152
+ "Kaco HV",
153
+ "Kaco HV",
154
+ "Ingeteam HV",
155
+ "Ingeteam HV",
156
+ "SMA SBS 2.5 HV",
157
+ "",
158
+ "SMA SBS 2.5 HV",
159
+ "Fronius HV"
160
+ ];
161
+
162
+ const myINVsLVS = [
163
+ "Fronius HV",
164
+ "Goodwe HV",
165
+ "Goodwe HV",
166
+ "Kostal HV",
167
+ "Selectronic LV",
168
+ "SMA SBS3.7/5.0",
169
+ "SMA LV",
170
+ "Victron LV",
171
+ "Suntech LV",
172
+ "Sungrow HV",
173
+ "Kaco HV",
174
+ "Studer LV",
175
+ "Solar Edge LV",
176
+ "Ingeteam HV",
177
+ "Sungrow LV",
178
+ "Schneider LV",
179
+ "SMA SBS2.5 HV",
180
+ "Solar Edge LV",
181
+ "Solar Edge LV",
182
+ "Solar Edge LV"
183
+ ];
184
+
185
+
186
+ const myBattTypes = [
187
+ "HVL",
188
+ "HVM",
189
+ "HVS"
190
+ ];
191
+ /* HVM: 16 cells per module
192
+ HVS: 32 cells per module
193
+ HVL: unknown so I count 0 cells per module
194
+ */
195
+
196
+ /**
197
+ * Starts the adapter instance
198
+ * @param {Partial<utils.AdapterOptions>} [options]
199
+ */
200
+ function startAdapter(options) {
201
+ // Create the adapter and define its methods
202
+ return adapter = utils.adapter(Object.assign({}, options, {
203
+ name: "bydhvs",
204
+
205
+ // The ready callback is called when databases are connected and adapter received configuration.
206
+ // start here!
207
+ ready: main, // Main method defined below for readability
208
+
209
+ // is called when adapter shuts down - callback has to be called under any circumstances!
210
+ unload: (callback) => {
211
+ adapter.log.silly("got unload event");
212
+ try {
213
+ clearInterval(idInterval1);
214
+ clearTimeout(idTimeout1);
215
+ stopPoll();
216
+ IPClient.destroy();
217
+
218
+ callback();
219
+ } catch (e) {
220
+ callback();
221
+ }
222
+ },
223
+ }));
224
+ }
225
+
226
+
227
+ function setObjectsCells() {
228
+ //Diagnose-data only if necessary.
229
+ const myObjects = [
230
+ ["Diagnosis.mVoltMax", "state", "Max Cell Voltage (mv)", "number", "value.voltage", true, false, "mV"],
231
+ ["Diagnosis.mVoltMin", "state", "Min Cell Voltage (mv)", "number", "value.voltage", true, false, "mV"],
232
+ ["Diagnosis.mVoltMaxCell", "state", "Max Cell Volt (Cellnr)", "number", "value.voltage", true, false, ""],
233
+ ["Diagnosis.mVoltMinCell", "state", "Min Cell Volt (Cellnr)", "number", "value.voltage", true, false, ""],
234
+ ["Diagnosis.TempMaxCell", "state", "Max Cell Temp (Cellnr)", "number", "value.temperature", true, false, ""],
235
+ ["Diagnosis.TempMinCell", "state", "Min Cell Temp(Cellnr)", "number", "value.temperature", true, false, ""],
236
+ ["Diagnosis.SOC", "state", "SOC (Diagnosis)", "number", "value.battery", true, false, "%"],
237
+ ];
238
+
239
+ for (let i = 0; i < myObjects.length; i++) {
240
+ adapter.setObjectNotExists(myObjects[i][0], {
241
+ type: myObjects[i][1],
242
+ common: {
243
+ name: myObjects[i][2],
244
+ type: myObjects[i][3],
245
+ role: myObjects[i][4],
246
+ read: myObjects[i][5],
247
+ write: myObjects[i][6],
248
+ unit: myObjects[i][7],
249
+ },
250
+ native: {}
251
+ });
252
+ }
253
+ for (let i = 0; i < myObjects.length; i++) {
254
+ //console.log("****extend " + i + " " + myObjects[i][0] + " " + myObjects[i][7]);
255
+ checkandrepairUnit(myObjects[i][0], myObjects[i][7], myObjects[i][5]);
256
+ }
257
+
258
+
259
+ for (let i = 1; i <= hvsNumCells; i++) {
260
+ adapter.setObjectNotExists("CellDetails.CellVolt" + pad(i, 3), {
261
+ type: "state",
262
+ common: {
263
+ name: "Voltage Cell: " + pad(i, 3),
264
+ type: "number",
265
+ role: "value.voltage",
266
+ read: true,
267
+ write: false,
268
+ unit: "mV"
269
+ },
270
+ native: {}
271
+ });
272
+ checkandrepairUnit("CellDetails.CellVolt" + pad(i, 3), "mV", "value.voltage"); //repair forgotten units in first version
273
+
274
+ for (let i = 1; i <= hvsNumTemps; i++) {
275
+ adapter.setObjectNotExists("CellDetails.CellTemp" + pad(i, 3), {
276
+ type: "state",
277
+ common: {
278
+ name: "Temp Cell: " + pad(i, 3),
279
+ type: "number",
280
+ role: "value.temperature",
281
+ read: true,
282
+ write: false,
283
+ unit: "°C"
284
+ },
285
+ native: {}
286
+ });
287
+ checkandrepairUnit("CellDetails.CellTemp" + pad(i, 3), "°C", "value.temperature"); //repair forgotten units in first version
288
+ }
289
+ }
290
+ }
291
+
292
+ function setObjects() {
293
+ const myObjects = [
294
+ ["System.Serial", "state", "Serial number", "string", "text", true, false, ""],
295
+ ["System.BMU", "state", "F/W BMU", "string", "text", true, false, ""],
296
+ ["System.BMS", "state", "F/W BMS", "string", "text", true, false, ""],
297
+ ["System.BMUBankA", "state", "F/W BMU-BankA", "string", "text", true, false, ""],
298
+ ["System.BMUBankB", "state", "F/W BMU-BankB", "string", "text", true, false, ""],
299
+ ["System.Modules", "state", "modules (count)", "number", "value", true, false, ""],
300
+ ["System.Grid", "state", "Parameter Table", "string", "text", true, false, ""],
301
+ ["System.ParamT", "state", "F/W BMU", "string", "text", true, false, ""],
302
+ ["System.BattType", "state", "Battery Type", "string", "text", true, false, ""],
303
+ ["System.InvType", "state", "Inverter Type", "string", "text", true, false, ""],
304
+ ["State.SOC", "state", "SOC", "number", "value.battery", true, false, "%"],
305
+ ["State.VoltMax", "state", "Max Cell Voltage", "number", "value.voltage", true, false, "V"],
306
+ ["State.VoltMin", "state", "Min Cell Voltage", "number", "value.voltage", true, false, "V"],
307
+ ["State.SOH", "state", "SOH", "number", "value.battery", true, false, "%"],
308
+ ["State.Current", "state", "Charge / Discharge Current", "number", "value.current", true, false, "A"],
309
+ ["State.Power_Consumption", "state", "Discharge Power", "number", "value.power", true, false, "W"],
310
+ ["State.Power_Delivery", "state", "Charge Power", "number", "value.power", true, false, "W"],
311
+ ["State.VoltBatt", "state", "Battery Voltage", "number", "value.voltage", true, false, "V"],
312
+ ["State.TempMax", "state", "Max Cell Temp", "number", "value.temperature", true, false, "°C"],
313
+ ["State.TempMin", "state", "Min Cell Temp", "number", "value.temperature", true, false, "°C"],
314
+ ["State.VoltDiff", "state", "Max - Min Cell Voltage", "number", "value.temperature", true, false, "V"],
315
+ ["State.Power", "state", "Power", "number", "value.power", true, false, "W"],
316
+ ["State.TempBatt", "state", "Battery Temperature", "number", "value.temperature", true, false, "°C"],
317
+ ["State.VoltOut", "state", "Output Voltage", "number", "value.voltage", true, false, "V"],
318
+ ["System.ErrorNum", "state", "Error (numeric)", "number", "value", true, false, ""],
319
+ //["State.ErrorNum", "state", "Error (numeric)", "number", "", true, false, ""], // ERROR ERROR ERROR
320
+ ["System.ErrorStr", "state", "Error (string)", "string", "text", true, false, ""],
321
+ ];
322
+
323
+ for (let i = 0; i < myObjects.length; i++) {
324
+ adapter.setObjectNotExists(myObjects[i][0], {
325
+ type: myObjects[i][1],
326
+ common: {
327
+ name: myObjects[i][2],
328
+ type: myObjects[i][3],
329
+ role: myObjects[i][4],
330
+ read: myObjects[i][5],
331
+ write: myObjects[i][6],
332
+ unit: myObjects[i][7], //works only for new objects, so check later for existing objects
333
+ },
334
+ native: {}
335
+ });
336
+ }
337
+ //repair forgotten units in first version and required roles
338
+ for (let i = 0; i < myObjects.length; i++) {
339
+ //console.log("****extend " + i + " " + myObjects[i][0] + " " + myObjects[i][7]);
340
+ checkandrepairUnit(myObjects[i][0], myObjects[i][7], myObjects[i][4]);
341
+ }
342
+ }
343
+
344
+ /* setTimeout(() => {
345
+ adapter.log.error("deleting State State.ErrorNum");
346
+ adapter.deleteState("State.ErrorNum", "", function (err, obj) {
347
+ adapter.log.error("callback deletestate called: " + err + " " + obj);
348
+ });
349
+ }, 4000);*/
350
+ //changeErrorNum(); //not a really good idea but I do not know how to delete -- did not work :-(
351
+
352
+
353
+
354
+ /*async function changeErrorNum() {
355
+ //did not work, this part created a state with "getObjectAsync"
356
+ try {
357
+ const obj = await adapter.getObjectAsync("State.ErrorNum");
358
+ adapter.extendObject("State.ErrorNum", { common: { type: "string", name: "deprecated" } });
359
+ setTimeout(() => {
360
+ adapter.setState("State.ErrorNum", "moved to System.ErrorNum");
361
+ }, 4000);
362
+ }
363
+ catch (err) {
364
+ //dann eben nicht.
365
+ }
366
+ }*/
367
+
368
+
369
+ async function checkandrepairUnit(id, NewUnit, NewRole) {
370
+ //want to test and understand async and await, so it's introduced here.
371
+ //check for forgotten unit in first version and if it's missing add unit.
372
+ try {
373
+ const obj = await adapter.getObjectAsync(id);
374
+ if (NewUnit != "") {
375
+ if (obj.common.unit != NewUnit) {
376
+ adapter.extendObject(id, { common: { unit: NewUnit } });
377
+ }
378
+ }
379
+ if (obj.common.role == "") {
380
+ adapter.extendObject(id, { common: { role: NewRole } });
381
+ }
382
+ }
383
+ catch (err) {
384
+ //dann eben nicht.
385
+ }
386
+ }
387
+
388
+ function checkPacket(data) {
389
+ const byteArray = new Uint8Array(data);
390
+ const packetLength = data[2] + 5;// 3 header, 2 crc
391
+ if (byteArray[0] != 1) { return false; }
392
+ if (byteArray[1] === 3) { //habe die Kodierung der Antwort mit 1 an zweiter Stelle nicht verstanden, daher hier keine Längenprüfung
393
+ if (packetLength != byteArray.length) {
394
+ return (false);
395
+ }
396
+ } else {
397
+ if (byteArray[1] != 16) { return false; }
398
+ }
399
+ return (crc.crc16modbus(byteArray) === 0);
400
+ }
401
+
402
+ function pad(n, width, z) {
403
+ z = z || "0";
404
+ n = n + "";
405
+ return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
406
+ }
407
+
408
+ function buf2int16SI(byteArray, pos) { //signed
409
+ let result = 0;
410
+ result = byteArray[pos] * 256 + byteArray[pos + 1];
411
+ if (result > 32768) {
412
+ result -= 65536;
413
+ }
414
+ return result;
415
+ }
416
+
417
+ function buf2int16US(byteArray, pos) { //unsigned
418
+ let result = 0;
419
+ result = byteArray[pos] * 256 + byteArray[pos + 1];
420
+ return result;
421
+ }
422
+
423
+ function decodePacket0(data) {
424
+ const byteArray = new Uint8Array(data);
425
+ hvsSerial = "";
426
+ for (let i = 3; i < 22; i++) {
427
+ hvsSerial += String.fromCharCode(byteArray[i]);
428
+ }
429
+ //leider dazugestrickt, wollte in die andere Logik nicht eingreifen
430
+ if (byteArray[5] == 51 ) {hvsBattType_fromSerial = "HVS";}
431
+ if (byteArray[5] == 50 ) {hvsBattType_fromSerial = "LVS";}
432
+ if (byteArray[5] == 49 ) {hvsBattType_fromSerial = "LVS";}
433
+ hvsBMUA = "V" + byteArray[27].toString() + "." + byteArray[28].toString();
434
+ hvsBMUB = "V" + byteArray[29].toString() + "." + byteArray[30].toString();
435
+ if (byteArray[33] === 0) {
436
+ hvsBMU = hvsBMUA + "-A";
437
+ } else {
438
+ hvsBMU = hvsBMUB + "-B";
439
+ }
440
+ hvsBMS = "V" + byteArray[31].toString() + "." + byteArray[32].toString() + "-" + String.fromCharCode(byteArray[34] + 65);
441
+ hvsModules = parseInt((byteArray[36] - 16).toString());
442
+ if (byteArray[38] === 1) {
443
+ hvsGrid = "OnGrid";
444
+ } else {
445
+ hvsGrid = "OffGrid";
446
+ }
447
+ /* if ((ConfBatDetails) && (hvsModules > 2)) {
448
+ adapter.log.error("Sorry, Details at the moment only for two modules. I need a wireshark dump from bigger systems to adjust the adapter.");
449
+ ConfBatDetails = false;
450
+ }*/
451
+ }
452
+
453
+ function decodePacket1(data) {
454
+ const byteArray = new Uint8Array(data);
455
+ hvsSOC = buf2int16SI(byteArray, 3);
456
+ hvsMaxVolt = parseFloat((buf2int16SI(byteArray, 5) * 1.0 / 100.0).toFixed(2));
457
+ hvsMinVolt = parseFloat((buf2int16SI(byteArray, 7) * 1.0 / 100.0).toFixed(2));
458
+ hvsSOH = buf2int16SI(byteArray, 9);
459
+ hvsA = parseFloat((buf2int16SI(byteArray, 11) * 1.0 / 10.0).toFixed(1));
460
+ hvsBattVolt = parseFloat((buf2int16US(byteArray, 13) * 1.0 / 100.0).toFixed(1));
461
+ hvsMaxTemp = buf2int16SI(byteArray, 15);
462
+ hvsMinTemp = buf2int16SI(byteArray, 17);
463
+ hvsBatTemp = buf2int16SI(byteArray, 19);
464
+ hvsError = buf2int16SI(byteArray, 29);
465
+ hvsParamT = byteArray[31].toString() + "." + byteArray[32].toString();
466
+ hvsOutVolt = parseFloat((buf2int16US(byteArray, 35) * 1.0 / 100.0).toFixed(1));
467
+ hvsPower = Math.round((hvsA * hvsOutVolt) * 100) / 100;
468
+ hvsDiffVolt = Math.round((hvsMaxVolt - hvsMinVolt) * 100) / 100;
469
+ hvsErrorString = "";
470
+ // hvsError = 65535;
471
+ for (let j = 0; j < 16; j++) {
472
+ if (((1 << j) & hvsError) !== 0) {
473
+ if (hvsErrorString.length > 0) {
474
+ hvsErrorString += "; ";
475
+ }
476
+ hvsErrorString += myErrors[j];
477
+ }
478
+ }
479
+ if (hvsErrorString.length === 0) { hvsErrorString = "no Error"; }
480
+ }
481
+
482
+ function decodePacketNOP(data) {
483
+ adapter.log.silly("Packet NOP");
484
+ }
485
+
486
+ function decodePacket2(data) {
487
+ const byteArray = new Uint8Array(data);
488
+ hvsBattType = byteArray[5];
489
+ hvsInvType = byteArray[3];
490
+ hvsNumCells = 0;
491
+ hvsNumTemps = 0;
492
+ switch (hvsBattType) {
493
+ case 0: //HVL -> unknown specification, so 0 cells and 0 temps
494
+ //hvsNumCells = 0;
495
+ //hvsNumTemps = 0;
496
+ //see above, is default
497
+ break;
498
+ case 1: //HVM 16 Cells per module
499
+ hvsNumCells = hvsModules * 16;
500
+ hvsNumTemps = hvsModules * 8;
501
+ break;
502
+ //crosscheck
503
+ // 5 modules, 80 voltages, 40 temps
504
+ case 2: //HVS 32 cells per module
505
+ hvsNumCells = hvsModules * 32;
506
+ hvsNumTemps = hvsModules * 12;
507
+ break;
508
+ //crosscheck:
509
+ //Counts from real data:
510
+ //mine: 2 modules, 64 voltages, 24 temps
511
+ //4 modules, 128 voltages, 48 temps
512
+ }
513
+ //leider hässlich dazugestrickt, wollte in die andere Logik nicht eingreifen
514
+ if (hvsBattType_fromSerial == "LVS") {
515
+ hvsBattType = "LVS";
516
+ hvsNumCells = hvsModules * 7;
517
+ hvsNumTemps = 0;
518
+ }
519
+ if (hvsNumCells > 160) { hvsNumCells = 160; }
520
+ if (hvsNumTemps > 64) { hvsNumTemps = 64; }
521
+ if (ConfBatDetails && FirstRun) {
522
+ FirstRun = false;
523
+ setObjectsCells();
524
+ }
525
+ adapter.log.silly ("NumCells: " + hvsNumCells +" Numtemps: " + hvsNumTemps + " Modules: " + hvsModules);
526
+ }
527
+
528
+
529
+ function decodePacket5(data) {
530
+ const byteArray = new Uint8Array(data);
531
+ hvsMaxmVolt = buf2int16SI(byteArray, 5);
532
+ hvsMinmVolt = buf2int16SI(byteArray, 7);
533
+ hvsMaxmVoltCell = byteArray[9];
534
+ hvsMinmVoltCell = byteArray[10];
535
+ hvsMaxTempCell = byteArray[15];
536
+ hvsMinTempCell = byteArray[16];
537
+ hvsSOCDiagnosis = parseFloat((buf2int16SI(byteArray, 53) * 1.0 / 10.0).toFixed(1));
538
+
539
+ //starting with byte 101, ending with 131, Cell voltage 1-16
540
+ const MaxCells = 16;
541
+ for (let i = 0; i < MaxCells; i++) {
542
+ adapter.log.silly("Battery Voltage-" + pad((i + 1), 3) + " :" + buf2int16SI(byteArray, i * 2 + 101));
543
+ hvsBatteryVoltsperCell[i + 1] = buf2int16SI(byteArray, i * 2 + 101);
544
+ }
545
+ }
546
+
547
+ function decodePacket6(data) {
548
+ const byteArray = new Uint8Array(data);
549
+ // e.g. hvsNumCells = 80
550
+ // first Voltage in byte 5+6
551
+ // Count = 80-17 --> 63
552
+ let MaxCells = hvsNumCells - 16; //0 to n-1 is the same like 1 to n
553
+ if (MaxCells > 64) { MaxCells = 64; }
554
+ for (let i = 0; i < MaxCells; i++) {
555
+ adapter.log.silly("Battery Voltage-" + pad((i + 17), 3) + " :" + buf2int16SI(byteArray, i * 2 + 5));
556
+ hvsBatteryVoltsperCell[i + 17] = buf2int16SI(byteArray, i * 2 + 5);
557
+ }
558
+ }
559
+
560
+ function decodePacket7(data) {
561
+ const byteArray = new Uint8Array(data);
562
+ //starting with byte 5, ending 101, voltage for cell 81 to 128
563
+ //starting with byte 103, ending 132, temp for cell 1 to 30
564
+
565
+ // e.g. hvsNumCells = 128
566
+ // first Voltage in byte 5+6
567
+ // Count = 128-80 --> 48
568
+ let MaxCells = hvsNumCells - 80; //0 to n-1 is the same like 1 to n
569
+ if (MaxCells > 48) { MaxCells = 48; }
570
+ adapter.log.silly("hvsModules =" + hvsModules + " maxCells= " + MaxCells);
571
+ for (let i = 0; i < MaxCells; i++) {
572
+ adapter.log.silly("Battery Voltage-" + pad((i + 81), 3) + " :" + buf2int16SI(byteArray, i * 2 + 5));
573
+ hvsBatteryVoltsperCell[i + 81] = buf2int16SI(byteArray, i * 2 + 5);
574
+ }
575
+
576
+ let MaxTemps = hvsNumTemps - 0; //0 to n-1 is the same like 1 to n
577
+ if (MaxTemps > 30) { MaxTemps = 30; }
578
+ adapter.log.silly("hvsModules =" + hvsModules + " MaxTemps= " + MaxTemps);
579
+ for (let i = 0; i < MaxTemps; i++) {
580
+ adapter.log.silly("Battery Temp " + pad(i + 1, 3) + " :" + byteArray[i + 103]);
581
+ hvsBatteryTempperCell[i + 1] = byteArray[i + 103];
582
+ }
583
+ }
584
+
585
+ function decodePacket8(data) {
586
+ const byteArray = new Uint8Array(data);
587
+ let MaxTemps = hvsNumTemps - 30; //0 to n-1 is the same like 1 to n
588
+ if (MaxTemps > 34) { MaxTemps = 34; }
589
+ adapter.log.silly("hvsModules =" + hvsModules + " MaxTemps= " + MaxTemps);
590
+ for (let i = 0; i < MaxTemps; i++) {
591
+ adapter.log.silly("Battery Temp " + pad(i + 31, 3) + " :" + byteArray[i + 5]);
592
+ hvsBatteryTempperCell[i + 31] = byteArray[i + 5];
593
+ }
594
+ }
595
+
596
+ /*
597
+ * decode response to request[12]
598
+ * @see #decodePacket5()
599
+ */
600
+ function decodeResponse12(data) {
601
+ const byteArray = new Uint8Array(data);
602
+ //starting with byte 101, ending with 131, Cell voltage 129-144
603
+ const MaxCells = 16;
604
+ for (let i = 0; i < MaxCells; i++) {
605
+ adapter.log.silly("Battery Voltage-" + pad((i + 1 + 128), 3) + " :" + buf2int16SI(byteArray, i * 2 + 101));
606
+ hvsBatteryVoltsperCell[i + 1 + 128] = buf2int16SI(byteArray, i * 2 + 101);
607
+ }
608
+ }
609
+
610
+ /*
611
+ * decode response to request[13]
612
+ * @see #decodePacket6()
613
+ */
614
+ function decodeResponse13(data) {
615
+ const byteArray = new Uint8Array(data);
616
+ let MaxCells = hvsNumCells - 128 - 16; // The first round measured up to 128 cells, request[12] then get another 16
617
+ if (MaxCells > 16) { MaxCells = 16; } // With 5 HVS Modules, only 16 cells are remaining
618
+ for (let i = 0; i < MaxCells; i++) {
619
+ adapter.log.silly("Battery Voltage-" + pad((i + 1 + 16 + 128), 3) + " :" + buf2int16SI(byteArray, i * 2 + 5));
620
+ hvsBatteryVoltsperCell[i + 1 + 16 + 128] = buf2int16SI(byteArray, i * 2 + 5);
621
+ }
622
+ }
623
+
624
+ function setConnected(adapter, isConnected) {
625
+ if (adapter._connected !== isConnected) {
626
+ adapter._connected = isConnected;
627
+ adapter.setState("info.connection", adapter._connected, true, err =>
628
+ // analyse if the state could be set (because of permissions)
629
+ err ? adapter.log.error("Can not update adapter._connected state: " + err) :
630
+ adapter.log.debug("connected set to " + adapter._connected));
631
+ }
632
+ }
633
+
634
+
635
+ function setStates() {
636
+
637
+ adapter.log.silly("hvsSerial >" + hvsSerial + "<");
638
+ adapter.log.silly("hvsBMU >" + hvsBMU + "<");
639
+ adapter.log.silly("hvsBMUA >" + hvsBMUA + "<");
640
+ adapter.log.silly("hvsBMUB >" + hvsBMUB + "<");
641
+ adapter.log.silly("hvsBMS >" + hvsBMS + "<");
642
+ adapter.log.silly("hvsModules >" + hvsModules + "<");
643
+ adapter.log.silly("hvsGrid >" + hvsGrid + "<");
644
+ adapter.log.silly("hvsSOC >" + hvsSOC + "<");
645
+ adapter.log.silly("hvsMaxVolt >" + hvsMaxVolt + "<");
646
+ adapter.log.silly("hvsMinVolt >" + hvsMinVolt + "<");
647
+ adapter.log.silly("hvsSOH >" + hvsSOH + "<");
648
+ adapter.log.silly("hvsA >" + hvsA + "<");
649
+ adapter.log.silly("hvsBattVolt >" + hvsBattVolt + "<");
650
+ adapter.log.silly("hvsMaxTemp >" + hvsMaxTemp + "<");
651
+ adapter.log.silly("hvsMinTemp >" + hvsMinTemp + "<");
652
+ adapter.log.silly("hvsDiffVolt >" + hvsDiffVolt + "<");
653
+ adapter.log.silly("hvsPower >" + hvsPower + "<");
654
+ adapter.log.silly("hvsParamT >" + hvsParamT + "<");
655
+ adapter.log.silly("hvsBatTemp >" + hvsBatTemp + "<");
656
+ adapter.log.silly("hvsOutVolt >" + hvsOutVolt + "<");
657
+ adapter.log.silly("hvsError >" + hvsError + "<");
658
+ adapter.log.silly("hvsErrorStr >" + hvsErrorString + "<");
659
+ adapter.log.silly("hvsSOC (Diag) >" + hvsSOCDiagnosis + "<");
660
+
661
+ adapter.setState("System.Serial", hvsSerial, true);
662
+ adapter.setState("System.BMU", hvsBMU, true);
663
+ adapter.setState("System.BMUBankA", hvsBMUA, true);
664
+ adapter.setState("System.BMUBankB", hvsBMUB, true);
665
+ adapter.setState("System.BMS", hvsBMS, true);
666
+ adapter.setState("System.Modules", hvsModules, true);
667
+ adapter.setState("System.Grid", hvsGrid, true);
668
+ adapter.setState("State.SOC", hvsSOC, true);
669
+ adapter.setState("State.VoltMax", hvsMaxVolt, true);
670
+ adapter.setState("State.VoltMin", hvsMinVolt, true);
671
+ adapter.setState("State.SOH", hvsSOH, true);
672
+ adapter.setState("State.Current", hvsA, true);
673
+ adapter.setState("State.VoltBatt", hvsBattVolt, true);
674
+ adapter.setState("State.TempMax", hvsMaxTemp, true);
675
+ adapter.setState("State.TempMin", hvsMinTemp, true);
676
+ adapter.setState("State.VoltDiff", hvsDiffVolt, true);
677
+ adapter.setState("State.Power", hvsPower, true /*ack*/);
678
+ adapter.setState("System.ParamT", hvsParamT, true);
679
+ adapter.setState("State.TempBatt", hvsBatTemp, true);
680
+ adapter.setState("State.VoltOut", hvsOutVolt, true);
681
+ adapter.setState("System.ErrorNum", hvsError, true);
682
+ adapter.setState("System.ErrorStr", hvsErrorString, true);
683
+ if (hvsPower >= 0) {
684
+ adapter.setState("State.Power_Consumption", hvsPower, true);
685
+ adapter.setState("State.Power_Delivery", 0, true);
686
+ } else {
687
+ adapter.setState("State.Power_Consumption", 0, true);
688
+ adapter.setState("State.Power_Delivery", -hvsPower, true);
689
+ }
690
+ adapter.setState("System.BattType", myBattTypes[hvsBattType], true);
691
+ if (hvsBattType_fromSerial == "LVS") { //unterschiedliche WR-Tabelle je nach Batt-Typ
692
+ adapter.setState("System.InvType", myINVsLVS[hvsInvType], true);
693
+ } else {
694
+ adapter.setState("System.InvType", myINVs[hvsInvType], true);
695
+ }
696
+ if (myNumberforDetails == 0) {
697
+ adapter.setState("Diagnosis.mVoltMax", hvsMaxmVolt, true);
698
+ adapter.setState("Diagnosis.mVoltMin", hvsMinmVolt, true);
699
+ adapter.setState("Diagnosis.mVoltMaxCell", hvsMaxmVoltCell, true);
700
+ adapter.setState("Diagnosis.mVoltMinCell", hvsMinmVoltCell, true);
701
+ adapter.setState("Diagnosis.TempMaxCell", hvsMaxTempCell, true);
702
+ adapter.setState("Diagnosis.TempMinCell", hvsMinTempCell, true);
703
+ adapter.setState("Diagnosis.SOC", hvsSOCDiagnosis, true);
704
+
705
+ for (let i = 1; i <= hvsNumCells; i++) {
706
+ adapter.setState("CellDetails.CellVolt" + pad(i, 3), hvsBatteryVoltsperCell[i], true);
707
+ }
708
+ for (let i = 1; i <= hvsNumTemps; i++) {
709
+ adapter.setState("CellDetails.CellTemp" + pad(i, 3), hvsBatteryTempperCell[i], true);
710
+ }
711
+ adapter.log.silly("hvsMaxmVolt >" + hvsMaxmVolt + "<");
712
+ adapter.log.silly("hvsMinmVolt >" + hvsMinmVolt + "<");
713
+ adapter.log.silly("hvsMaxmVoltCell >" + hvsMaxmVoltCell + "<");
714
+ adapter.log.silly("hvsMinmVoltCell >" + hvsMinmVoltCell + "<");
715
+ adapter.log.silly("hvsMaxTempCell >" + hvsMaxTempCell + "<");
716
+ adapter.log.silly("hvsMinTempCell >" + hvsMinTempCell + "<");
717
+ }
718
+
719
+ }
720
+
721
+ function startPoll(adapter) {
722
+ //erster Start sofort (500ms), dann entsprechend der Config - dann muss man nicht beim Entwickeln warten bis der erste Timer durch ist.
723
+ FirstRun = true;
724
+ idTimeout1 = setTimeout(() => { Poll(adapter); }, 500);
725
+ idInterval1 = setInterval(() => Poll(adapter), confBatPollTime * 1000);
726
+ adapter.log.info("gestartet: " + adapter.config.ConfPollInterval + " " + idInterval1);
727
+ }
728
+
729
+ function stopPoll() {
730
+ idInterval1 && clearInterval(idInterval1);
731
+ }
732
+
733
+ IPClient.on("data", function (data) {
734
+ adapter.log.silly("Received, State: " + myState + " Data: " + data.toString("hex"));
735
+ if (ConfTestMode) {
736
+ const PacketNumber = myState - 1;
737
+ adapter.log.info("Received, Packet: " + PacketNumber + " Data: " + data.toString("hex"));
738
+ }
739
+ if (checkPacket(data) == false) {
740
+ adapter.log.error("error: no valid data");
741
+ IPClient.destroy();
742
+ setConnected(adapter, false);
743
+ myState = 0;
744
+ }
745
+ setConnected(adapter, true);
746
+ switch (myState) {
747
+ case 2:
748
+ decodePacket0(data); // decode request 0
749
+ IPClient.setTimeout(1000);
750
+ setTimeout(() => {
751
+ myState = 3;
752
+ IPClient.write(myRequests[1]);
753
+ }, 200);
754
+ break;
755
+ case 3:
756
+ decodePacket1(data);
757
+ IPClient.setTimeout(1000);
758
+ setTimeout(() => {
759
+ myState = 4;
760
+ IPClient.write(myRequests[2]);
761
+ }, 200);
762
+ break;
763
+ case 4: //test if it is time for reading all data. If not stop here
764
+ decodePacket2(data);
765
+ if ((myNumberforDetails < ConfBatDetailshowoften) || (ConfBatDetails == false)) {
766
+ setStates();
767
+ IPClient.destroy();
768
+ myState = 0;
769
+ } else {
770
+ myNumberforDetails = 0; //restart counting
771
+ IPClient.setTimeout(1000);
772
+ setTimeout(() => {
773
+ myState = 5;
774
+ IPClient.write(myRequests[3]);
775
+ }, 200);
776
+ }
777
+ break;
778
+ case 5:
779
+ decodePacketNOP(data);
780
+ IPClient.setTimeout(8000);
781
+ myState = 6;
782
+ adapter.log.silly("waiting 3 seconds to measure cells");
783
+ setTimeout(() => {
784
+ IPClient.write(myRequests[4]);
785
+ }, 3000);
786
+ break;
787
+ case 6:
788
+ decodePacketNOP(data);
789
+ IPClient.setTimeout(1000);
790
+ myState = 7;
791
+ setTimeout(() => {
792
+ IPClient.write(myRequests[5]);
793
+ }, 200);
794
+ break;
795
+ case 7:
796
+ decodePacket5(data);
797
+ IPClient.setTimeout(1000);
798
+ setTimeout(() => {
799
+ myState = 8;
800
+ IPClient.write(myRequests[6]);
801
+ }, 200);
802
+ break;
803
+ case 8:
804
+ decodePacket6(data);
805
+ IPClient.setTimeout(1000);
806
+ setTimeout(() => {
807
+ myState = 9;
808
+ IPClient.write(myRequests[7]);
809
+ }, 200);
810
+ break;
811
+ case 9:
812
+ decodePacket7(data);
813
+ IPClient.setTimeout(1000);
814
+ setTimeout(() => {
815
+ myState = 10;
816
+ IPClient.write(myRequests[8]);
817
+ }, 200);
818
+ break;
819
+ case 10:
820
+ decodePacket8(data);
821
+ if (hvsNumCells > 128) {
822
+ setTimeout(() => {
823
+ myState = 11;
824
+ IPClient.write(myRequests[9]); // Switch to second turn for the last module
825
+ }, 200);
826
+ } else {
827
+ setStates();
828
+ IPClient.destroy();
829
+ myState = 0;
830
+ }
831
+ break;
832
+ case 11:
833
+ decodePacketNOP(data);
834
+ setTimeout(() => {
835
+ myState = 12;
836
+ IPClient.write(myRequests[10]);
837
+ }, 200);
838
+ break;
839
+ case 12:
840
+ decodePacketNOP(data);
841
+ IPClient.setTimeout(8000);
842
+ adapter.log.silly("waiting 3 seconds to measure cells");
843
+ setTimeout(() => {
844
+ myState = 13;
845
+ IPClient.write(myRequests[11]);
846
+ }, 3000);
847
+ break;
848
+ case 13:
849
+ decodePacketNOP(data);
850
+ IPClient.setTimeout(1000);
851
+ setTimeout(() => {
852
+ myState = 14;
853
+ IPClient.write(myRequests[12]);
854
+ }, 200);
855
+ break;
856
+ case 14:
857
+ decodeResponse12(data);
858
+ setTimeout(() => {
859
+ myState = 15;
860
+ IPClient.write(myRequests[13]);
861
+ }, 200);
862
+ break;
863
+ case 15:
864
+ decodeResponse13(data);
865
+
866
+ setStates();
867
+ IPClient.destroy();
868
+ myState = 0;
869
+ break;
870
+ default:
871
+ IPClient.destroy();
872
+ }
873
+ });
874
+
875
+
876
+ IPClient.on("timeout", function () {
877
+ IPClient.destroy();
878
+ setConnected(adapter, false);
879
+ myState = 0;
880
+ adapter.log.error("no connection to IP: " + adapter.config.ConfIPAdress);
881
+ });
882
+
883
+ IPClient.on("error", function () {
884
+ IPClient.destroy();
885
+ setConnected(adapter, false);
886
+ myState = 0;
887
+ adapter.log.error("Error connecting to " + adapter.config.ConfIPAdress);
888
+ });
889
+
890
+
891
+ function Poll(adapter) {
892
+ myState = 1;
893
+ IPClient.setTimeout(1000);
894
+ myNumberforDetails += 1;
895
+ adapter.log.silly("myNumberforDetails:" + myNumberforDetails);
896
+ adapter.log.silly("Poll start, IP:" + adapter.config.ConfIPAdress);
897
+ IPClient.connect(8080, adapter.config.ConfIPAdress, function () {
898
+ myState = 2;
899
+ setConnected(adapter, true);
900
+ IPClient.write(myRequests[0]);
901
+ });
902
+ }
903
+
904
+ async function main() {
905
+
906
+ // Reset the connection indicator during startup
907
+ // await this.setStateAsync("info.connection", false, true);
908
+ setConnected(adapter, false);
909
+ setObjects();
910
+ myState = 0;
911
+
912
+ // The adapters config (in the instance object everything under the attribute "native") is accessible via
913
+ // adapter.config:
914
+ adapter.log.info("Poll Interval: " + adapter.config.ConfPollInterval);
915
+ confBatPollTime = parseInt(adapter.config.ConfPollInterval);
916
+ if (confBatPollTime < 60) {
917
+ confBatPollTime = 60;
918
+ adapter.log.error("polling to often - max once per minute ");
919
+ }
920
+ adapter.log.info("BYD IP Adress: " + adapter.config.ConfIPAdress);
921
+ ConfBatDetails = (adapter.config.ConfBatDetails ? true : false);
922
+ adapter.log.info("Bat Details : " + adapter.config.ConfBatDetails);
923
+ ConfBatDetailshowoften = parseInt(adapter.config.ConfDetailshowoften);
924
+ /*if (ConfBatDetailshowoften < 10) {
925
+ ConfBatDetails = false;
926
+ adapter.log.error("Details polling to often - disabling ");
927
+ }*/
928
+ ConfTestMode = (adapter.config.ConfTestMode ? true : false);
929
+ adapter.log.info("BatDetailshowoften: " + ConfBatDetailshowoften);
930
+ adapter.log.silly("TestMode= " + ConfTestMode);
931
+ myNumberforDetails = ConfBatDetailshowoften;
932
+ // adapter.config.ConfPollInterval = parseInt(adapter.config.ConfPollInterval, 10) || 60;
933
+
934
+ adapter.log.info("starte poll");
935
+ startPoll(adapter);
936
+
937
+ // examples for the checkPassword/checkGroup functions
938
+ /* adapter.checkPassword("admin", "iobroker", (res) => {
939
+ adapter.log.info("check user admin pw iobroker: " + res);
940
+ });
941
+ adapter.checkGroup("admin", "admin", (res) => {
942
+ adapter.log.info("check group user admin group admin: " + res);
943
+ });*/
944
+ }
945
+
946
+ // @ts-ignore parent is a valid property on module
947
+ if (module.parent) {
948
+ // Export startAdapter in compact mode
949
+ module.exports = startAdapter;
950
+ } else {
951
+ // otherwise start the instance directly
952
+ startAdapter();
953
+ }