iobroker.bydhvs 1.5.0 → 1.5.2
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/CHANGELOG_OLD.md +13 -0
- package/LICENSE +21 -21
- package/README.md +16 -18
- package/admin/jsonConfig.json +108 -0
- package/docs/byd-hexstructure.md +78 -0
- package/eslint.config.mjs +33 -0
- package/io-package.json +89 -31
- package/lib/constants.js +127 -0
- package/lib/methods.js +56 -0
- package/main.js +1461 -965
- package/package.json +33 -27
- package/prettier.config.mjs +8 -0
- package/PSD_Battery_Icons.psd +0 -0
- package/admin/admin.d.ts +0 -93
- package/admin/index_m.html +0 -113
- package/admin/style.css +0 -32
- package/admin/words.js +0 -81
- package/lib/tools.js +0 -99
package/main.js
CHANGED
@@ -1,965 +1,1461 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
/*
|
4
|
-
* Created with @iobroker/create-adapter v1.31.0
|
5
|
-
*/
|
6
|
-
|
7
|
-
//
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
const
|
14
|
-
|
15
|
-
const
|
16
|
-
const
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
let
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
let
|
32
|
-
let
|
33
|
-
let
|
34
|
-
let
|
35
|
-
let
|
36
|
-
let
|
37
|
-
let
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
let
|
42
|
-
|
43
|
-
let
|
44
|
-
let
|
45
|
-
let
|
46
|
-
let
|
47
|
-
let hvsBatTemp;
|
48
|
-
let hvsOutVolt;
|
49
|
-
let
|
50
|
-
let
|
51
|
-
let
|
52
|
-
let
|
53
|
-
let
|
54
|
-
let
|
55
|
-
let
|
56
|
-
let
|
57
|
-
let
|
58
|
-
let
|
59
|
-
let
|
60
|
-
let
|
61
|
-
let
|
62
|
-
let
|
63
|
-
let
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
let
|
68
|
-
let
|
69
|
-
|
70
|
-
let
|
71
|
-
let
|
72
|
-
let
|
73
|
-
let
|
74
|
-
let
|
75
|
-
|
76
|
-
|
77
|
-
let
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
"
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
let idInterval1;
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
}
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
}
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
}
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
}
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
}
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
}
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
/*
|
4
|
+
* Created with @iobroker/create-adapter v1.31.0
|
5
|
+
*/
|
6
|
+
|
7
|
+
const utils = require('@iobroker/adapter-core'); // Get common adapter utils
|
8
|
+
const crc = require('crc');
|
9
|
+
const net = require('net');
|
10
|
+
|
11
|
+
const _methods = require('./lib/methods');
|
12
|
+
|
13
|
+
const myRequests = require('./lib/constants').myRequests;
|
14
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
15
|
+
const byd_stat_tower = require('./lib/constants').byd_stat_tower;
|
16
|
+
const myINVs = require('./lib/constants').myINVs;
|
17
|
+
const myINVsLVS = require('./lib/constants').myINVsLVS;
|
18
|
+
|
19
|
+
const socket = new net.Socket();
|
20
|
+
/**
|
21
|
+
* The adapter instance
|
22
|
+
*
|
23
|
+
*/
|
24
|
+
let myState; // Aktueller Status
|
25
|
+
let hvsSOC;
|
26
|
+
let hvsMaxVolt;
|
27
|
+
let hvsMinVolt;
|
28
|
+
let hvsSOH;
|
29
|
+
/**
|
30
|
+
* Removed attributes because they can now occour mor than once.
|
31
|
+
* let hvsMaxmVolt;
|
32
|
+
* let hvsMinmVolt;
|
33
|
+
* let hvsMaxmVoltCell;
|
34
|
+
* let hvsMinmVoltCell;
|
35
|
+
* let hvsMaxTempCell;
|
36
|
+
* let hvsMinTempCell;
|
37
|
+
* let hvsSOCDiagnosis;
|
38
|
+
* const hvsBatteryVoltsperCell = [];
|
39
|
+
* const hvsBatteryTempperCell = [];
|
40
|
+
*/
|
41
|
+
let towerAttributes = [];
|
42
|
+
|
43
|
+
let hvsA;
|
44
|
+
let hvsBattVolt;
|
45
|
+
let hvsMaxTemp;
|
46
|
+
let hvsMinTemp;
|
47
|
+
let hvsBatTemp;
|
48
|
+
let hvsOutVolt;
|
49
|
+
let hvsChargeTotal;
|
50
|
+
let hvsDischargeTotal;
|
51
|
+
let hvsETA;
|
52
|
+
let hvsError;
|
53
|
+
let hvsModules;
|
54
|
+
let hvsTowers;
|
55
|
+
let hvsDiffVolt;
|
56
|
+
let hvsPower;
|
57
|
+
let hvsBattType;
|
58
|
+
let hvsBattType_fromSerial;
|
59
|
+
let hvsInvType;
|
60
|
+
let hvsInvType_String;
|
61
|
+
let hvsNumCells; //number of cells in system
|
62
|
+
let hvsNumTemps; // number of temperatures to count with
|
63
|
+
let ConfBatDetailshowoften;
|
64
|
+
let ConfBydTowerCount;
|
65
|
+
let confBatPollTime;
|
66
|
+
let myNumberforDetails;
|
67
|
+
let ConfTestMode;
|
68
|
+
let _firstRun = false;
|
69
|
+
|
70
|
+
let hvsSerial;
|
71
|
+
let hvsBMU;
|
72
|
+
let hvsBMUA;
|
73
|
+
let hvsBMUB;
|
74
|
+
let hvsBMS;
|
75
|
+
let hvsGrid;
|
76
|
+
let hvsErrorString;
|
77
|
+
let hvsParamT;
|
78
|
+
|
79
|
+
let ConfBatDetails;
|
80
|
+
let ConfOverridePollInterval = 0;
|
81
|
+
|
82
|
+
/*const myStates = [
|
83
|
+
"no state",
|
84
|
+
"waiting for initial connect",
|
85
|
+
"waiting for 1st answer",
|
86
|
+
"waiting for 2nd answer"
|
87
|
+
|
88
|
+
];*/
|
89
|
+
|
90
|
+
let idInterval1 = 0;
|
91
|
+
|
92
|
+
const myBattTypes = ['HVL', 'HVM', 'HVS'];
|
93
|
+
/* HVM: 16 cells per module
|
94
|
+
HVS: 32 cells per module
|
95
|
+
HVL: unknown so I count 0 cells per module
|
96
|
+
*/
|
97
|
+
|
98
|
+
class bydhvsControll extends utils.Adapter {
|
99
|
+
constructor(options = {}) {
|
100
|
+
super({
|
101
|
+
...options,
|
102
|
+
name: 'bydhvs',
|
103
|
+
});
|
104
|
+
|
105
|
+
this.on('ready', this.onReady.bind(this));
|
106
|
+
// this.on('stateChange', this.onStateChange.bind(this));
|
107
|
+
this.on('unload', this.onUnload.bind(this));
|
108
|
+
}
|
109
|
+
|
110
|
+
async onReady() {
|
111
|
+
//first check account settings
|
112
|
+
this.setState('info.connection', false, true);
|
113
|
+
this.setState('info.socketConnection', false, true);
|
114
|
+
|
115
|
+
this.buf2int16SI = _methods.buf2int16SI.bind(this);
|
116
|
+
this.buf2int16US = _methods.buf2int16US.bind(this);
|
117
|
+
this.buf2int32US = _methods.buf2int32US.bind(this);
|
118
|
+
this.decodePacketNOP = _methods.decodePacketNOP.bind(this);
|
119
|
+
this.countSetBits = _methods.countSetBits.bind(this);
|
120
|
+
|
121
|
+
this.setStateAsync(`info.socketConnection`, false, true);
|
122
|
+
|
123
|
+
this.initData();
|
124
|
+
|
125
|
+
this.log.info('starte polling');
|
126
|
+
this.startQuery();
|
127
|
+
}
|
128
|
+
|
129
|
+
/**
|
130
|
+
* Is called when adapter shuts down - callback has to be called under any circumstances!
|
131
|
+
*
|
132
|
+
* @param callback
|
133
|
+
*/
|
134
|
+
onUnload(callback) {
|
135
|
+
try {
|
136
|
+
clearTimeout(idInterval1);
|
137
|
+
socket.destroy();
|
138
|
+
this.log.info('Adapter bluelink cleaned up everything...');
|
139
|
+
callback();
|
140
|
+
} catch (error) {
|
141
|
+
callback();
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
initData() {
|
146
|
+
this.setObjects();
|
147
|
+
|
148
|
+
myState = 0;
|
149
|
+
|
150
|
+
ConfOverridePollInterval = this.config.ConfOverridePollInterval ? this.config.ConfOverridePollInterval : 0;
|
151
|
+
|
152
|
+
if (ConfOverridePollInterval == 0) {
|
153
|
+
confBatPollTime = parseInt(this.config.ConfPollInterval);
|
154
|
+
} else {
|
155
|
+
const OverridePollState = this.getState('System.OverridePoll');
|
156
|
+
confBatPollTime = OverridePollState ? OverridePollState.val : 60;
|
157
|
+
}
|
158
|
+
|
159
|
+
if (confBatPollTime < 30) {
|
160
|
+
//confBatPollTime = 60;
|
161
|
+
this.log.warn('poll to often - recommendation is not more than every 30 seconds');
|
162
|
+
}
|
163
|
+
|
164
|
+
ConfBydTowerCount = this.config.ConfBydTowerCount ? this.config.ConfBydTowerCount : 1;
|
165
|
+
ConfBatDetails = this.config.ConfBatDetails ? true : false;
|
166
|
+
ConfBatDetailshowoften = parseInt(this.config.ConfDetailshowoften);
|
167
|
+
ConfTestMode = this.config.ConfTestMode ? true : false;
|
168
|
+
myNumberforDetails = ConfBatDetailshowoften;
|
169
|
+
|
170
|
+
this.log.info(`BYD IP Adress: ${this.config.ConfIPAdress}`);
|
171
|
+
this.log.info(`Bat Details : ${this.config.ConfBatDetails}`);
|
172
|
+
this.log.info(`Tower count: ${this.config.ConfBydTowerCount}`);
|
173
|
+
this.log.info(
|
174
|
+
`Override Poll, so use from state and not from settings: ${this.config.ConfOverridePollInterval}`,
|
175
|
+
);
|
176
|
+
this.log.info(`Battery Poll Time: ${confBatPollTime}`);
|
177
|
+
this.log.info(`BatDetailshowoften: ${ConfBatDetailshowoften}`);
|
178
|
+
this.log.silly(`TestMode= ${ConfTestMode}`);
|
179
|
+
}
|
180
|
+
|
181
|
+
async checkandrepairUnit(id, NewUnit, NewRole, newName) {
|
182
|
+
//want to test and understand async and await, so it's introduced here.
|
183
|
+
//check for forgotten unit in first version and if it's missing add unit.
|
184
|
+
try {
|
185
|
+
const obj = await this.getObjectAsync(id);
|
186
|
+
if (NewUnit != '') {
|
187
|
+
if (obj.common.unit != NewUnit) {
|
188
|
+
this.extendObject(id, { common: { unit: NewUnit } });
|
189
|
+
}
|
190
|
+
}
|
191
|
+
if (obj.common.role == '') {
|
192
|
+
this.extendObject(id, { common: { role: NewRole } });
|
193
|
+
}
|
194
|
+
if (newName != '') {
|
195
|
+
if (obj.common.name != newName) {
|
196
|
+
this.extendObject(id, { common: { name: newName } });
|
197
|
+
}
|
198
|
+
}
|
199
|
+
} catch {
|
200
|
+
//dann eben nicht.
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
checkPacket(data) {
|
205
|
+
const byteArray = new Uint8Array(data);
|
206
|
+
const packetLength = data[2] + 5; // 3 header, 2 crc
|
207
|
+
if (byteArray[0] != 1) {
|
208
|
+
return false;
|
209
|
+
}
|
210
|
+
if (byteArray[1] === 3) {
|
211
|
+
//habe die Kodierung der Antwort mit 1 an zweiter Stelle nicht verstanden, daher hier keine Längenprüfung
|
212
|
+
if (packetLength != byteArray.length) {
|
213
|
+
return false;
|
214
|
+
}
|
215
|
+
} else {
|
216
|
+
if (byteArray[1] != 16) {
|
217
|
+
return false;
|
218
|
+
}
|
219
|
+
}
|
220
|
+
return crc.crc16modbus(byteArray) === 0;
|
221
|
+
}
|
222
|
+
|
223
|
+
pad(n, width, z) {
|
224
|
+
z = z || '0';
|
225
|
+
n = `${n}`;
|
226
|
+
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
|
227
|
+
}
|
228
|
+
|
229
|
+
setObjects() {
|
230
|
+
let myObjects = [
|
231
|
+
['System.Serial', 'state', 'Serial number', 'string', 'text', true, false, ''],
|
232
|
+
['System.BMU', 'state', 'F/W BMU', 'string', 'text', true, false, ''],
|
233
|
+
['System.BMS', 'state', 'F/W BMS', 'string', 'text', true, false, ''],
|
234
|
+
['System.BMUBankA', 'state', 'F/W BMU-BankA', 'string', 'text', true, false, ''],
|
235
|
+
['System.BMUBankB', 'state', 'F/W BMU-BankB', 'string', 'text', true, false, ''],
|
236
|
+
['System.Modules', 'state', 'modules (count)', 'number', 'value', true, false, ''],
|
237
|
+
['System.Towers', 'state', 'towers (count)', 'number', 'value', true, false, ''],
|
238
|
+
['System.Grid', 'state', 'Parameter Table', 'string', 'text', true, false, ''],
|
239
|
+
['System.ParamT', 'state', 'F/W BMU', 'string', 'text', true, false, ''],
|
240
|
+
['System.BattType', 'state', 'Battery Type', 'string', 'text', true, false, ''],
|
241
|
+
['System.InvType', 'state', 'Inverter Type', 'string', 'text', true, false, ''],
|
242
|
+
['State.SOC', 'state', 'SOC', 'number', 'value.battery', true, false, '%'],
|
243
|
+
['State.VoltMax', 'state', 'Max Cell Voltage', 'number', 'value.voltage', true, false, 'V'],
|
244
|
+
['State.VoltMin', 'state', 'Min Cell Voltage', 'number', 'value.voltage', true, false, 'V'],
|
245
|
+
['State.SOH', 'state', 'SOH', 'number', 'value.battery', true, false, '%'],
|
246
|
+
['State.Current', 'state', 'Charge / Discharge Current', 'number', 'value.current', true, false, 'A'],
|
247
|
+
['State.Power_Consumption', 'state', 'Charge Power', 'number', 'value.power', true, false, 'W'],
|
248
|
+
['State.Power_Delivery', 'state', 'Discharge Power', 'number', 'value.power', true, false, 'W'],
|
249
|
+
['State.VoltBatt', 'state', 'Battery Voltage', 'number', 'value.voltage', true, false, 'V'],
|
250
|
+
['State.TempMax', 'state', 'Max Cell Temp', 'number', 'value.temperature', true, false, '°C'],
|
251
|
+
['State.TempMin', 'state', 'Min Cell Temp', 'number', 'value.temperature', true, false, '°C'],
|
252
|
+
['State.VoltDiff', 'state', 'Max - Min Cell Voltage', 'number', 'value.temperature', true, false, 'V'],
|
253
|
+
['State.Power', 'state', 'Power', 'number', 'value.power', true, false, 'W'],
|
254
|
+
['State.TempBatt', 'state', 'Battery Temperature', 'number', 'value.temperature', true, false, '°C'],
|
255
|
+
['State.VoltOut', 'state', 'Output Voltage', 'number', 'value.voltage', true, false, 'V'],
|
256
|
+
['System.ErrorNum', 'state', 'Error (numeric)', 'number', 'value', true, false, ''],
|
257
|
+
['System.ErrorStr', 'state', 'Error (string)', 'string', 'text', true, false, ''],
|
258
|
+
['System.ChargeTotal', 'state', 'Total Charge of the system', 'number', 'value.energy', true, false, 'Wh'],
|
259
|
+
[
|
260
|
+
'System.DischargeTotal',
|
261
|
+
'state',
|
262
|
+
'Total Discharge of the system',
|
263
|
+
'number',
|
264
|
+
'value.energy',
|
265
|
+
true,
|
266
|
+
false,
|
267
|
+
'Wh',
|
268
|
+
],
|
269
|
+
['System.ETA', 'state', 'Efficiency of in percent', 'number', 'value', true, false, ''],
|
270
|
+
['System.OverridePoll', 'state', 'Poll interval if set per state', 'number', 'value', true, true, ''],
|
271
|
+
];
|
272
|
+
|
273
|
+
const rawObjects = [
|
274
|
+
['System.Raw_00', 'state', 'Raw Message of sequence 00', 'string', 'text', true, false, ''],
|
275
|
+
['System.Raw_01', 'state', 'Raw Message of sequence 01', 'string', 'text', true, false, ''],
|
276
|
+
['System.Raw_02', 'state', 'Raw Message of sequence 02', 'string', 'text', true, false, ''],
|
277
|
+
];
|
278
|
+
if (this.config.ConfStoreRawMessages) {
|
279
|
+
myObjects = myObjects.concat(rawObjects);
|
280
|
+
}
|
281
|
+
|
282
|
+
for (let i = 0; i < myObjects.length; i++) {
|
283
|
+
this.setObjectNotExists(myObjects[i][0], {
|
284
|
+
type: myObjects[i][1],
|
285
|
+
common: {
|
286
|
+
name: myObjects[i][2],
|
287
|
+
type: myObjects[i][3],
|
288
|
+
role: myObjects[i][4],
|
289
|
+
read: myObjects[i][5],
|
290
|
+
write: myObjects[i][6],
|
291
|
+
unit: myObjects[i][7], //works only for new objects, so check later for existing objects
|
292
|
+
},
|
293
|
+
native: {},
|
294
|
+
});
|
295
|
+
}
|
296
|
+
//repair forgotten units in first version and required roles
|
297
|
+
for (const myObject of myObjects) {
|
298
|
+
//console.log("****extend " + i + " " + myObjects[i][0] + " " + myObjects[i][7]);
|
299
|
+
this.checkandrepairUnit(myObject[0], myObject[7], myObject[4], myObject[2]);
|
300
|
+
}
|
301
|
+
}
|
302
|
+
|
303
|
+
setStates() {
|
304
|
+
let ObjTowerString = '';
|
305
|
+
|
306
|
+
this.log.silly(`hvsSerial >${hvsSerial}<
|
307
|
+
hvsBMU >${hvsBMU}<;
|
308
|
+
hvsBMUA >${hvsBMUA}<;
|
309
|
+
hvsBMUB >${hvsBMUB}<;
|
310
|
+
hvsBMS >${hvsBMS}<;
|
311
|
+
hvsModules >${hvsModules}<;
|
312
|
+
hvsGrid >${hvsGrid}<;
|
313
|
+
hvsSOC >${hvsSOC}<;
|
314
|
+
hvsMaxVolt >${hvsMaxVolt}<;
|
315
|
+
hvsMinVolt >${hvsMinVolt}<;
|
316
|
+
hvsSOH >${hvsSOH}<;
|
317
|
+
hvsA >${hvsA}<;
|
318
|
+
hvsBattVolt >${hvsBattVolt}<;
|
319
|
+
hvsMaxTemp >${hvsMaxTemp}<;
|
320
|
+
hvsMinTemp >${hvsMinTemp}<;
|
321
|
+
hvsDiffVolt >${hvsDiffVolt}<;
|
322
|
+
hvsPower >${hvsPower}<;
|
323
|
+
hvsParamT >${hvsParamT}<;
|
324
|
+
hvsBatTemp >${hvsBatTemp}<;
|
325
|
+
hvsOutVolt >${hvsOutVolt}<,
|
326
|
+
hvsError >${hvsError}<,
|
327
|
+
hvsErrorStr >${hvsErrorString}<,
|
328
|
+
BattType >${hvsBattType_fromSerial}<,
|
329
|
+
Invert. Type >${hvsInvType_String}, Nr: ${hvsInvType}<`);
|
330
|
+
|
331
|
+
this.setState('System.Serial', hvsSerial, true);
|
332
|
+
this.setState('System.BMU', hvsBMU, true);
|
333
|
+
this.setState('System.BMUBankA', hvsBMUA, true);
|
334
|
+
this.setState('System.BMUBankB', hvsBMUB, true);
|
335
|
+
this.setState('System.BMS', hvsBMS, true);
|
336
|
+
this.setState('System.Modules', hvsModules, true);
|
337
|
+
this.setState('System.Towers', hvsTowers, true);
|
338
|
+
this.setState('System.Grid', hvsGrid, true);
|
339
|
+
this.setState('State.SOC', hvsSOC, true);
|
340
|
+
this.setState('State.VoltMax', hvsMaxVolt, true);
|
341
|
+
this.setState('State.VoltMin', hvsMinVolt, true);
|
342
|
+
this.setState('State.SOH', hvsSOH, true);
|
343
|
+
this.setState('State.Current', hvsA, true);
|
344
|
+
this.setState('State.VoltBatt', hvsBattVolt, true);
|
345
|
+
this.setState('State.TempMax', hvsMaxTemp, true);
|
346
|
+
this.setState('State.TempMin', hvsMinTemp, true);
|
347
|
+
this.setState('State.VoltDiff', hvsDiffVolt, true);
|
348
|
+
this.setState('State.Power', hvsPower, true /*ack*/);
|
349
|
+
this.setState('System.ParamT', hvsParamT, true);
|
350
|
+
this.setState('State.TempBatt', hvsBatTemp, true);
|
351
|
+
this.setState('State.VoltOut', hvsOutVolt, true);
|
352
|
+
this.setState('System.ErrorNum', hvsError, true);
|
353
|
+
this.setState('System.ErrorStr', hvsErrorString, true);
|
354
|
+
|
355
|
+
if (hvsPower >= 0) {
|
356
|
+
this.setState('State.Power_Consumption', hvsPower, true);
|
357
|
+
this.setState('State.Power_Delivery', 0, true);
|
358
|
+
} else {
|
359
|
+
this.setState('State.Power_Consumption', 0, true);
|
360
|
+
this.setState('State.Power_Delivery', -hvsPower, true);
|
361
|
+
}
|
362
|
+
|
363
|
+
this.setState('System.BattType', hvsBattType_fromSerial, true);
|
364
|
+
this.setState('System.InvType', hvsInvType_String, true);
|
365
|
+
this.setState('System.ChargeTotal', hvsChargeTotal, true);
|
366
|
+
this.setState('System.DischargeTotal', hvsDischargeTotal, true);
|
367
|
+
this.setState('System.ETA', hvsETA, true);
|
368
|
+
|
369
|
+
if (myNumberforDetails == 0) {
|
370
|
+
// For every tower
|
371
|
+
this.log.silly(`Tower attributes: ${JSON.stringify(towerAttributes)}`);
|
372
|
+
for (let t = 0; t < towerAttributes.length; t++) {
|
373
|
+
try {
|
374
|
+
if (ConfBydTowerCount > 1) {
|
375
|
+
ObjTowerString = `.Tower_${t + 1}`;
|
376
|
+
}
|
377
|
+
|
378
|
+
// Test if all required msg received.
|
379
|
+
if (towerAttributes[t].hvsMaxmVolt) {
|
380
|
+
this.setState(`Diagnosis${ObjTowerString}.mVoltMax`, towerAttributes[t].hvsMaxmVolt, true);
|
381
|
+
this.setState(`Diagnosis${ObjTowerString}.mVoltMin`, towerAttributes[t].hvsMinmVolt, true);
|
382
|
+
this.setState(
|
383
|
+
`Diagnosis${ObjTowerString}.mVoltMaxCell`,
|
384
|
+
towerAttributes[t].hvsMaxmVoltCell,
|
385
|
+
true,
|
386
|
+
);
|
387
|
+
this.setState(
|
388
|
+
`Diagnosis${ObjTowerString}.mVoltMinCell`,
|
389
|
+
towerAttributes[t].hvsMinmVoltCell,
|
390
|
+
true,
|
391
|
+
);
|
392
|
+
this.setState(`Diagnosis${ObjTowerString}.TempMax`, towerAttributes[t].hvsMaxmTemp, true);
|
393
|
+
this.setState(`Diagnosis${ObjTowerString}.TempMin`, towerAttributes[t].hvsMinmTemp, true);
|
394
|
+
this.setState(
|
395
|
+
`Diagnosis${ObjTowerString}.TempMaxCell`,
|
396
|
+
towerAttributes[t].hvsMaxTempCell,
|
397
|
+
true,
|
398
|
+
);
|
399
|
+
this.setState(
|
400
|
+
`Diagnosis${ObjTowerString}.TempMinCell`,
|
401
|
+
towerAttributes[t].hvsMinTempCell,
|
402
|
+
true,
|
403
|
+
);
|
404
|
+
this.setState(`Diagnosis${ObjTowerString}.ChargeTotal`, towerAttributes[t].chargeTotal, true);
|
405
|
+
this.setState(
|
406
|
+
`Diagnosis${ObjTowerString}.DischargeTotal`,
|
407
|
+
towerAttributes[t].dischargeTotal,
|
408
|
+
true,
|
409
|
+
);
|
410
|
+
this.setState(`Diagnosis${ObjTowerString}.ETA`, towerAttributes[t].eta, true);
|
411
|
+
this.setState(`Diagnosis${ObjTowerString}.BatteryVolt`, towerAttributes[t].batteryVolt, true);
|
412
|
+
this.setState(`Diagnosis${ObjTowerString}.OutVolt`, towerAttributes[t].outVolt, true);
|
413
|
+
this.setState(`Diagnosis${ObjTowerString}.SOC`, towerAttributes[t].hvsSOCDiagnosis, true);
|
414
|
+
this.setState(`Diagnosis${ObjTowerString}.SOH`, towerAttributes[t].soh, true);
|
415
|
+
this.setState(`Diagnosis${ObjTowerString}.State`, towerAttributes[t].state, true);
|
416
|
+
this.setState(`Diagnosis${ObjTowerString}.BalancingCells`, towerAttributes[t].balancing, true);
|
417
|
+
this.setState(
|
418
|
+
`Diagnosis${ObjTowerString}.BalancingCellsCount`,
|
419
|
+
towerAttributes[t].balancingcount,
|
420
|
+
true,
|
421
|
+
);
|
422
|
+
|
423
|
+
this.log.debug(`Tower_${t + 1} balancing >${towerAttributes[t].balancing}<`);
|
424
|
+
this.log.debug(`Tower_${t + 1} balcount >${towerAttributes[t].balancingcount}<`);
|
425
|
+
|
426
|
+
if (t == 0) {
|
427
|
+
this.setState(
|
428
|
+
`Diagnosis${ObjTowerString}.BalancingOne`,
|
429
|
+
towerAttributes[t].balancing ? towerAttributes[t].balancing : '',
|
430
|
+
true,
|
431
|
+
);
|
432
|
+
this.setState(
|
433
|
+
`Diagnosis${ObjTowerString}.BalancingCountOne`,
|
434
|
+
towerAttributes[t].balancingcount,
|
435
|
+
true,
|
436
|
+
);
|
437
|
+
} else {
|
438
|
+
this.setState(
|
439
|
+
`Diagnosis${ObjTowerString}.BalancingTwo`,
|
440
|
+
towerAttributes[t].balancing ? towerAttributes[t].balancing : '',
|
441
|
+
true,
|
442
|
+
);
|
443
|
+
this.setState(
|
444
|
+
`Diagnosis${ObjTowerString}.BalancingCountTwo`,
|
445
|
+
towerAttributes[t].balancingcount,
|
446
|
+
true,
|
447
|
+
);
|
448
|
+
}
|
449
|
+
/*
|
450
|
+
if (towerAttributes[t].balancing) this.setState(`Diagnosis` + ObjTowerString + `.BalancingOne`, towerAttributes[t].balancing_one, true);
|
451
|
+
if (towerAttributes[t].balancingcount_one) this.setState(`Diagnosis` + ObjTowerString + `.BalancingOne`, towerAttributes[t].balancing_one, true);
|
452
|
+
this.setState(`Diagnosis` + ObjTowerString + `.BalancingTwo`, towerAttributes[t].balancing_two ? towerAttributes[t].balancing_two : "", true);
|
453
|
+
this.setState(`Diagnosis` + ObjTowerString + `.BalancingCountTwo`, towerAttributes[t].balancingcount_two ? towerAttributes[t].balancingcount_two : 0, true );
|
454
|
+
*/
|
455
|
+
for (let i = 1; i <= hvsNumCells; i++) {
|
456
|
+
this.setState(
|
457
|
+
`CellDetails${ObjTowerString}.CellVolt${this.pad(i, 3)}`,
|
458
|
+
towerAttributes[t].hvsBatteryVoltsperCell[i]
|
459
|
+
? towerAttributes[t].hvsBatteryVoltsperCell[i]
|
460
|
+
: 0,
|
461
|
+
true,
|
462
|
+
);
|
463
|
+
}
|
464
|
+
const mVoltDefDeviation = this.calcDeviation(
|
465
|
+
towerAttributes[t].hvsBatteryVoltsperCell.filter(v => v > 0),
|
466
|
+
);
|
467
|
+
const mVoltMean = this.calcAverage(
|
468
|
+
towerAttributes[t].hvsBatteryVoltsperCell.filter(v => v > 0),
|
469
|
+
);
|
470
|
+
this.setState(`Diagnosis${ObjTowerString}.mVoltDefDeviation`, mVoltDefDeviation, true);
|
471
|
+
this.setState(`Diagnosis${ObjTowerString}.mVoltMean`, mVoltMean, true);
|
472
|
+
this.setState(
|
473
|
+
`Diagnosis${ObjTowerString}.mVoltGt150DefVar`,
|
474
|
+
towerAttributes[t].hvsBatteryVoltsperCell.filter(
|
475
|
+
v => v > mVoltMean + mVoltDefDeviation * 1.5,
|
476
|
+
).length,
|
477
|
+
true,
|
478
|
+
);
|
479
|
+
this.setState(
|
480
|
+
`Diagnosis${ObjTowerString}.mVoltLt150DefVar`,
|
481
|
+
towerAttributes[t].hvsBatteryVoltsperCell
|
482
|
+
.filter(v => v > 0)
|
483
|
+
.filter(v => v < mVoltMean - mVoltDefDeviation * 1.5).length,
|
484
|
+
true,
|
485
|
+
);
|
486
|
+
|
487
|
+
for (let i = 1; i <= hvsNumTemps; i++) {
|
488
|
+
this.setState(
|
489
|
+
`CellDetails${ObjTowerString}.CellTemp${this.pad(i, 3)}`,
|
490
|
+
towerAttributes[t].hvsBatteryTempperCell[i]
|
491
|
+
? towerAttributes[t].hvsBatteryTempperCell[i]
|
492
|
+
: 0,
|
493
|
+
true,
|
494
|
+
);
|
495
|
+
}
|
496
|
+
const tempDefDeviation = this.calcDeviation(
|
497
|
+
towerAttributes[t].hvsBatteryTempperCell.filter(v => v > 0),
|
498
|
+
);
|
499
|
+
const tempMean = this.calcAverage(towerAttributes[t].hvsBatteryTempperCell.filter(v => v > 0));
|
500
|
+
this.setState(`Diagnosis${ObjTowerString}.TempDefDeviation`, tempDefDeviation, true);
|
501
|
+
this.setState(`Diagnosis${ObjTowerString}.TempMean`, tempMean, true);
|
502
|
+
this.setState(
|
503
|
+
`Diagnosis${ObjTowerString}.TempGt150DefVar`,
|
504
|
+
towerAttributes[t].hvsBatteryTempperCell.filter(v => v > tempMean + tempDefDeviation * 1.5)
|
505
|
+
.length,
|
506
|
+
true,
|
507
|
+
);
|
508
|
+
this.setState(
|
509
|
+
`Diagnosis${ObjTowerString}.TempLt150DefVar`,
|
510
|
+
towerAttributes[t].hvsBatteryTempperCell
|
511
|
+
.filter(v => v > 0)
|
512
|
+
.filter(v => v < tempMean - tempDefDeviation * 1.5).length,
|
513
|
+
true,
|
514
|
+
);
|
515
|
+
|
516
|
+
this.log.silly(`Tower_${t + 1} hvsMaxmVolt >${towerAttributes[t].hvsMaxmVolt}<`);
|
517
|
+
this.log.silly(`Tower_${t + 1} hvsMinmVolt >${towerAttributes[t].hvsMinmVolt}<`);
|
518
|
+
this.log.silly(`Tower_${t + 1} hvsMaxmVoltCell >${towerAttributes[t].hvsMaxmVoltCell}<`);
|
519
|
+
this.log.silly(`Tower_${t + 1} hvsMinmVoltCell >${towerAttributes[t].hvsMinmVoltCell}<`);
|
520
|
+
this.log.silly(`Tower_${t + 1} hvsMaxTempCell >${towerAttributes[t].hvsMaxTempCell}<`);
|
521
|
+
this.log.silly(`Tower_${t + 1} hvsMinTempCell >${towerAttributes[t].hvsMinTempCell}<`);
|
522
|
+
this.log.silly(`Tower_${t + 1} hvsSOC (Diag) >${towerAttributes[t].hvsSOCDiagnosis}<`);
|
523
|
+
}
|
524
|
+
} catch (err) {
|
525
|
+
if (err instanceof Error) {
|
526
|
+
this.log.error(`Cant read in Tower ${t} with ${err.message}`);
|
527
|
+
} else {
|
528
|
+
this.log.error(`Cant read in Tower ${t} with unknown error`);
|
529
|
+
}
|
530
|
+
}
|
531
|
+
}
|
532
|
+
}
|
533
|
+
}
|
534
|
+
|
535
|
+
startQuery() {
|
536
|
+
//erster Start sofort (500ms), dann entsprechend der Config - dann muss man nicht beim Entwickeln warten bis der erste Timer durch ist.
|
537
|
+
_firstRun = true;
|
538
|
+
|
539
|
+
const runPoll = () => this.pollQuery();
|
540
|
+
|
541
|
+
// Start direkt nach 500ms
|
542
|
+
setTimeout(runPoll, 500);
|
543
|
+
|
544
|
+
// Danach zyklisch gemäß Konfiguration
|
545
|
+
idInterval1 = setInterval(runPoll, confBatPollTime * 1000);
|
546
|
+
this.log.info(`gestartet pollTime :${confBatPollTime} intervalId :${idInterval1}`);
|
547
|
+
}
|
548
|
+
|
549
|
+
async setupIPClientHandlers() {
|
550
|
+
const waitTime = 8000;
|
551
|
+
const timeout = 2000;
|
552
|
+
|
553
|
+
this.log.debug('Starte Datenabfrage via TCP-Client...');
|
554
|
+
|
555
|
+
return new Promise(resolve => {
|
556
|
+
const cleanup = () => {
|
557
|
+
this.log.debug('Schließe Socket-Verbindung und setze State zurück');
|
558
|
+
socket.destroy();
|
559
|
+
myState = 0;
|
560
|
+
};
|
561
|
+
|
562
|
+
const sendRequest = (requestIndex, nextState, delay = 200) => {
|
563
|
+
return new Promise(res => {
|
564
|
+
setTimeout(() => {
|
565
|
+
this.log.debug(`→ Sende Request [${requestIndex}] und wechsle in State ${nextState}`);
|
566
|
+
myState = nextState;
|
567
|
+
socket.write(myRequests[requestIndex]);
|
568
|
+
res();
|
569
|
+
}, delay);
|
570
|
+
});
|
571
|
+
};
|
572
|
+
|
573
|
+
const waitForData = () => {
|
574
|
+
return new Promise((res, rej) => {
|
575
|
+
socket.once('data', data => {
|
576
|
+
this.log.debug(`← Daten empfangen (Länge: ${data.length}) in State ${myState}`);
|
577
|
+
res(data);
|
578
|
+
});
|
579
|
+
socket.once('timeout', () => rej(new Error('Socket Timeout')));
|
580
|
+
socket.once('error', err => rej(err));
|
581
|
+
});
|
582
|
+
};
|
583
|
+
|
584
|
+
socket.setTimeout(timeout);
|
585
|
+
|
586
|
+
try {
|
587
|
+
socket.connect(8080, this.config.ConfIPAdress, async () => {
|
588
|
+
this.log.debug(`Socket verbunden mit ${this.config.ConfIPAdress}:8080`);
|
589
|
+
try {
|
590
|
+
myState = 2;
|
591
|
+
await sendRequest(0, 2);
|
592
|
+
|
593
|
+
while (true) {
|
594
|
+
const data = await waitForData();
|
595
|
+
|
596
|
+
if (!this.checkPacket(data)) {
|
597
|
+
this.log.warn(`⚠️ Ungültiges Paket empfangen in State ${myState}`);
|
598
|
+
this.setStateChanged('info.connection', { val: false, ack: true });
|
599
|
+
cleanup();
|
600
|
+
return resolve(false);
|
601
|
+
}
|
602
|
+
|
603
|
+
this.setStateChanged('info.connection', { val: true, ack: true });
|
604
|
+
|
605
|
+
switch (myState) {
|
606
|
+
case 2:
|
607
|
+
this.log.debug('➡️ State 2: Verarbeite Paket 0');
|
608
|
+
this.decodePacket0(data);
|
609
|
+
socket.setTimeout(timeout);
|
610
|
+
await sendRequest(1, 3);
|
611
|
+
break;
|
612
|
+
|
613
|
+
case 3:
|
614
|
+
this.log.debug('➡️ State 3: Verarbeite Paket 1');
|
615
|
+
this.decodePacket1(data);
|
616
|
+
socket.setTimeout(timeout);
|
617
|
+
await sendRequest(2, 4);
|
618
|
+
break;
|
619
|
+
|
620
|
+
case 4:
|
621
|
+
this.log.debug('➡️ State 4: Verarbeite Paket 2');
|
622
|
+
this.decodePacket2(data);
|
623
|
+
if (myNumberforDetails < ConfBatDetailshowoften || !ConfBatDetails) {
|
624
|
+
this.log.debug('⚡ Details nicht notwendig – beende Zyklus');
|
625
|
+
this.setStates();
|
626
|
+
cleanup();
|
627
|
+
return resolve(true);
|
628
|
+
}
|
629
|
+
myNumberforDetails = 0;
|
630
|
+
socket.setTimeout(timeout);
|
631
|
+
await sendRequest(3, 5);
|
632
|
+
break;
|
633
|
+
|
634
|
+
case 5:
|
635
|
+
this.log.debug('➡️ State 5: NOP + Wartezeit');
|
636
|
+
this.decodePacketNOP(data);
|
637
|
+
socket.setTimeout(waitTime + timeout);
|
638
|
+
await new Promise(res => setTimeout(res, waitTime));
|
639
|
+
await sendRequest(4, 6, 0);
|
640
|
+
break;
|
641
|
+
|
642
|
+
case 6:
|
643
|
+
this.log.debug('➡️ State 6: NOP');
|
644
|
+
this.decodePacketNOP(data);
|
645
|
+
await sendRequest(5, 7);
|
646
|
+
break;
|
647
|
+
|
648
|
+
case 7:
|
649
|
+
this.log.debug('➡️ State 7: Paket 5');
|
650
|
+
this.decodePacket5(data);
|
651
|
+
await sendRequest(6, 8);
|
652
|
+
break;
|
653
|
+
|
654
|
+
case 8:
|
655
|
+
this.log.debug('➡️ State 8: Paket 6');
|
656
|
+
this.decodePacket6(data);
|
657
|
+
await sendRequest(7, 9);
|
658
|
+
break;
|
659
|
+
|
660
|
+
case 9:
|
661
|
+
this.log.debug('➡️ State 9: Paket 7');
|
662
|
+
this.decodePacket7(data);
|
663
|
+
await sendRequest(8, 10);
|
664
|
+
break;
|
665
|
+
|
666
|
+
case 10:
|
667
|
+
this.log.debug('➡️ State 10: Paket 8');
|
668
|
+
this.decodePacket8(data);
|
669
|
+
if (hvsNumCells > 128) {
|
670
|
+
this.log.debug('Mehr als 128 Zellen erkannt → sende weiteres Paket');
|
671
|
+
await sendRequest(9, 11);
|
672
|
+
} else if (ConfBydTowerCount > 1) {
|
673
|
+
this.log.debug('Mehrere Tower erkannt → Wechsel zu State 16');
|
674
|
+
await sendRequest(16, 16);
|
675
|
+
} else {
|
676
|
+
this.log.debug('Alle Daten empfangen, beende...');
|
677
|
+
this.setStates();
|
678
|
+
cleanup();
|
679
|
+
return resolve(true);
|
680
|
+
}
|
681
|
+
break;
|
682
|
+
|
683
|
+
case 11:
|
684
|
+
this.log.debug('➡️ State 11: NOP');
|
685
|
+
this.decodePacketNOP(data);
|
686
|
+
await sendRequest(10, 12);
|
687
|
+
break;
|
688
|
+
|
689
|
+
case 12:
|
690
|
+
this.log.debug('➡️ State 12: NOP + Wartezeit');
|
691
|
+
this.decodePacketNOP(data);
|
692
|
+
socket.setTimeout(8000);
|
693
|
+
await new Promise(res => setTimeout(res, 3000));
|
694
|
+
await sendRequest(11, 13, 0);
|
695
|
+
break;
|
696
|
+
|
697
|
+
case 13:
|
698
|
+
this.log.debug('➡️ State 13: NOP');
|
699
|
+
this.decodePacketNOP(data);
|
700
|
+
await sendRequest(12, 14);
|
701
|
+
break;
|
702
|
+
|
703
|
+
case 14:
|
704
|
+
this.log.debug('➡️ State 14: Response12');
|
705
|
+
this.decodeResponse12(data);
|
706
|
+
await sendRequest(13, 15);
|
707
|
+
break;
|
708
|
+
|
709
|
+
case 15:
|
710
|
+
this.log.debug('➡️ State 15: Response13');
|
711
|
+
this.decodeResponse13(data);
|
712
|
+
if (ConfBydTowerCount > 1) {
|
713
|
+
await sendRequest(16, 16);
|
714
|
+
} else {
|
715
|
+
this.log.debug('Beende nach Response13');
|
716
|
+
this.setStates();
|
717
|
+
cleanup();
|
718
|
+
return resolve(true);
|
719
|
+
}
|
720
|
+
break;
|
721
|
+
|
722
|
+
case 16:
|
723
|
+
this.log.debug('➡️ State 16: Zweiter Tower – NOP + Wartezeit');
|
724
|
+
this.decodePacketNOP(data);
|
725
|
+
socket.setTimeout(waitTime + timeout);
|
726
|
+
await new Promise(res => setTimeout(res, waitTime));
|
727
|
+
await sendRequest(4, 17, 0);
|
728
|
+
break;
|
729
|
+
|
730
|
+
case 17:
|
731
|
+
this.log.debug('➡️ State 17: NOP');
|
732
|
+
this.decodePacketNOP(data);
|
733
|
+
await sendRequest(5, 18);
|
734
|
+
break;
|
735
|
+
|
736
|
+
case 18:
|
737
|
+
this.log.debug('➡️ State 18: Paket 5 (Tower 2)');
|
738
|
+
this.decodePacket5(data, 1);
|
739
|
+
await sendRequest(6, 19);
|
740
|
+
break;
|
741
|
+
|
742
|
+
case 19:
|
743
|
+
this.log.debug('➡️ State 19: Paket 6 (Tower 2)');
|
744
|
+
this.decodePacket6(data, 1);
|
745
|
+
await sendRequest(7, 20);
|
746
|
+
break;
|
747
|
+
|
748
|
+
case 20:
|
749
|
+
this.log.debug('➡️ State 20: Paket 7 (Tower 2)');
|
750
|
+
this.decodePacket7(data, 1);
|
751
|
+
await sendRequest(8, 22);
|
752
|
+
break;
|
753
|
+
|
754
|
+
case 22:
|
755
|
+
this.log.debug('➡️ State 22: Paket 8 (Tower 2)');
|
756
|
+
this.decodePacket8(data, 1);
|
757
|
+
this.log.debug('✅ Alle Daten erfolgreich verarbeitet');
|
758
|
+
this.setStates();
|
759
|
+
cleanup();
|
760
|
+
return resolve(true);
|
761
|
+
|
762
|
+
default:
|
763
|
+
this.log.warn(`❓ Unerwarteter Zustand: ${myState}`);
|
764
|
+
cleanup();
|
765
|
+
return resolve(false);
|
766
|
+
}
|
767
|
+
}
|
768
|
+
} catch (err) {
|
769
|
+
this.log.error(`❌ Fehler im Ablauf: ${err.message}`);
|
770
|
+
this.log.debug(err.stack);
|
771
|
+
this.setStateChanged('info.connection', { val: false, ack: true });
|
772
|
+
cleanup();
|
773
|
+
return resolve(false);
|
774
|
+
}
|
775
|
+
});
|
776
|
+
} catch (err) {
|
777
|
+
this.log.error(`❌ Socket konnte nicht verbunden werden: ${err.message}`);
|
778
|
+
this.log.debug(err.stack);
|
779
|
+
this.setStateChanged('info.connection', { val: false, ack: true });
|
780
|
+
cleanup();
|
781
|
+
return resolve(false);
|
782
|
+
}
|
783
|
+
});
|
784
|
+
}
|
785
|
+
|
786
|
+
async pollQuery() {
|
787
|
+
if (myState > 0) {
|
788
|
+
return;
|
789
|
+
}
|
790
|
+
|
791
|
+
// Prüfe und ggf. setze neues Poll-Intervall
|
792
|
+
if (ConfOverridePollInterval !== 0) {
|
793
|
+
const state = await this.getState('System.OverridePoll');
|
794
|
+
const newPollTime = state?.val ?? 60;
|
795
|
+
|
796
|
+
if (confBatPollTime !== newPollTime) {
|
797
|
+
confBatPollTime = newPollTime;
|
798
|
+
clearInterval(idInterval1);
|
799
|
+
idInterval1 = setInterval(() => this.startPoll(), confBatPollTime * 1000);
|
800
|
+
this.log.info(`Poll-Intervall aktualisiert: ${confBatPollTime}s, Interval-ID: ${idInterval1}`);
|
801
|
+
}
|
802
|
+
}
|
803
|
+
|
804
|
+
myState = 1;
|
805
|
+
myNumberforDetails++;
|
806
|
+
|
807
|
+
this.log.debug(`myNumberforDetails: ${myNumberforDetails}`);
|
808
|
+
this.log.debug(`Starte Polling an IP: ${this.config.ConfIPAdress}`);
|
809
|
+
|
810
|
+
// Tower-Attribute initialisieren
|
811
|
+
towerAttributes = Array.from({ length: ConfBydTowerCount }, (_, i) => {
|
812
|
+
this.log.debug(`Initialisiere Tower ${i}`);
|
813
|
+
return {
|
814
|
+
hvsBatteryVoltsperCell: [],
|
815
|
+
hvsBatteryTempperCell: [],
|
816
|
+
};
|
817
|
+
});
|
818
|
+
|
819
|
+
const socketConnection = await this.setupIPClientHandlers();
|
820
|
+
await this.setStateAsync('info.socketConnection', socketConnection, true);
|
821
|
+
}
|
822
|
+
|
823
|
+
/*
|
824
|
+
* Calculate default deviation / Standardabweichung
|
825
|
+
*/
|
826
|
+
calcDeviation(array) {
|
827
|
+
if (!Array.isArray(array) || array.length === 0) {
|
828
|
+
return 0;
|
829
|
+
}
|
830
|
+
|
831
|
+
const n = array.length;
|
832
|
+
const mean = array.reduce((sum, val) => sum + val, 0) / n;
|
833
|
+
const variance = array.reduce((acc, val) => acc + Math.pow(val - mean, 2), 0) / (n > 1 ? n - 1 : 1);
|
834
|
+
|
835
|
+
return Math.sqrt(variance);
|
836
|
+
}
|
837
|
+
|
838
|
+
/*
|
839
|
+
* Calculate the average / mean
|
840
|
+
*/
|
841
|
+
calcAverage(array) {
|
842
|
+
if (!Array.isArray(array) || array.length === 0) {
|
843
|
+
return 0;
|
844
|
+
}
|
845
|
+
return array.reduce((a, b) => a + b, 0) / array.length;
|
846
|
+
}
|
847
|
+
|
848
|
+
decodePacket2(data) {
|
849
|
+
if (this.config.ConfStoreRawMessages) {
|
850
|
+
this.setState('System.Raw_02', data.toString('hex'), true);
|
851
|
+
}
|
852
|
+
const byteArray = new Uint8Array(data);
|
853
|
+
hvsBattType = byteArray[5];
|
854
|
+
hvsInvType = byteArray[3];
|
855
|
+
hvsNumCells = 0;
|
856
|
+
hvsNumTemps = 0;
|
857
|
+
switch (hvsBattType) {
|
858
|
+
case 0: //HVL -> unknown specification, so 0 cells and 0 temps
|
859
|
+
//hvsNumCells = 0;
|
860
|
+
//hvsNumTemps = 0;
|
861
|
+
//see above, is default
|
862
|
+
break;
|
863
|
+
case 1: //HVM 16 Cells per module
|
864
|
+
hvsNumCells = hvsModules * 16;
|
865
|
+
hvsNumTemps = hvsModules * 8;
|
866
|
+
break;
|
867
|
+
//crosscheck
|
868
|
+
// 5 modules, 80 voltages, 40 temps
|
869
|
+
case 2: //HVS 32 cells per module
|
870
|
+
hvsNumCells = hvsModules * 32;
|
871
|
+
hvsNumTemps = hvsModules * 12;
|
872
|
+
break;
|
873
|
+
//crosscheck:
|
874
|
+
//Counts from real data:
|
875
|
+
//mine: 2 modules, 64 voltages, 24 temps
|
876
|
+
//4 modules, 128 voltages, 48 temps
|
877
|
+
}
|
878
|
+
//leider hässlich dazugestrickt, wollte in die andere Logik nicht eingreifen
|
879
|
+
if (hvsBattType_fromSerial == 'LVS') {
|
880
|
+
hvsBattType = 'LVS';
|
881
|
+
hvsNumCells = hvsModules * 7;
|
882
|
+
hvsNumTemps = 0;
|
883
|
+
}
|
884
|
+
if (hvsBattType_fromSerial == 'LVS') {
|
885
|
+
//unterschiedliche WR-Tabelle je nach Batt-Typ
|
886
|
+
hvsInvType_String = myINVsLVS[hvsInvType];
|
887
|
+
} else {
|
888
|
+
hvsInvType_String = myINVs[hvsInvType];
|
889
|
+
}
|
890
|
+
if (hvsInvType_String == undefined) {
|
891
|
+
hvsInvType_String = 'undefined';
|
892
|
+
}
|
893
|
+
|
894
|
+
if (hvsNumCells > 160) {
|
895
|
+
hvsNumCells = 160;
|
896
|
+
}
|
897
|
+
if (hvsNumTemps > 64) {
|
898
|
+
hvsNumTemps = 64;
|
899
|
+
}
|
900
|
+
if (ConfBatDetails && _firstRun) {
|
901
|
+
_firstRun = false;
|
902
|
+
this.setObjectsCells();
|
903
|
+
}
|
904
|
+
this.log.debug(`NumCells: ${hvsNumCells} Numtemps: ${hvsNumTemps} Modules: ${hvsModules}`);
|
905
|
+
}
|
906
|
+
|
907
|
+
setObjectsCells() {
|
908
|
+
//Diagnose-data only if necessary.
|
909
|
+
let myObjects = [];
|
910
|
+
let ObjTowerString = '';
|
911
|
+
|
912
|
+
for (let towerNumber = 0; towerNumber < ConfBydTowerCount; towerNumber++) {
|
913
|
+
if (ConfBydTowerCount > 1) {
|
914
|
+
ObjTowerString = `.Tower_${towerNumber + 1}`;
|
915
|
+
}
|
916
|
+
myObjects = [
|
917
|
+
[
|
918
|
+
`Diagnosis${ObjTowerString}.mVoltMax`,
|
919
|
+
'state',
|
920
|
+
'Max Cell Voltage (mv)',
|
921
|
+
'number',
|
922
|
+
'value.voltage',
|
923
|
+
true,
|
924
|
+
false,
|
925
|
+
'mV',
|
926
|
+
],
|
927
|
+
[
|
928
|
+
`Diagnosis${ObjTowerString}.mVoltMin`,
|
929
|
+
'state',
|
930
|
+
'Min Cell Voltage (mv)',
|
931
|
+
'number',
|
932
|
+
'value.voltage',
|
933
|
+
true,
|
934
|
+
false,
|
935
|
+
'mV',
|
936
|
+
],
|
937
|
+
[
|
938
|
+
`Diagnosis${ObjTowerString}.mVoltMaxCell`,
|
939
|
+
'state',
|
940
|
+
'Max Cell Volt (Cellnr)',
|
941
|
+
'number',
|
942
|
+
'value.voltage',
|
943
|
+
true,
|
944
|
+
false,
|
945
|
+
'',
|
946
|
+
],
|
947
|
+
[
|
948
|
+
`Diagnosis${ObjTowerString}.mVoltMinCell`,
|
949
|
+
'state',
|
950
|
+
'Min Cell Volt (Cellnr)',
|
951
|
+
'number',
|
952
|
+
'value.voltage',
|
953
|
+
true,
|
954
|
+
false,
|
955
|
+
'',
|
956
|
+
],
|
957
|
+
[
|
958
|
+
`Diagnosis${ObjTowerString}.TempMax`,
|
959
|
+
'state',
|
960
|
+
'Max Cell Temperature',
|
961
|
+
'number',
|
962
|
+
'value.temperature',
|
963
|
+
true,
|
964
|
+
false,
|
965
|
+
'°C',
|
966
|
+
],
|
967
|
+
[
|
968
|
+
`Diagnosis${ObjTowerString}.TempMin`,
|
969
|
+
'state',
|
970
|
+
'Min Cell Temperature',
|
971
|
+
'number',
|
972
|
+
'value.temperature',
|
973
|
+
true,
|
974
|
+
false,
|
975
|
+
'°C',
|
976
|
+
],
|
977
|
+
[
|
978
|
+
`Diagnosis${ObjTowerString}.TempMaxCell`,
|
979
|
+
'state',
|
980
|
+
'Max Cell Temp (Cellnr)',
|
981
|
+
'number',
|
982
|
+
'value.temperature',
|
983
|
+
true,
|
984
|
+
false,
|
985
|
+
'',
|
986
|
+
],
|
987
|
+
[
|
988
|
+
`Diagnosis${ObjTowerString}.TempMinCell`,
|
989
|
+
'state',
|
990
|
+
'Min Cell Temp(Cellnr)',
|
991
|
+
'number',
|
992
|
+
'value.temperature',
|
993
|
+
true,
|
994
|
+
false,
|
995
|
+
'',
|
996
|
+
],
|
997
|
+
|
998
|
+
[
|
999
|
+
`Diagnosis${ObjTowerString}.mVoltDefDeviation`,
|
1000
|
+
'state',
|
1001
|
+
'voltage std-dev of the cells',
|
1002
|
+
'number',
|
1003
|
+
'value.voltage',
|
1004
|
+
true,
|
1005
|
+
false,
|
1006
|
+
'mV',
|
1007
|
+
],
|
1008
|
+
[
|
1009
|
+
`Diagnosis${ObjTowerString}.TempDefDeviation`,
|
1010
|
+
'state',
|
1011
|
+
'temperature std-dev of the cells',
|
1012
|
+
'number',
|
1013
|
+
'value.temperature',
|
1014
|
+
true,
|
1015
|
+
false,
|
1016
|
+
'°C',
|
1017
|
+
],
|
1018
|
+
[
|
1019
|
+
`Diagnosis${ObjTowerString}.mVoltMean`,
|
1020
|
+
'state',
|
1021
|
+
'mean voltage of the cells',
|
1022
|
+
'number',
|
1023
|
+
'value.voltage',
|
1024
|
+
true,
|
1025
|
+
false,
|
1026
|
+
'mV',
|
1027
|
+
],
|
1028
|
+
[
|
1029
|
+
`Diagnosis${ObjTowerString}.TempMean`,
|
1030
|
+
'state',
|
1031
|
+
'mean temperature of the cells',
|
1032
|
+
'number',
|
1033
|
+
'value.temperature',
|
1034
|
+
true,
|
1035
|
+
false,
|
1036
|
+
'°C',
|
1037
|
+
],
|
1038
|
+
[
|
1039
|
+
`Diagnosis${ObjTowerString}.mVoltGt150DefVar`,
|
1040
|
+
'state',
|
1041
|
+
'#cells voltage above 150% std-dev',
|
1042
|
+
'number',
|
1043
|
+
'value.voltage',
|
1044
|
+
true,
|
1045
|
+
false,
|
1046
|
+
'',
|
1047
|
+
],
|
1048
|
+
[
|
1049
|
+
`Diagnosis${ObjTowerString}.mVoltLt150DefVar`,
|
1050
|
+
'state',
|
1051
|
+
'#cells voltage below 150% std-dev',
|
1052
|
+
'number',
|
1053
|
+
'value.voltage',
|
1054
|
+
true,
|
1055
|
+
false,
|
1056
|
+
'',
|
1057
|
+
],
|
1058
|
+
[
|
1059
|
+
`Diagnosis${ObjTowerString}.TempGt150DefVar`,
|
1060
|
+
'state',
|
1061
|
+
'#cells temperature above 150% std-dev',
|
1062
|
+
'number',
|
1063
|
+
'value.temperature',
|
1064
|
+
true,
|
1065
|
+
false,
|
1066
|
+
'',
|
1067
|
+
],
|
1068
|
+
[
|
1069
|
+
`Diagnosis${ObjTowerString}.TempLt150DefVar`,
|
1070
|
+
'state',
|
1071
|
+
'#cells temperature below 150% std-dev',
|
1072
|
+
'number',
|
1073
|
+
'value.temperature',
|
1074
|
+
true,
|
1075
|
+
false,
|
1076
|
+
'',
|
1077
|
+
],
|
1078
|
+
|
1079
|
+
[
|
1080
|
+
`Diagnosis${ObjTowerString}.ChargeTotal`,
|
1081
|
+
'state',
|
1082
|
+
'Total Charge in that tower',
|
1083
|
+
'number',
|
1084
|
+
'value.watt',
|
1085
|
+
true,
|
1086
|
+
false,
|
1087
|
+
'',
|
1088
|
+
],
|
1089
|
+
[
|
1090
|
+
`Diagnosis${ObjTowerString}.DischargeTotal`,
|
1091
|
+
'state',
|
1092
|
+
'Total Discharge in that tower',
|
1093
|
+
'number',
|
1094
|
+
'value.watt',
|
1095
|
+
true,
|
1096
|
+
false,
|
1097
|
+
'',
|
1098
|
+
],
|
1099
|
+
[`Diagnosis${ObjTowerString}.ETA`, 'state', 'ETA of that tower', 'number', 'value', true, false, ''],
|
1100
|
+
[
|
1101
|
+
`Diagnosis${ObjTowerString}.BatteryVolt`,
|
1102
|
+
'state',
|
1103
|
+
'Voltage of that tower',
|
1104
|
+
'number',
|
1105
|
+
'value',
|
1106
|
+
true,
|
1107
|
+
false,
|
1108
|
+
'',
|
1109
|
+
],
|
1110
|
+
[`Diagnosis${ObjTowerString}.OutVolt`, 'state', 'Output voltage', 'number', 'value', true, false, ''],
|
1111
|
+
[
|
1112
|
+
`Diagnosis${ObjTowerString}.SOC`,
|
1113
|
+
'state',
|
1114
|
+
'SOC (Diagnosis)',
|
1115
|
+
'number',
|
1116
|
+
'value.battery',
|
1117
|
+
true,
|
1118
|
+
false,
|
1119
|
+
'%',
|
1120
|
+
],
|
1121
|
+
|
1122
|
+
[`Diagnosis${ObjTowerString}.SOH`, 'state', 'State of Health', 'number', 'value', true, false, ''],
|
1123
|
+
[`Diagnosis${ObjTowerString}.State`, 'state', 'tower state', 'string', 'value', true, false, ''],
|
1124
|
+
[
|
1125
|
+
`Diagnosis${ObjTowerString}.BalancingCells`,
|
1126
|
+
'state',
|
1127
|
+
'bitmask of balanced cells',
|
1128
|
+
'string',
|
1129
|
+
'value',
|
1130
|
+
true,
|
1131
|
+
false,
|
1132
|
+
'',
|
1133
|
+
],
|
1134
|
+
[
|
1135
|
+
`Diagnosis${ObjTowerString}.BalancingCellsCount`,
|
1136
|
+
'state',
|
1137
|
+
'number of currently balanced cells',
|
1138
|
+
'number',
|
1139
|
+
'value',
|
1140
|
+
true,
|
1141
|
+
false,
|
1142
|
+
'',
|
1143
|
+
],
|
1144
|
+
[`Diagnosis${ObjTowerString}.BalancingOne`, 'state', 'tower state', 'string', 'value', true, false, ''],
|
1145
|
+
[`Diagnosis${ObjTowerString}.BalancingTwo`, 'state', 'tower state', 'string', 'value', true, false, ''],
|
1146
|
+
[
|
1147
|
+
`Diagnosis${ObjTowerString}.BalancingCountOne`,
|
1148
|
+
'state',
|
1149
|
+
'tower state',
|
1150
|
+
'number',
|
1151
|
+
'value',
|
1152
|
+
true,
|
1153
|
+
false,
|
1154
|
+
'',
|
1155
|
+
],
|
1156
|
+
[
|
1157
|
+
`Diagnosis${ObjTowerString}.BalancingCountTwo`,
|
1158
|
+
'state',
|
1159
|
+
'tower state',
|
1160
|
+
'number',
|
1161
|
+
'value',
|
1162
|
+
true,
|
1163
|
+
false,
|
1164
|
+
'',
|
1165
|
+
],
|
1166
|
+
];
|
1167
|
+
|
1168
|
+
for (let i = 0; i < myObjects.length; i++) {
|
1169
|
+
this.setObjectNotExists(myObjects[i][0], {
|
1170
|
+
type: myObjects[i][1],
|
1171
|
+
common: {
|
1172
|
+
name: myObjects[i][2],
|
1173
|
+
type: myObjects[i][3],
|
1174
|
+
role: myObjects[i][4],
|
1175
|
+
read: myObjects[i][5],
|
1176
|
+
write: myObjects[i][6],
|
1177
|
+
unit: myObjects[i][7],
|
1178
|
+
},
|
1179
|
+
native: {},
|
1180
|
+
});
|
1181
|
+
}
|
1182
|
+
for (let i = 0; i < myObjects.length; i++) {
|
1183
|
+
//console.log("****extend " + i + " " + myObjects[i][0] + " " + myObjects[i][7]);
|
1184
|
+
this.checkandrepairUnit(myObjects[i][0], myObjects[i][7], myObjects[i][5], myObjects[i][2]);
|
1185
|
+
}
|
1186
|
+
|
1187
|
+
for (let i = 1; i <= hvsNumCells; i++) {
|
1188
|
+
this.setObjectNotExists(`CellDetails${ObjTowerString}.CellVolt${this.pad(i, 3)}`, {
|
1189
|
+
type: 'state',
|
1190
|
+
common: {
|
1191
|
+
name: `Voltage Cell: ${this.pad(i, 3)}`,
|
1192
|
+
type: 'number',
|
1193
|
+
role: 'value.voltage',
|
1194
|
+
read: true,
|
1195
|
+
write: false,
|
1196
|
+
unit: 'mV',
|
1197
|
+
},
|
1198
|
+
native: {},
|
1199
|
+
});
|
1200
|
+
this.checkandrepairUnit(
|
1201
|
+
`CellDetails${ObjTowerString}.CellVolt${this.pad(i, 3)}`,
|
1202
|
+
'mV',
|
1203
|
+
'value.voltage',
|
1204
|
+
); //repair forgotten units in first version
|
1205
|
+
|
1206
|
+
for (let i = 1; i <= hvsNumTemps; i++) {
|
1207
|
+
this.setObjectNotExists(`CellDetails${ObjTowerString}.CellTemp${this.pad(i, 3)}`, {
|
1208
|
+
type: 'state',
|
1209
|
+
common: {
|
1210
|
+
name: `Temp Cell: ${this.pad(i, 3)}`,
|
1211
|
+
type: 'number',
|
1212
|
+
role: 'value.temperature',
|
1213
|
+
read: true,
|
1214
|
+
write: false,
|
1215
|
+
unit: '°C',
|
1216
|
+
},
|
1217
|
+
native: {},
|
1218
|
+
});
|
1219
|
+
this.checkandrepairUnit(
|
1220
|
+
`CellDetails${ObjTowerString}.CellTemp${this.pad(i, 3)}`,
|
1221
|
+
'°C',
|
1222
|
+
'value.temperature',
|
1223
|
+
); //repair forgotten units in first version
|
1224
|
+
}
|
1225
|
+
}
|
1226
|
+
}
|
1227
|
+
}
|
1228
|
+
|
1229
|
+
decodePacket5(data, towerNumber = 0) {
|
1230
|
+
const byteArray = new Uint8Array(data);
|
1231
|
+
towerAttributes[towerNumber].hvsMaxmVolt = this.buf2int16SI(byteArray, 5);
|
1232
|
+
towerAttributes[towerNumber].hvsMinmVolt = this.buf2int16SI(byteArray, 7);
|
1233
|
+
towerAttributes[towerNumber].hvsMaxmVoltCell = byteArray[9];
|
1234
|
+
towerAttributes[towerNumber].hvsMinmVoltCell = byteArray[10];
|
1235
|
+
towerAttributes[towerNumber].hvsMaxmTemp = this.buf2int16SI(byteArray, 11);
|
1236
|
+
towerAttributes[towerNumber].hvsMinmTemp = this.buf2int16SI(byteArray, 13);
|
1237
|
+
towerAttributes[towerNumber].hvsMaxTempCell = byteArray[15];
|
1238
|
+
towerAttributes[towerNumber].hvsMinTempCell = byteArray[16];
|
1239
|
+
|
1240
|
+
//starting with byte 101, ending with 131, Cell voltage 1-16
|
1241
|
+
const MaxCells = 16;
|
1242
|
+
for (let i = 0; i < MaxCells; i++) {
|
1243
|
+
this.log.silly(`Battery Voltage-${this.pad(i + 1, 3)} :${this.buf2int16SI(byteArray, i * 2 + 101)}`);
|
1244
|
+
towerAttributes[towerNumber].hvsBatteryVoltsperCell[i + 1] = this.buf2int16SI(byteArray, i * 2 + 101);
|
1245
|
+
}
|
1246
|
+
|
1247
|
+
// Balancing Flags
|
1248
|
+
// 17 bis 32
|
1249
|
+
towerAttributes[towerNumber].balancing = data.slice(17, 33).toString('hex');
|
1250
|
+
towerAttributes[towerNumber].balancingcount = this.countSetBits(data.slice(17, 33).toString('hex'));
|
1251
|
+
|
1252
|
+
towerAttributes[towerNumber].chargeTotal = this.buf2int32US(byteArray, 33);
|
1253
|
+
towerAttributes[towerNumber].dischargeTotal = this.buf2int32US(byteArray, 37);
|
1254
|
+
towerAttributes[towerNumber].eta =
|
1255
|
+
towerAttributes[towerNumber].dischargeTotal / towerAttributes[towerNumber].chargeTotal;
|
1256
|
+
towerAttributes[towerNumber].batteryVolt = this.buf2int16SI(byteArray, 45);
|
1257
|
+
towerAttributes[towerNumber].outVolt = this.buf2int16SI(byteArray, 51);
|
1258
|
+
towerAttributes[towerNumber].hvsSOCDiagnosis = parseFloat(
|
1259
|
+
((this.buf2int16SI(byteArray, 53) * 1.0) / 10.0).toFixed(1),
|
1260
|
+
);
|
1261
|
+
towerAttributes[towerNumber].soh = parseFloat((this.buf2int16SI(byteArray, 55) * 1.0).toFixed(1));
|
1262
|
+
towerAttributes[towerNumber].state = byteArray[59].toString(16) + byteArray[60].toString(16);
|
1263
|
+
}
|
1264
|
+
|
1265
|
+
decodePacket6(data, towerNumber = 0) {
|
1266
|
+
const byteArray = new Uint8Array(data);
|
1267
|
+
// e.g. hvsNumCells = 80
|
1268
|
+
// first Voltage in byte 5+6
|
1269
|
+
// Count = 80-17 --> 63
|
1270
|
+
let MaxCells = hvsNumCells - 16; //0 to n-1 is the same like 1 to n
|
1271
|
+
if (MaxCells > 64) {
|
1272
|
+
MaxCells = 64;
|
1273
|
+
}
|
1274
|
+
for (let i = 0; i < MaxCells; i++) {
|
1275
|
+
this.log.silly(`Battery Voltage-${this.pad(i + 17, 3)} :${this.buf2int16SI(byteArray, i * 2 + 5)}`);
|
1276
|
+
towerAttributes[towerNumber].hvsBatteryVoltsperCell[i + 17] = this.buf2int16SI(byteArray, i * 2 + 5);
|
1277
|
+
}
|
1278
|
+
}
|
1279
|
+
|
1280
|
+
decodePacket7(data, towerNumber = 0) {
|
1281
|
+
const byteArray = new Uint8Array(data);
|
1282
|
+
//starting with byte 5, ending 101, voltage for cell 81 to 128
|
1283
|
+
//starting with byte 103, ending 132, temp for cell 1 to 30
|
1284
|
+
|
1285
|
+
// e.g. hvsNumCells = 128
|
1286
|
+
// first Voltage in byte 5+6
|
1287
|
+
// Count = 128-80 --> 48
|
1288
|
+
let MaxCells = hvsNumCells - 80; //0 to n-1 is the same like 1 to n
|
1289
|
+
if (MaxCells > 48) {
|
1290
|
+
MaxCells = 48;
|
1291
|
+
}
|
1292
|
+
this.log.silly(`hvsModules =${hvsModules} maxCells= ${MaxCells}`);
|
1293
|
+
for (let i = 0; i < MaxCells; i++) {
|
1294
|
+
this.log.silly(`Battery Voltage-${this.pad(i + 81, 3)} :${this.buf2int16SI(byteArray, i * 2 + 5)}`);
|
1295
|
+
towerAttributes[towerNumber].hvsBatteryVoltsperCell[i + 81] = this.buf2int16SI(byteArray, i * 2 + 5);
|
1296
|
+
}
|
1297
|
+
|
1298
|
+
let MaxTemps = hvsNumTemps - 0; //0 to n-1 is the same like 1 to n
|
1299
|
+
if (MaxTemps > 30) {
|
1300
|
+
MaxTemps = 30;
|
1301
|
+
}
|
1302
|
+
this.log.silly(`hvsModules =${hvsModules} MaxTemps= ${MaxTemps}`);
|
1303
|
+
for (let i = 0; i < MaxTemps; i++) {
|
1304
|
+
this.log.silly(`Battery Temp ${this.pad(i + 1, 3)} :${byteArray[i + 103]}`);
|
1305
|
+
towerAttributes[towerNumber].hvsBatteryTempperCell[i + 1] = byteArray[i + 103];
|
1306
|
+
}
|
1307
|
+
}
|
1308
|
+
|
1309
|
+
decodePacket8(data, towerNumber = 0) {
|
1310
|
+
const byteArray = new Uint8Array(data);
|
1311
|
+
let MaxTemps = hvsNumTemps - 30; //0 to n-1 is the same like 1 to n
|
1312
|
+
if (MaxTemps > 34) {
|
1313
|
+
MaxTemps = 34;
|
1314
|
+
}
|
1315
|
+
this.log.silly(`hvsModules =${hvsModules} MaxTemps= ${MaxTemps}`);
|
1316
|
+
for (let i = 0; i < MaxTemps; i++) {
|
1317
|
+
this.log.silly(`Battery Temp ${this.pad(i + 31, 3)} :${byteArray[i + 5]}`);
|
1318
|
+
towerAttributes[towerNumber].hvsBatteryTempperCell[i + 31] = byteArray[i + 5];
|
1319
|
+
}
|
1320
|
+
}
|
1321
|
+
|
1322
|
+
/*
|
1323
|
+
* decode response to request[12]
|
1324
|
+
* @see #decodePacket5()
|
1325
|
+
*/
|
1326
|
+
decodeResponse12(data, towerNumber = 0) {
|
1327
|
+
const byteArray = new Uint8Array(data);
|
1328
|
+
//starting with byte 101, ending with 131, Cell voltage 129-144
|
1329
|
+
|
1330
|
+
// Balancing Flags
|
1331
|
+
towerAttributes[towerNumber].balancing = data.slice(17, 33).toString('hex');
|
1332
|
+
towerAttributes[towerNumber].balancingcount = this.countSetBits(data.slice(17, 33).toString('hex'));
|
1333
|
+
|
1334
|
+
const MaxCells = 16;
|
1335
|
+
for (let i = 0; i < MaxCells; i++) {
|
1336
|
+
this.log.silly(`Battery Voltage-${this.pad(i + 1 + 128, 3)} :${this.buf2int16SI(byteArray, i * 2 + 101)}`);
|
1337
|
+
towerAttributes[towerNumber].hvsBatteryVoltsperCell[i + 1 + 128] = this.buf2int16SI(byteArray, i * 2 + 101);
|
1338
|
+
}
|
1339
|
+
}
|
1340
|
+
|
1341
|
+
/*
|
1342
|
+
* decode response to request[13]
|
1343
|
+
* @see #decodePacket6()
|
1344
|
+
*/
|
1345
|
+
decodeResponse13(data, towerNumber = 0) {
|
1346
|
+
const byteArray = new Uint8Array(data);
|
1347
|
+
let MaxCells = hvsNumCells - 128 - 16; // The first round measured up to 128 cells, request[12] then get another 16
|
1348
|
+
if (MaxCells > 16) {
|
1349
|
+
MaxCells = 16;
|
1350
|
+
} // With 5 HVS Modules, only 16 cells are remaining
|
1351
|
+
for (let i = 0; i < MaxCells; i++) {
|
1352
|
+
this.log.silly(
|
1353
|
+
`Battery Voltage-${this.pad(i + 1 + 16 + 128, 3)} :${this.buf2int16SI(byteArray, i * 2 + 5)}`,
|
1354
|
+
);
|
1355
|
+
towerAttributes[towerNumber].hvsBatteryVoltsperCell[i + 1 + 16 + 128] = this.buf2int16SI(
|
1356
|
+
byteArray,
|
1357
|
+
i * 2 + 5,
|
1358
|
+
);
|
1359
|
+
}
|
1360
|
+
}
|
1361
|
+
|
1362
|
+
decodePacket0(data) {
|
1363
|
+
if (this.config.ConfStoreRawMessages) {
|
1364
|
+
this.setState('System.Raw_00', data.toString('hex'), true);
|
1365
|
+
}
|
1366
|
+
const byteArray = new Uint8Array(data);
|
1367
|
+
|
1368
|
+
// Serialnumber
|
1369
|
+
hvsSerial = '';
|
1370
|
+
for (let i = 3; i < 22; i++) {
|
1371
|
+
hvsSerial += String.fromCharCode(byteArray[i]);
|
1372
|
+
}
|
1373
|
+
|
1374
|
+
// Hardwaretype
|
1375
|
+
//leider dazugestrickt, wollte in die andere Logik nicht eingreifen
|
1376
|
+
if (byteArray[5] == 51) {
|
1377
|
+
hvsBattType_fromSerial = 'HVS';
|
1378
|
+
}
|
1379
|
+
if (byteArray[5] == 50) {
|
1380
|
+
hvsBattType_fromSerial = 'LVS';
|
1381
|
+
}
|
1382
|
+
if (byteArray[5] == 49) {
|
1383
|
+
hvsBattType_fromSerial = 'LVS';
|
1384
|
+
}
|
1385
|
+
|
1386
|
+
// Firmwareversion
|
1387
|
+
hvsBMUA = `V${byteArray[27].toString()}.${byteArray[28].toString()}`;
|
1388
|
+
hvsBMUB = `V${byteArray[29].toString()}.${byteArray[30].toString()}`;
|
1389
|
+
if (byteArray[33] === 0) {
|
1390
|
+
hvsBMU = `${hvsBMUA}-A`;
|
1391
|
+
} else {
|
1392
|
+
hvsBMU = `${hvsBMUB}-B`;
|
1393
|
+
}
|
1394
|
+
hvsBMS = `V${byteArray[31].toString()}.${byteArray[32].toString()}-${String.fromCharCode(byteArray[34] + 65)}`;
|
1395
|
+
|
1396
|
+
// Amount of towers
|
1397
|
+
// 1st Byte - Count of towers
|
1398
|
+
// 2nd Byte - Amount of Modules (per Tower)
|
1399
|
+
hvsModules = parseInt((byteArray[36] % 16).toString());
|
1400
|
+
hvsTowers = parseInt(Math.floor(byteArray[36] / 16).toString());
|
1401
|
+
|
1402
|
+
// Architecture type
|
1403
|
+
if (byteArray[38] === 0) {
|
1404
|
+
hvsGrid = 'OffGrid';
|
1405
|
+
}
|
1406
|
+
if (byteArray[38] === 1) {
|
1407
|
+
hvsGrid = 'OnGrid';
|
1408
|
+
}
|
1409
|
+
if (byteArray[38] === 2) {
|
1410
|
+
hvsGrid = 'Backup';
|
1411
|
+
}
|
1412
|
+
}
|
1413
|
+
|
1414
|
+
decodePacket1(data) {
|
1415
|
+
if (this.config.ConfStoreRawMessages) {
|
1416
|
+
this.setState('System.Raw_01', data.toString('hex'), true);
|
1417
|
+
}
|
1418
|
+
const byteArray = new Uint8Array(data);
|
1419
|
+
hvsSOC = this.buf2int16SI(byteArray, 3);
|
1420
|
+
hvsMaxVolt = parseFloat(((this.buf2int16SI(byteArray, 5) * 1.0) / 100.0).toFixed(2));
|
1421
|
+
hvsMinVolt = parseFloat(((this.buf2int16SI(byteArray, 7) * 1.0) / 100.0).toFixed(2));
|
1422
|
+
hvsSOH = this.buf2int16SI(byteArray, 9);
|
1423
|
+
hvsA = parseFloat(((this.buf2int16SI(byteArray, 11) * 1.0) / 10.0).toFixed(1));
|
1424
|
+
hvsBattVolt = parseFloat(((this.buf2int16US(byteArray, 13) * 1.0) / 100.0).toFixed(1));
|
1425
|
+
hvsMaxTemp = this.buf2int16SI(byteArray, 15);
|
1426
|
+
hvsMinTemp = this.buf2int16SI(byteArray, 17);
|
1427
|
+
hvsBatTemp = this.buf2int16SI(byteArray, 19);
|
1428
|
+
hvsError = this.buf2int16SI(byteArray, 29);
|
1429
|
+
hvsParamT = `${byteArray[31].toString()}.${byteArray[32].toString()}`;
|
1430
|
+
hvsOutVolt = parseFloat(((this.buf2int16US(byteArray, 35) * 1.0) / 100.0).toFixed(1));
|
1431
|
+
hvsPower = Math.round(hvsA * hvsOutVolt * 100) / 100;
|
1432
|
+
hvsDiffVolt = Math.round((hvsMaxVolt - hvsMinVolt) * 100) / 100;
|
1433
|
+
hvsErrorString = '';
|
1434
|
+
// hvsError = 65535;
|
1435
|
+
for (let j = 0; j < 16; j++) {
|
1436
|
+
if (((1 << j) & hvsError) !== 0) {
|
1437
|
+
if (hvsErrorString.length > 0) {
|
1438
|
+
hvsErrorString += '; ';
|
1439
|
+
}
|
1440
|
+
hvsErrorString += this.myErrors[j];
|
1441
|
+
}
|
1442
|
+
}
|
1443
|
+
if (hvsErrorString.length === 0) {
|
1444
|
+
hvsErrorString = 'no Error';
|
1445
|
+
}
|
1446
|
+
|
1447
|
+
hvsChargeTotal = this.buf2int32US(byteArray, 37) / 10;
|
1448
|
+
hvsDischargeTotal = this.buf2int32US(byteArray, 41) / 10;
|
1449
|
+
hvsETA = hvsDischargeTotal / hvsChargeTotal;
|
1450
|
+
}
|
1451
|
+
}
|
1452
|
+
|
1453
|
+
if (module.parent) {
|
1454
|
+
/**
|
1455
|
+
* @param [options]
|
1456
|
+
*/
|
1457
|
+
module.exports = options => new bydhvsControll(options);
|
1458
|
+
} else {
|
1459
|
+
// otherwise start the instance directly
|
1460
|
+
new bydhvsControll();
|
1461
|
+
}
|