-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathCharge-Control_Ver_1.6.10.js
More file actions
3002 lines (2699 loc) · 180 KB
/
Copy pathCharge-Control_Ver_1.6.10.js
File metadata and controls
3002 lines (2699 loc) · 180 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
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
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
'use strict';
// ============================================================================
// ============================ USER ANPASSUNGEN ==============================
// ============================================================================
const LogparserSyntax = true // Wenn true wird die LOG Ausgabe an Adapter Logparser angepasst
const instanzE3DC_RSCP = 'e3dc-rscp.0' // Instanz e3dc-rscp Adapter
const instanz = '0_userdata.0'; // Instanz Script Charge-Control
const PfadEbene1 = 'Charge_Control'; // Pfad innerhalb der Instanz
const PfadEbene2 = ['Parameter','Allgemein','History','Proplanta','USER_ANPASSUNGEN'] // Pfad innerhalb PfadEbene1
const idTibber = `${instanz}.TibberSkript`; // ObjektID Tibber Skript
// Berechnung Durchschnittsverbrauch
const BUFFER_SIZE= 60; // z.B. 60 Werte = 1 Minute (bei 1Hz Trigger)
const MAX_ENTRIES = 1440; // Maximale Anzahl gespeicherter Werte pro Tag/Nacht
const DAY_START = 5; // ab 05:00 = Tag
const NIGHT_START = 21; // ab 21:00 = Nacht
const HAUSVERBRAUCH_BUFFER_SIZE = 5; // für den gleitenden Durchschnitt
const HystereseBattSoc = 4; // Hysterese Wert um Batterie SOC Schwankungen auszugleichen
// ============================================================================
// ======================= ENDE USER ANPASSUNGEN ==============================
// ============================================================================
logChargeControl(`-==== Charge-Control Version 1.6.10 ====-`);
//*************************************** ID's Adapter e3dc.rscp ***************************************
const sID_Power_Home_W =`${instanzE3DC_RSCP}.EMS.POWER_HOME`; // aktueller Hausverbrauch E3DC // Pfad ist abhängig von Variable ScriptHausverbrauch siehe function CheckState()
const sID_Batterie_SOC =`${instanzE3DC_RSCP}.EMS.BAT_SOC`; // aktueller Batterie_SOC
const sID_PvLeistung_E3DC_W =`${instanzE3DC_RSCP}.EMS.POWER_PV`; // aktuelle PV_Leistung
const sID_PvLeistung_ADD_W =`${instanzE3DC_RSCP}.EMS.POWER_ADD`; // Zusätzliche Einspeiser Leistung
const sID_Power_Wallbox_W =`${instanzE3DC_RSCP}.EMS.POWER_WB_ALL`; // aktuelle Wallbox Leistung
const sID_Power_Bat_W = `${instanzE3DC_RSCP}.EMS.POWER_BAT`; // aktuelle Batterie_Leistung'
const sID_Installed_Peak_Power =`${instanzE3DC_RSCP}.EMS.INSTALLED_PEAK_POWER`; // Wp der installierten PV Module
const sID_Bat_Discharge_Limit =`${instanzE3DC_RSCP}.EMS.SYS_SPECS.maxBatDischargPower`; // Batterie Entladelimit
const sID_Bat_Charge_Limit =`${instanzE3DC_RSCP}.EMS.SYS_SPECS.maxBatChargePower`; // Batterie Ladelimit
const sID_Notrom_Status =`${instanzE3DC_RSCP}.EMS.EMERGENCY_POWER_STATUS`; // 0= nicht möglich 1=Aktiv 2= nicht Aktiv 3= nicht verfügbar 4=Inselbetrieb
const sID_SPECIFIED_Battery_Capacity_0 =`${instanzE3DC_RSCP}.BAT.BAT_0.SPECIFIED_CAPACITY`; // Installierte Batterie Kapazität Batteriekreis 0
const sID_SPECIFIED_Battery_Capacity_1 =`${instanzE3DC_RSCP}.BAT.BAT_1.SPECIFIED_CAPACITY`; // Installierte Batterie Kapazität Batteriekreis 1
const sID_FirmwareVersion =`${instanzE3DC_RSCP}.INFO.SW_RELEASE`; // Aktuelle Virmware Version E3DC
const sID_POWER_LIMITS_USED =`${instanzE3DC_RSCP}.EMS.POWER_LIMITS_USED`; // Leistungs-Limits aktiviert
const sID_Manual_Charge_Energy = `${instanzE3DC_RSCP}.EMS.MANUAL_CHARGE_ENERGY`; // Manuelle Ladung Batterie aus dem Netz
const sID_SET_POWER_MODE =`${instanzE3DC_RSCP}.EMS.SET_POWER_MODE`; // Lademodus
const sID_SET_POWER_VALUE_W =`${instanzE3DC_RSCP}.EMS.SET_POWER_VALUE`; // Eingestellte Ladeleistung
const sID_Max_wrleistung_W =`${instanzE3DC_RSCP}.EMS.SYS_SPECS.maxAcPower`; // Maximale Wechselrichter Leistung
const sID_Einspeiselimit_Pro =`${instanzE3DC_RSCP}.EMS.DERATE_AT_PERCENT_VALUE`; // Eingestellte Einspeisegrenze E3DC in Prozent
const sID_BAT0_Alterungszustand =`${instanzE3DC_RSCP}.BAT.BAT_0.ASOC`; // Batterie ASOC e3dc-rscp
const sID_Max_Discharge_Power_W =`${instanzE3DC_RSCP}.EMS.MAX_DISCHARGE_POWER`; // Eingestellte maximale Batterie-Entladeleistung. (Variable Einstellung E3DC)
const sID_Max_Charge_Power_W =`${instanzE3DC_RSCP}.EMS.MAX_CHARGE_POWER`; // Eingestellte maximale Batterie-Ladeleistung. (Variable Einstellung E3DC)
const sID_DISCHARGE_START_POWER =`${instanzE3DC_RSCP}.EMS.DISCHARGE_START_POWER`; // Anfängliche Batterie-Entladeleistung
let sID_PARAM_EP_RESERVE_W =`${instanzE3DC_RSCP}.EP.PARAM_0.PARAM_EP_RESERVE_ENERGY`; // Eingestellte Notstrom Reserve E3DC
const sID_Powersave =`${instanzE3DC_RSCP}.EMS.POWERSAVE_ENABLED`; // Powersave Modus
const sID_BattTraining = `${instanzE3DC_RSCP}.EMS.STATUS_9`; // Batterie Training aktiv
//************************************* ID's Skript ChargeControl *************************************
const sID_Saved_Power_W =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Saved_Power_W`; // Leistung die mit Charge-Control gerettet wurde
const sID_PVErtragLM2 =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Saved_PowerLM2_kWh`; // Leistungszähler für PV Leistung die mit Charge-Control gerettet wurde
const sID_Automatik_Prognose =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Automatik`; // Vorwahl in VIS true = automatik false = manuell
const sID_Automatik_Regelung =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Automatik_Regelung`; // Vorwahl in VIS true = automatik false = manuell
const sID_NotstromAusNetz =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.NotstromAusNetz`; // Vorwahl in VIS true = Notstrom aus Netz nachladen
const sID_EinstellungAnwahl =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.EinstellungAnwahl`; // Vorwahl in VIS Einstellung 1-5
const sID_PVErtragLM0 =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.IstPvErtragLM0_kWh`; // Leistungszähler PV-Leistung
const sID_PVErtragLM1 =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.IstPvErtragLM1_kWh`; // Leistungszähler zusätzlicher WR (extern)
const sID_PrognoseAnwahl =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.PrognoseAnwahl`; // Aktuelle Einstellung welche Prognose für Berechnung verwendet wird
const sID_EigenverbrauchDurchschnitt =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.EigenverbrauchDurchschnitt`; // Anzeige in VIS:Durchschnittlicher Eigenverbrauch Tag / Nacht
const sID_EigenverbrauchTag_kWh =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.EigenverbrauchTag`; // Einstellung täglicher Eigenverbrauch in VIS oder über anderes Script
const sID_HausverbrauchBereinigt_W = `${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Hausverbrauch`; // Reiner Hausverbrauch ohne WB, LW-Pumpe oder Heizstab
const sID_arrayHausverbrauchDurchschnitt = `${instanz}.${PfadEbene1}.${PfadEbene2[1]}.arrayHausverbrauchDurchschnitt`; // Array zum speichern vom durchschnittlicher Hausverbrauch ohne WB, LW-Pumpe oder Heizstab
const sID_arrayHausverbrauch = `${instanz}.${PfadEbene1}.${PfadEbene2[1]}.arrayHausverbrauch`; // Array zum speichern der Leistung Hausverbrauch ohne WB, LW-Pumpe oder Heizstab
const sID_AnzeigeHistoryMonat =`${instanz}.${PfadEbene1}.${PfadEbene2[2]}.HistorySelect`; // Vorwahl in VIS: Umschaltung der Monate im View Prognose
const sID_arrayPV_LeistungTag_kWh =`${instanz}.${PfadEbene1}.${PfadEbene2[2]}.istPV_LeistungTag_kWh`;
const sID_PrognoseProp_kWh =`${instanz}.${PfadEbene1}.${PfadEbene2[2]}.PrognoseProp_kWh`;
const sID_PrognoseAuto_kWh =`${instanz}.${PfadEbene1}.${PfadEbene2[2]}.PrognoseAuto_kWh`;
const sID_PrognoseSolcast90_kWh =`${instanz}.${PfadEbene1}.${PfadEbene2[2]}.PrognoseSolcast90_kWh`;
const sID_PrognoseSolcast_kWh =`${instanz}.${PfadEbene1}.${PfadEbene2[2]}.PrognoseSolcast_kWh`;
const sID_Regelbeginn_MEZ =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Regelbeginn_MEZ`; // Anzeige in VIS: Regelbeginn in MEZ Zeit
const sID_Regelende_MEZ =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Regelende_MEZ`; // Anzeige in VIS: Regelende in MEZ Zeit
const sID_Ladeende_MEZ =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Ladeende_MEZ`; // Anzeige in VIS: Ladeende in MEZ Zeit
const sID_Notstrom_min_Proz =`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.Notstrom_min`;
const sID_Notstrom_sockel_Proz =`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.Notstrom_sockel`;
const sID_Notstrom_akt =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Notstrom_akt`;
const sID_Autonomiezeit =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Autonomiezeit`; // Anzeige in VIS: Reichweite der Batterie bei entladung
const sID_AutonomiezeitDurchschnitt =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.AutonomiezeitDurchschnitt`; // Anzeige in VIS: Reichweite der Batterie bei entladung
const sID_BatSoc_kWh =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Batteriekapazität_kWh`; // Anzeige in VIS: Batteriekapazität in kWh
const sID_FirmwareDate =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.FirmwareDate`; // Anzeige in VIS: Firmware Datum
const sID_LastFirmwareVersion =`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.LastFirmwareVersion`; // Anzeige in VIS: Firmware Version
const sID_out_Akt_Ladeleistung_W=`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Akt_Berechnete_Ladeleistung_W`; // Ausgabe der berechneten Ladeleistung um diese in VIS anzuzeigen.
let sID_UntererLadekorridor_W =[],sID_Ladeschwelle_Proz =[],sID_Ladeende_Proz=[],sID_Ladeende2_Proz=[],sID_RegelbeginnOffset=[],sID_RegelendeOffset=[],sID_LadeendeOffset=[],sID_Unload_Proz=[];
for (let i = 0; i <= 5; i++) {
sID_UntererLadekorridor_W[i] =`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.UntererLadekorridor_${i}`;
sID_Ladeschwelle_Proz[i] =`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.Ladeschwelle_${i}`;
sID_Ladeende_Proz[i] =`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.Ladeende_${i}`;
sID_Ladeende2_Proz[i] =`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.Ladeende2_${i}`;
sID_RegelbeginnOffset[i] =`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.RegelbeginnOffset_${i}`;
sID_RegelendeOffset[i] =`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.RegelendeOffset_${i}`;
sID_LadeendeOffset[i] =`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.LadeendeOffset_${i}`;
sID_Unload_Proz[i] =`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.Unload_${i}`;
}
const arrayID_Notstrom =[sID_Notstrom_min_Proz,sID_Notstrom_sockel_Proz];
const arrayID_Parameters = [
[sID_UntererLadekorridor_W[0], sID_Ladeschwelle_Proz[0], sID_Ladeende_Proz[0], sID_Ladeende2_Proz[0], sID_RegelbeginnOffset[0], sID_RegelendeOffset[0], sID_LadeendeOffset[0], sID_Unload_Proz[0]],
[sID_UntererLadekorridor_W[1], sID_Ladeschwelle_Proz[1], sID_Ladeende_Proz[1], sID_Ladeende2_Proz[1], sID_RegelbeginnOffset[1], sID_RegelendeOffset[1], sID_LadeendeOffset[1], sID_Unload_Proz[1]],
[sID_UntererLadekorridor_W[2], sID_Ladeschwelle_Proz[2], sID_Ladeende_Proz[2], sID_Ladeende2_Proz[2], sID_RegelbeginnOffset[2], sID_RegelendeOffset[2], sID_LadeendeOffset[2], sID_Unload_Proz[2]],
[sID_UntererLadekorridor_W[3], sID_Ladeschwelle_Proz[3], sID_Ladeende_Proz[3], sID_Ladeende2_Proz[3], sID_RegelbeginnOffset[3], sID_RegelendeOffset[3], sID_LadeendeOffset[3], sID_Unload_Proz[3]],
[sID_UntererLadekorridor_W[4], sID_Ladeschwelle_Proz[4], sID_Ladeende_Proz[4], sID_Ladeende2_Proz[4], sID_RegelbeginnOffset[4], sID_RegelendeOffset[4], sID_LadeendeOffset[4], sID_Unload_Proz[4]],
[sID_UntererLadekorridor_W[5], sID_Ladeschwelle_Proz[5], sID_Ladeende_Proz[5], sID_Ladeende2_Proz[5], sID_RegelbeginnOffset[5], sID_RegelendeOffset[5], sID_LadeendeOffset[5], sID_Unload_Proz[5]],
];
// Flache Liste aller Parameter-IDs erstellen
const allParameterIDs = arrayID_Parameters.flat();
//************************************** Globale Variable ***************************************
// @ts-ignore
const fs = require('fs').promises;
// @ts-ignore
const axios = require('axios');
//******************** Globale Variable Array ********************
const idCache = {}
let hausverbrauchBuffer = []; // Buffer für Hausverbrauchswerte
let listeners = []; // Array zum Speichern aller Listener-Objekte
let homeConsumption = {};
let homeAverage = {};
let SummePV_Leistung_Tag_kW =[{0:'',1:'',2:'',3:'',4:'',5:'',6:'',7:''},{0:0,1:0,2:0,3:0,4:0,5:0,6:0,7:0},{0:0,1:0,2:0,3:0,4:0,5:0,6:0,7:0},{0:0,1:0,2:0,3:0,4:0,5:0,6:0,7:0}];
let baseUrlsCountrys = {
"de" : "https://www.proplanta.de/Wetter/profi-wetter.php?SITEID=60&PLZ=#PLZ#&STADT=#ORT#&WETTERaufrufen=stadt&Wtp=&SUCHE=Wetter&wT=0",
"at" : "https://www.proplanta.de/Wetter-Oesterreich/profi-wetter-at.php?SITEID=70&PLZ=#PLZ#&STADT=#ORT#&WETTERaufrufen=stadt&Wtp=&SUCHE=Wetter&wT=0",
"ch" : "https://www.proplanta.de/Wetter-Schweiz/profi-wetter-ch.php?SITEID=80&PLZ=#PLZ#&STADT=#ORT#&WETTERaufrufen=stadt&Wtp=&SUCHE=Wetter&wT=0",
};
let arrayPV_LeistungTag_kWh = new Array(32), arrayPrognoseProp_kWh = new Array(32), arrayPrognoseAuto_kWh = new Array(32);
let arrayPrognoseSolcast90_kWh = new Array(32), arrayPrognoseSolcast_kWh = new Array(32);
//******************** Globale Variable zuweisung in Funktion CheckState() ********************
let logflag,sLogPath,bLogAusgabe,bDebugAusgabe,bDebugAusgabeDetail,Offset_sunriseEnd_min,minWertPrognose_kWh,Entladetiefe_Pro;
let Systemwirkungsgrad_Pro,bScriptTibber,bEvcc,country,ProplantaOrt,ProplantaPlz,BewoelkungsgradGrenzwert,bSolcast;
let nModulFlaeche,nWirkungsgradModule,nKorrFaktor,nMinPvLeistungTag_kWh,nMaxPvLeistungTag_kWh;
let SolcastDachflaechen,Resource_Id_Dach=[],SolcastAPI_key,tibberMaxLadeleistungUser_W, startDischargeDefault;
let sID_LeistungHeizstab_W, sID_WallboxLadeLeistung_1_W,sID_WallboxLadeLeistung_2_W,sID_LeistungLW_Pumpe_W;
let sID_Path_evcc_loadpoint1_charging,sID_Path_evcc_loadpoint2_charging,sID_Path_evcc_mode1, sID_Path_evcc_mode2,sID_Path_ScriptTibber;
//******************************* Globale Variable Time Counter *******************************
let lastDebugLogTime = 0, lastExecutionTime = 0, count0 = 0, count1 = 0, count2 = 0, count3 = 0;
let Timer0 = null, Timer1 = null,Timer2 = null,TimerProplanta= null,TimerSolcast= null;
let RE_AstroSolarNoon,LE_AstroSunset,RB_AstroSolarNoon,RE_AstroSolarNoon_alt_milisek,RB_AstroSolarNoon_alt_milisek,Zeit_alt_milisek=0,ZeitE3DC_SetPowerAlt_ms=0;
//******************************* Globale Variable Boolean *******************************
let bStart = true, bM_Notstrom = false, bStoppTriggerParameter = false, bStoppTriggerEinstellungAnwahl =false, bNotstromVerwenden;
let bStatus_Notstrom_SOC=false, bLadenEntladenStoppen= false, bLadenEntladenStoppen_alt=false,bCharging_evcc = false;
let bM_Abriegelung = false, bLadenAufNotstromSOC = false, bHeuteNotstromVerbraucht = false, bCheckConfig = true, bBattTraining = false;
let bNotstromAusNetz, bAutomatikAnwahl, bAutomatikRegelung, bManuelleLadungBatt, bTibberLaden = false, bTibberEntladesperre = false,bRegelungAktiv = false;
//*********************************** Globale Variable ***********************************
let LogProgrammablauf = "", Notstrom_Status,m_Batt_SOC_Proz, Speichergroesse_kWh;
let Max_wrleistung_W ,InstalliertPeakLeistung, Einspeiselimit_Pro, Einspeiselimit_kWh, maximumLadeleistung_W, Bat_Discharge_Limit_W;
let EinstellungAnwahl,PrognoseAnwahl, M_Power=0,M_Power_alt=0,Set_Power_Value_W=0,tibberMaxLadeleistung_W= null;
let Batterie_SOC_alt_Proz=0, Notstrom_SOC_Proz = 0, Summe0 = 0, Summe1 = 0, Summe2 = 0, Summe3 = 0, baseurl, TibberSubscribeID;
let sMode_evcc,nEvcc_Instanz, nEvcc_WB1_Loadpoint, nEvcc_WB2_Loadpoint, hystereseWatt = 2000;
//***************************************************************************************************
//**************************************** Function Bereich *****************************************
//***************************************************************************************************
// Wird nur beim Start vom Script aufgerufen
async function ScriptStart(){
try {
await CreateState();
logChargeControl(`-==== alle Objekt ID\'s angelegt ====-`);
await CheckState();
logChargeControl(`-==== alle Objekte ID\'s überprüft ====-`);
await pruefeAdapterEinstellungen();
// Proplanta Länderauswahl zuordnen
baseurl = await baseUrlsCountrys[country];
function safeParse(val, fallback) {
try {
return (val !== null && val !== undefined && val !== '') ? JSON.parse(val) : fallback;
} catch (e) {
logChargeControl(`Fehler beim Parsen eines JSON-States: ${e.message}`, 'warn');
return fallback;
}
}
const stateResults = await Promise.all([
getStateAsync(sID_arrayHausverbrauch),
getStateAsync(sID_arrayHausverbrauchDurchschnitt),
getStateAsync(sID_PrognoseAuto_kWh),
getStateAsync(sID_PrognoseSolcast90_kWh),
getStateAsync(sID_PrognoseProp_kWh),
getStateAsync(sID_PrognoseSolcast_kWh),
getStateAsync(sID_arrayPV_LeistungTag_kWh)
]);
homeConsumption = safeParse(stateResults[0]?.val, {});
homeAverage = safeParse(stateResults[1]?.val, {});
arrayPrognoseAuto_kWh = safeParse(stateResults[2]?.val, []);
arrayPrognoseSolcast90_kWh = safeParse(stateResults[3]?.val, []);
arrayPrognoseProp_kWh = safeParse(stateResults[4]?.val, []);
arrayPrognoseSolcast_kWh = safeParse(stateResults[5]?.val, []);
arrayPV_LeistungTag_kWh = safeParse(stateResults[6]?.val, []);
// Falls Struktur leer → Defaultstruktur anlegen
const wochentage = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'];
for (const tag of wochentage) {
if (!homeConsumption[tag]) homeConsumption[tag] = { day: [], night: [] };
if (!homeAverage[tag]) homeAverage[tag] = { day: 0, night: 0 };
}
[bAutomatikAnwahl, bAutomatikRegelung, bNotstromAusNetz, Notstrom_Status,PrognoseAnwahl, EinstellungAnwahl, Max_wrleistung_W
, InstalliertPeakLeistung, Einspeiselimit_Pro, maximumLadeleistung_W, Bat_Discharge_Limit_W, m_Batt_SOC_Proz, bBattTraining
]= await Promise.all([
getStateAsync(sID_Automatik_Prognose), // Vorwahl in VIS true = automatik false = manuell
getStateAsync(sID_Automatik_Regelung), // Vorwahl in VIS true = automatik false = manuell
getStateAsync(sID_NotstromAusNetz), // Vorwahl in VIS true = Notstrom aus Netz nachladen
getStateAsync(sID_Notrom_Status), // 0= nicht möglich 1=Aktiv 2= nicht Aktiv 3= nicht verfügbar 4=Inselbetrieb
getStateAsync(sID_PrognoseAnwahl), // Aktuelle Einstellung welche Prognose für Berechnung verwendet wird
getStateAsync(sID_EinstellungAnwahl), // Vorwahl in VIS Einstellung 1-5
getStateAsync(sID_Max_wrleistung_W), // Maximale Wechselrichter Leistung
getStateAsync(sID_Installed_Peak_Power), // Installierte Peak Leistung der PV-Module
getStateAsync(sID_Einspeiselimit_Pro), // Einspeiselimit in Prozent
getStateAsync(sID_Bat_Charge_Limit), // Maximal mögliche Batterie Ladeleistung
getStateAsync(sID_Bat_Discharge_Limit), // Maximal mögliche Batterie Entladeleistung
getStateAsync(sID_Batterie_SOC), // Aktueller Batterie SOC
getStateAsync(sID_BattTraining) // Batterie Training aktiv
]).then(states => states.map(s => s?.val));
Max_wrleistung_W = Max_wrleistung_W - 200; // Maximale Wechselrichter Leistung (Abzüglich 200 W, um die Trägheit der Steuerung auszugleichen)
Einspeiselimit_kWh = ((InstalliertPeakLeistung/100)*Einspeiselimit_Pro-200)/1000 // Einspeiselimit (Abzüglich 200 W, um die Trägheit der Steuerung auszugleichen)
// EVCC-Integration prüfen
if (bEvcc) {
sID_Path_evcc_loadpoint1_charging = `evcc.${nEvcc_Instanz}.loadpoint.${nEvcc_WB1_Loadpoint}.status.charging`
sID_Path_evcc_loadpoint2_charging = `evcc.${nEvcc_Instanz}.loadpoint.${nEvcc_WB2_Loadpoint}.status.charging`
sID_Path_evcc_mode1 = `evcc.${nEvcc_Instanz}.loadpoint.${nEvcc_WB1_Loadpoint}.status.mode`
sID_Path_evcc_mode2 = `evcc.${nEvcc_Instanz}.loadpoint.${nEvcc_WB2_Loadpoint}.status.mode`
const useID1 = existsObject(sID_Path_evcc_loadpoint1_charging);
const useID2 = existsObject(sID_Path_evcc_loadpoint2_charging);
const useID3 = existsObject(sID_Path_evcc_mode1);
const useID4 = existsObject(sID_Path_evcc_mode2);
if (useID1 || useID2) {
if (useID1 && !useID2) {
bCharging_evcc = (await getStateAsync(sID_Path_evcc_loadpoint1_charging)).val;
} else if (!useID1 && useID2) {
bCharging_evcc = (await getStateAsync(sID_Path_evcc_loadpoint2_charging)).val;
} else if (useID1 && useID2) {
const [val1, val2] = await Promise.all([
getStateAsync(sID_Path_evcc_loadpoint1_charging),
getStateAsync(sID_Path_evcc_loadpoint2_charging)
]).then(states => states.map(s => s.val));
bCharging_evcc = val1 || val2;
}
}
if (useID3 || useID4) {
if (useID3 && !useID4) {
sMode_evcc = (await getStateAsync(sID_Path_evcc_mode1)).val
} else if (!useID3 && useID4) {
sMode_evcc = (await getStateAsync(sID_Path_evcc_mode2)).val
} else {
const [val3, val4] = await Promise.all([
getStateAsync(sID_Path_evcc_mode1),
getStateAsync(sID_Path_evcc_mode2)
]).then(states => states.map(s => s.val));
if (val3 == 'pv' && val4 == 'pv') {
sMode_evcc = 'pv';
}
}
}
}
// Manuelle Batterie-Ladung prüfen
bManuelleLadungBatt = ((await getStateAsync(sID_Manual_Charge_Energy)).val > 0);
// Wetterdaten beim Programmstart aktualisieren und Timer starten.
await Speichergroesse() // aktuell verfügbare Batterie Speichergröße berechnen
if (bSolcast) {await SheduleSolcast(SolcastDachflaechen);} // Wetterdaten Solcast abrufen wenn User Variable 30_AbfrageSolcast = true
await MEZ_Regelzeiten(); // RE,RB und Ladeende berechnen
await Notstromreserve(); // Eingestellte Notstromreserve berechnen
await SheduleProplanta(); // Wetterdaten Proplanta abrufen danach wird WetterprognoseAktualisieren() augerufen und ein Timer gestartet.
bStart = false
await registerEventHandlers();
LogProgrammablauf += '0,';
logChargeControl(`-==== ScriptStart() erfolgreich abgeschlossen ====-`);
} catch (err) {
logChargeControl(`❌ Fehler in ScriptStart(): ${err.message}`, 'error');
}
}
// Alle nötigen Objekt ID's anlegen
async function CreateState(){
try {
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.Notstrom_min`, {'def':30, 'name':'Speicherreserve in % bei Wintersonnenwende 21.12', 'type':'number', 'role':'value', 'desc':'Speicherreserve in % bei winterminimum', 'unit':'%'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.Notstrom_sockel`, {'def':20, 'name':'min. SOC Wert bei Tag-/Nachtgleiche 21.3./21.9.', 'type':'number', 'role':'value', 'desc':'min. SOC Wert bei Tag-/Nachtgleiche 21.3./21.9.', 'unit':'%'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Autonomiezeit`, {'def':"", 'name':'verbleibende Reichweite der Batterie in h und m', 'type':'string', 'role':'value', 'desc':'verbleibende Reichweite der Batterie in h'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.AutonomiezeitDurchschnitt`, {'def':"", 'name':'Durchschnittliche verbleibende Reichweite der Batterie in h und m', 'type':'string', 'role':'value', 'desc':'verbleibende Reichweite der Batterie in h'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Batteriekapazität_kWh`, {'def':0, 'name':'verbleibende Reichweite der Batterie in kWh', 'type':'number', 'role':'value', 'desc':'verbleibende Reichweite der Batterie in kWh', 'unit':'kWh'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Hausverbrauch`, {'def':0, 'name':'Reiner Hausverbrauch ohne WB, LW-Pumpe oder Heizstab' , 'type':'number', 'role':'value', 'unit':'W'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.arrayHausverbrauchDurchschnitt`, {'def':{"Montag":{"night":100,"day":100},"Dienstag":{"night":100,"day":100},"Mittwoch":{"night":100,"day":100},"Donnerstag":{"night":100,"day":100},"Freitag":{"night":100,"day":100},"Samstag":{"night":100,"day":100},"Sonntag":{"night":100,"day":100}}, 'name':'Merker durchschnittlicher Hausverbrauch ohne Wallbox und Heizstab' , 'type':'string', 'role':'value'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.arrayHausverbrauch`, {'def':{"Montag":{"night":[{ "hour": 14, "value": 380 }],"day":[{ "hour": 14, "value": 380 }]},"Dienstag":{"night":[{ "hour": 14, "value": 380 }],"day":[{ "hour": 14, "value": 380 }]},"Mittwoch":{"night":[{ "hour": 14, "value": 380 }],"day":[{ "hour": 14, "value": 380 }]},"Donnerstag":{"night":[{ "hour": 14, "value": 380 }],"day":[{ "hour": 14, "value": 380 }]},"Freitag":{"night":[{ "hour": 14, "value": 380 }],"day":[{ "hour": 14, "value": 380 }]},"Samstag":{"night":[{ "hour": 14, "value": 380 }],"day":[{ "hour": 14, "value": 380 }]},"Sonntag":{"night":[{ "hour": 14, "value": 380 }],"day":[{ "hour": 14, "value": 380 }]}}, 'name':'Merker Leistung Hausverbrauch ohne Wallbox und Heizstab' , 'type':'string', 'role':'value'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Notstrom_akt`, {'def':0, 'name':'aktuell berechnete Notstromreserve', 'type':'number', 'role':'value', 'desc':'aktuell berechnete Notstromreserve', 'unit':'%'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.EinstellungAnwahl`, {'def':0, 'name':'Aktuell manuell angewählte Einstellung', 'type':'number', 'role':'State'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.EigenverbrauchTag`, {'def':0, 'name':'min. Eigenverbrauch von 6:00 Uhr bis 19:00 Uhr in kWh', 'type':'number', 'role':'value'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Automatik`, {'def':false, 'name':'Bei true werden die Parameter automatisch nach Wetterprognose angepast' , 'type':'boolean', 'role':'State', 'desc':'Automatik Charge-Control ein/aus'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Automatik_Regelung`, {'def':false, 'name':'Bei true ist die Lade Regelung eingeschaltet' , 'type':'boolean', 'role':'State', 'desc':'Automatik Charge-Control ein/aus'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.NotstromAusNetz`, {'def':false, 'name':'Bei true wird aus dem Netz bis Notstrom SOC nachgeladen' , 'type':'boolean', 'role':'State', 'desc':'Notstrom aus Netz nachladen'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.PrognoseBerechnung_kWh_heute`, {'def':0, 'name':'Prognose für Berechnung' , 'type':'number', 'role':'value', 'unit':'kWh'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Regelbeginn_MEZ`, {'def':'00:00', 'name':'Regelbeginn MEZ', 'type':'string', 'role':'string', 'desc':'Regelbeginn MEZ Zeit', 'unit':'Uhr'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Regelende_MEZ`, {'def':'00:00', 'name':'Regelende MEZ', 'type':'string', 'role':'string', 'desc':'Regelende MEZ Zeit', 'unit':'Uhr'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Ladeende_MEZ`, {'def':'00:00', 'name':'Ladeende MEZ', 'type':'string', 'role':'string', 'desc':'Ladeende MEZ Zeit', 'unit':'Uhr'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Saved_Power_W`, {'def':0, 'name':'Überschuss in W' , 'type':'number', 'role':'value', 'unit':'W'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Saved_PowerLM2_kWh`, {'def':0, 'name':'kWh Leistungsmesser 2' , 'type':'number', 'role':'value', 'unit':'kWh'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.IstPvErtragLM0_kWh`, {'def':0, 'name':'kWh Leistungsmesser 0 ' , 'type':'number', 'role':'value', 'unit':'kWh'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.IstPvErtragLM1_kWh`, {'def':0, 'name':'kWh Leistungsmesser 1 ' , 'type':'number', 'role':'value', 'unit':'kWh'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.EigenverbrauchDurchschnitt`, {'def':'', 'name':'Eigenverbrauch Durchschnitt Tag/Nacht ' , 'type':'string'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.PrognoseAnwahl`, {'def':0, 'name':'Beide Berechnung nach min. Wert = 0 nur Proplanta=1 nur Solcast=2 Beide Berechnung nach max. Wert=3 Beide Berechnung nach Ø Wert=4 nur Solcast90=5' , 'type':'number', 'role':'value'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.FirmwareDate`, {'def':formatDate(new Date(), "DD.MM.YYYY hh:mm:ss"), 'name':'Datum Firmware Update' , 'type':'string', 'role':'value'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.LastFirmwareVersion`, {'def':"", 'name':'Alte Frimware Version' , 'type':'string', 'role':'value'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Akt_Berechnete_Ladeleistung_W`, {'def':0, 'name':'Aktuell eingestellte ist Ladeleistung in W' , 'type':'number', 'role':'value', 'unit':'W'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[2]}.HistoryJSON`, {'def':'[]', 'name':'JSON für materialdesign json chart' ,'type':'string'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[2]}.istPV_LeistungTag_kWh`, {'def':'[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]', 'name':'Array für Summe PV Leistung Tag in kWh' ,'type':'string'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[2]}.PrognoseProp_kWh`, {'def':'[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]', 'name':'Array für Prognose Proplanta PV Leistung Tag in kWh' ,'type':'string'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[2]}.PrognoseAuto_kWh`, {'def':'[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]', 'name':'Array für verwendete Prognose im Automatikmodus' ,'type':'string'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[2]}.PrognoseSolcast90_kWh`, {'def':'[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]', 'name':'Array für Prognose Solcast PV-Leistung in Kilowatt (kW) 90. Perzentil (hohes Szenario)' ,'type':'string'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[2]}.PrognoseSolcast_kWh`, {'def':'[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]', 'name':'Array für Prognose Solcast PV-Leistung in Kilowatt (kW)' ,'type':'string'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[2]}.HistorySelect`, {'def':1, 'name':'Select Menü für materialdesign json chart' ,'type':'number'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.NaesteAktualisierung`, {'def':'0', 'name':'Aktualisierung Proplanta' ,'type':'string'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Bewoelkungsgrad_12`, {'def':NaN, 'name':'Bewölkungsgrad 12 Uhr Proplanta' ,'type':'number'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Bewoelkungsgrad_15`, {'def':NaN, 'name':'Bewölkungsgrad 15 Uhr Proplanta' ,'type':'number'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Max_Temperatur_Tag_0`, {'def':0, 'name':'Max Temperatur heute' ,'type':'number', 'unit':'°C'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Max_Temperatur_Tag_1`, {'def':0, 'name':'Max Temperatur Morgen' ,'type':'number', 'unit':'°C'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Max_Temperatur_Tag_2`, {'def':0, 'name':'Max Temperatur Übermorgen' ,'type':'number', 'unit':'°C'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Max_Temperatur_Tag_3`, {'def':0, 'name':'Max Temperatur in vier Tagen' ,'type':'number', 'unit':'°C'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Min_Temperatur_Tag_0`, {'def':0, 'name':'Min Temperatur heute' ,'type':'number', 'unit':'°C'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Min_Temperatur_Tag_1`, {'def':0, 'name':'Min Temperatur Morgen' ,'type':'number', 'unit':'°C'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Min_Temperatur_Tag_2`, {'def':0, 'name':'Min Temperatur Übermorgen' ,'type':'number', 'unit':'°C'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Min_Temperatur_Tag_3`, {'def':0, 'name':'Min Temperatur in vier Tagen' ,'type':'number', 'unit':'°C'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_LogHistoryLokal`, {'def':false,'name':'History Daten in Lokaler Datei speichern' ,'type':'boolean', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_LogHistoryPath`, {'def':'','name':'Pfad zur Sicherungsdatei History ' ,'type':'string', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_Path_LeistungHeizstab`, {'def':'','name':'Pfad zu den Leistungswerte Heizstab eintragen ansonsten leer lassen ' ,'type':'string', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_Path_WallboxLadeLeistung_1`, {'def':'','name':'Pfad zu den Leistungswerte Wallbox1 die nicht vom E3DC gesteuert wird eintragen ansonsten leer lassen ' ,'type':'string', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_Path_WallboxLadeLeistung_2`, {'def':'','name':'Pfad zu den Leistungswerte Wallbox2 die nicht vom E3DC gesteuert wird eintragen ansonsten leer lassen ' ,'type':'string', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_Path_LeistungLW_Pumpe`, {'def':'','name':'Pfad zu den Leistungswerte Wärmepumpe eintragen ansonsten leer lassen ' ,'type':'string', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_LogAusgabe`, {'def':false,'name':'Zusätzliche allgemeine LOG Ausgaben' ,'type':'boolean', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_DebugAusgabe`, {'def':false,'name':'Debug Ausgabe im LOG zur Fehlersuche' ,'type':'boolean', 'unit':'','role':'State'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_DebugAusgabeDetail`, {'def':false,'name':'Zusätzliche LOG Ausgaben der Lade-Regelung' ,'type':'boolean', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_Offset_sunriseEnd`, {'def':60,'name':'Wieviele Minuten nach Sonnenaufgang soll die Notstromreserve noch abdecken' ,'type':'number', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_minWertPrognose_kWh`, {'def':0,'name':'Wenn Prognose nächster Tag > als minWertPrognode_kWh wird die Notstromreserve freigegeben 0=Notstromreserve nicht freigegeben' ,'type':'number', 'unit':'kWh','role':'value'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_maxEntladetiefeBatterie`, {'def':90,'name':'Die Entladetiefe der Batterie in % aus den technischen Daten E3DC (beim S10E pro 90%)' ,'type':'number', 'unit':'%','role':'value'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_Systemwirkungsgrad`, {'def':88,'name':'max. Systemwirkungsgrad inkl. Batterie in % aus den technischen Daten E3DC (beim S10E 88%)' ,'type':'number', 'unit':'%','role':'value'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_ScriptTibber`, {'def':false,'name':'Wenn das Script Tibber verwendet wird auf True setzen)' ,'type':'boolean', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_ScriptTibber_Path`, {'def':'0_userdata.0.TibberSkript','name':'Pfad zu ID TibberSkript eintragen ansonsten leer lassen ' ,'type':'string', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_Discharge_Start_Power`, {'def':65,'name':'Einstellung E3DC untere Entladeschwelle W)' ,'type':'number', 'unit':'W','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_evcc`, {'def':false,'name':'Wenn evcc verwendet wird auf True setzen' ,'type':'boolean', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_evcc_Instanz`, {'def':0,'name':'Die Instanz vom evcc Adapter eintragen' ,'type':'number', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_evcc_WB1_Loadpoint`, {'def':0,'name':'Nr EVCC Loadpoint Wallbox 1 eintragen' ,'type':'number', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_evcc_WB2_Loadpoint`, {'def':0,'name':'Nr EVCC Loadpoint Wallbox 2 eintragen' ,'type':'number', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.20_ProplantaCountry`, {'def':'de','name':'Ländercode für Proplanta de,at, ch, fr, it' ,'type':'string', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.20_ProplantaOrt`, {'def':'','name':'Wohnort für Abfrage Wetterdaten Proplanta' ,'type':'string', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.20_ProplantaPlz`, {'def':'','name':'Postleitzahl für Abfrage Wetterdaten Proplanta' ,'type':'string', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.20_BewoelkungsgradGrenzwert`, {'def':90,'name':'wird als Umschaltkriterium für die Einstellung 2-5 verwendet' ,'type':'number', 'unit':'%','role':'value'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.30_AbfrageSolcast`, {'def':false,'name':'true = Daten Solcast werden abgerufen false = Daten Solcast werden nicht abgerufen' ,'type':'boolean', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.30_SolcastDachflaechen`, {'def':0,'name':'Aktuell max. zwei Dachflächen möglich' ,'type':'number', 'unit':'Stück','role':'value'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.30_SolcastResource_Id_Dach1`, {'def':'','name':'Rooftop 1 Id von der Homepage Solcast' ,'type':'string', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.30_SolcastResource_Id_Dach2`, {'def':'','name':'Rooftop 2 Id von der Homepage Solcast' ,'type':'string', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.30_SolcastAPI_key`, {'def':'','name':'API Key von der Homepage Solcast' ,'type':'string', 'unit':'','role':'state'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.40_ModulFlaeche`, {'def':0,'name':'Installierte Modulfläche in m² (Silizium-Zelle 156x156x60 Zellen x 50 Module)' ,'type':'number', 'unit':'m²','role':'value'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.40_WirkungsgradModule`, {'def':21,'name':'Wirkungsgrad / Effizienzgrad der Solarmodule in % bezogen auf die Globalstrahlung (aktuelle Module haben max. 24 %)' ,'type':'number', 'unit':'%','role':'value'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.40_KorrekturFaktor`, {'def':0,'name':'Korrektur Faktor in Prozent. Reduziert die berechnete Prognose um diese anzugleichen.nKorrFaktor= 0 ohne Korrektur' ,'type':'number', 'unit':'%','role':'value'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.40_minPvLeistungTag_kWh`, {'def':3,'name':'minimal Mögliche PV-Leistung. Wenn Prognose niedriger ist wird mit diesem Wert gerechnet' ,'type':'number', 'unit':'kWh','role':'value'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.40_maxPvLeistungTag_kWh`, {'def':105,'name':'max. Mögliche PV-Leistung. Wenn Prognose höher ist wird mit diesem Wert gerechnet' ,'type':'number', 'unit':'kWh','role':'value'});
for (let i = 0; i <= 31; i++) {
if(i <=6){
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Datum_Tag_${i}`, {'def':'0', 'name':'Datum Proplanta' ,'type':'string'});
}
if(i <= 5){
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.UntererLadekorridor_${i}`, {'def':500, 'name':'Die Ladeleistung soll sich oberhalb dieses Wertes bewegen', 'type':'number', 'role':'value', 'desc':'UntererLadekorridor', 'unit':'W'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.Ladeschwelle_${i}`, {'def':0, 'name':'bis zur dieser Schwelle wird geladen bevor die Regelung beginnt', 'type':'number', 'role':'value', 'desc':'Ladeschwelle', 'unit':'%'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.Ladeende_${i}`, {'def':80, 'name':'Zielwert bis Ende Regelung, dannach wird Ladung auf ladeende2 weiter geregelt', 'type':'number', 'role':'value', 'desc':'Ladeende', 'unit':'%'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.Ladeende2_${i}`, {'def':93, 'name':'ladeende2 kann der Wert abweichend vom Defaultwert 93% gesetzt werden.Muss > ladeende sein', 'type':'number', 'role':'value', 'desc':'Ladeende2', 'unit':'%'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.RegelbeginnOffset_${i}`, {'def':"02:00", 'name':'Offset Wert start Regelbeginn in min. von solarNoon (höchster Sonnenstand) = 0 ', 'type':'string', 'role':'value', 'desc':'RB_Offset'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.RegelendeOffset_${i}`, {'def':"02:00", 'name':'Offset Wert ende Regelung in min. von solarNoon (höchster Sonnenstand) = 0 ', 'type':'string', 'role':'value', 'desc':'RE_Offset'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.LadeendeOffset_${i}`, {'def':"02:00", 'name':'Offset Wert Ladeende in min. von sunset (Sonnenuntergang) = 0 ', 'type':'string', 'role':'value', 'desc':'LE_Offset'});
await createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[0]}.Unload_${i}`, {'def':100, 'name':'Zielwert beim entladen.Die ladeschwelle muss < unload sein', 'type':'number', 'role':'value', 'desc':'Unload', 'unit':'%'});
}
if (i > 0 && i < 13){
let n = i.toString().padStart(2,"0");
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[2]}.HistoryJSON_${n}`, {'def':'[]', 'name':'JSON für materialdesign json chart' ,'type':'string'});
}
}
} catch (err) {
logChargeControl(`Fehler in Funktion CreateState()`, 'error');
}
}
// Alle User Eingaben prüfen ob Werte eingetragen wurden und Werte zuweisen
async function CheckState() {
const idUSER_ANPASSUNGEN = `${instanz}.${PfadEbene1}.${PfadEbene2[4]}`;
const objekte = [
{ id: '10_LogHistoryLokal', varName: 'logflag', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '10_LogHistoryPath', varName: 'sLogPath', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '10_Path_LeistungHeizstab', varName: 'sID_LeistungHeizstab_W', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '10_Path_WallboxLadeLeistung_1', varName: 'sID_WallboxLadeLeistung_1_W', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '10_Path_WallboxLadeLeistung_2', varName: 'sID_WallboxLadeLeistung_2_W', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '10_Path_LeistungLW_Pumpe', varName: 'sID_LeistungLW_Pumpe_W', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '10_LogAusgabe', varName: 'bLogAusgabe', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '10_DebugAusgabe', varName: 'bDebugAusgabe', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '10_DebugAusgabeDetail', varName: 'bDebugAusgabeDetail', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '10_Offset_sunriseEnd', varName: 'Offset_sunriseEnd_min', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '10_minWertPrognose_kWh', varName: 'minWertPrognose_kWh', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '10_maxEntladetiefeBatterie', varName: 'Entladetiefe_Pro', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen', min: 0, max: 100, errorMsg: 'Entladetiefe Batterie muss zwischen 0% und 100% sein' },
{ id: '10_Systemwirkungsgrad', varName: 'Systemwirkungsgrad_Pro', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen', min: 0, max: 100, errorMsg: 'Systemwirkungsgrad muss zwischen 0% und 100% sein' },
{ id: '10_ScriptTibber', varName: 'bScriptTibber', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen'},
{ id: '10_ScriptTibber_Path', varName: 'sID_Path_ScriptTibber', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '10_Discharge_Start_Power', varName: 'startDischargeDefault', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen'},
{ id: '10_evcc', varName: 'bEvcc', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen'},
{ id: '10_evcc_Instanz', varName: 'nEvcc_Instanz', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen'},
{ id: '10_evcc_WB1_Loadpoint', varName: 'nEvcc_WB1_Loadpoint', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen'},
{ id: '10_evcc_WB2_Loadpoint', varName: 'nEvcc_WB2_Loadpoint', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen'},
{ id: '20_ProplantaCountry', varName: 'country', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '20_ProplantaOrt', varName: 'ProplantaOrt', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '20_ProplantaPlz', varName: 'ProplantaPlz', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '20_BewoelkungsgradGrenzwert', varName: 'BewoelkungsgradGrenzwert', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '30_AbfrageSolcast', varName: 'bSolcast', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '40_ModulFlaeche', varName: 'nModulFlaeche', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '40_WirkungsgradModule', varName: 'nWirkungsgradModule', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '40_KorrekturFaktor', varName: 'nKorrFaktor', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '40_minPvLeistungTag_kWh', varName: 'nMinPvLeistungTag_kWh', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '40_maxPvLeistungTag_kWh', varName: 'nMaxPvLeistungTag_kWh', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' }
];
const objekteSolcast = [
{ id: '30_SolcastDachflaechen', varName: 'SolcastDachflaechen', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '30_SolcastResource_Id_Dach1', varName: 'Resource_Id_Dach[1]', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '30_SolcastResource_Id_Dach2', varName: 'Resource_Id_Dach[2]', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: '30_SolcastAPI_key', varName: 'SolcastAPI_key', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
];
const objekteTibber = [
{ id: 'BatterieEntladesperre', varName: 'bTibberEntladesperre', beschreibung: 'enthält keinen gültigen Wert, bitte unter Skripte im ioBroker prüfen ob das TibberSkript läuft' },
{ id: 'BatterieLaden', varName: 'bTibberLaden', beschreibung: 'enthält keinen gültigen Wert, bitte unter Skripte im ioBroker prüfen ob das TibberSkript läuft' },
{ id: 'maxLadeleistung', varName: 'tibberMaxLadeleistungUser_W', beschreibung: 'enthält keinen gültigen Wert, bitte unter Skripte im ioBroker prüfen ob das TibberSkript läuft' },
];
for (const obj of objekte) {
const state = await getStateAsync(`${idUSER_ANPASSUNGEN}.${obj.id}`);
if (!state || typeof state.val === 'undefined' || state.val === null) {
logError(obj.beschreibung, `${idUSER_ANPASSUNGEN}.${obj.id}`);
continue;
}
const value = state.val;
eval(`${obj.varName} = value`);
if (obj.min !== undefined && (value < obj.min || value > obj.max)) {
console.error(obj.errorMsg);
}
}
if (bScriptTibber) {
for (const obj of objekteTibber) {
let state;
if (obj.id === 'maxLadeleistung') {
state = await getStateAsync(`${idTibber}.USER_ANPASSUNGEN.${obj.id}`);
} else {
state = await getStateAsync(`${idTibber}.OutputSignal.${obj.id}`);
}
if (!state || typeof state.val === 'undefined' || state.val === null) {
logError(obj.beschreibung, `${idTibber}...${obj.id}`);
continue;
}
const value = state.val;
eval(`${obj.varName} = value`);
if (obj.min !== undefined && (value < obj.min || value > obj.max)) {
console.error(obj.errorMsg);
}
}
} else {
unsubscribe(TibberSubscribeID);
bTibberEntladesperre = false;
bTibberLaden = false;
}
if (bSolcast) {
for (const obj of objekteSolcast) {
const state = await getStateAsync(`${idUSER_ANPASSUNGEN}.${obj.id}`);
if (!state || typeof state.val === 'undefined' || state.val === null) {
logError(obj.beschreibung, `${idUSER_ANPASSUNGEN}.${obj.id}`);
continue;
}
const value = state.val;
eval(`${obj.varName} = value`);
if (obj.min !== undefined && (value < obj.min || value > obj.max)) {
console.error(obj.errorMsg);
}
}
if (TimerSolcast) clearSchedule(TimerSolcast);
// Daten von Solcast immer zwischen 04:01 und 04:59 Uhr abholen wenn const Solcast = true
TimerSolcast = schedule(`${Math.floor(Math.random() * (59 - 1 + 1)) + 1} 4 * * *`, function () {
SheduleSolcast(SolcastDachflaechen);
});
}
// Pfadangaben zu den Modulen Modbus und e3dc-rscp überprüfen
const PruefeID = [
sID_Batterie_SOC, sID_PvLeistung_E3DC_W, sID_PvLeistung_ADD_W,
sID_Power_Home_W, sID_Power_Wallbox_W, sID_Bat_Discharge_Limit, sID_Bat_Charge_Limit,
sID_Notrom_Status, sID_SPECIFIED_Battery_Capacity_0, sID_SET_POWER_MODE, sID_SET_POWER_VALUE_W,
sID_Max_Discharge_Power_W, sID_Max_Charge_Power_W, sID_Max_wrleistung_W,
sID_BAT0_Alterungszustand, sID_DISCHARGE_START_POWER, sID_PARAM_EP_RESERVE_W
];
for (const id of PruefeID) {
if (!(await existsObjectAsync(id))) {
logError('existiert nicht, bitte prüfen', id);
}
}
}
// Aktualisiert die Prognose Werte und das Diagramm PV-Prognosen in VIS
async function WetterprognoseAktualisieren()
{
try {
//Prognosen in kWh umrechen
await Prognosen_Berechnen();
// Diagramm aktualisieren
await makeJson();
// Einstellungen 1-5 je nach Überschuss PV Leistung Wetterprognose und Bewölkung anwählen
const ueberschuss = await Ueberschuss_Prozent();
await Einstellung(ueberschuss);
} catch (err) {
logChargeControl(`Fehler in Funktion WetterprognoseAktualisieren(): ${err.message}`, 'error');
}
}
// Programmablauf für die Laderegelung der Batterie wird im 3 sek. Takt getriggert
async function Ladesteuerung()
{
let dAkt = new Date();
const currentTime = Date.now();
const [
stateSetPowerMode,
statePvLeistungE3DC,
statePvLeistungADD,
stateWallboxPower,
stateUntererLadekorridor,
stateMaxEntladeleistung_W,
stateMaxLadeleistung_W,
stateSOC,
stateNotstromStatus,
statePowerHome,
stateLadeschwelle_Proz,
stateUnload_Proz,
stateLadeende_Proz,
stateLadeende2_Proz
] = await Promise.all([
getStateAsync(sID_SET_POWER_MODE),
getStateAsync(sID_PvLeistung_E3DC_W),
getStateAsync(sID_PvLeistung_ADD_W),
getStateAsync(sID_Power_Wallbox_W),
getStateAsync(sID_UntererLadekorridor_W[EinstellungAnwahl]),
getStateAsync(sID_Max_Discharge_Power_W),
getStateAsync(sID_Max_Charge_Power_W),
getStateAsync(sID_Batterie_SOC),
getStateAsync(sID_Notrom_Status),
getStateAsync(sID_Power_Home_W),
getStateAsync(sID_Ladeschwelle_Proz[EinstellungAnwahl]),
getStateAsync(sID_Unload_Proz[EinstellungAnwahl]),
getStateAsync(sID_Ladeende_Proz[EinstellungAnwahl]),
getStateAsync(sID_Ladeende2_Proz[EinstellungAnwahl])
]);
const SET_POWER_MODE = stateSetPowerMode?.val ?? 0;
const PV_Leistung_E3DC_W = statePvLeistungE3DC?.val ?? 0;
const PV_Leistung_ADD_W = statePvLeistungADD?.val ?? 0;
const WallboxPower = stateWallboxPower?.val ?? 0;
const UntererLadekorridor_W = stateUntererLadekorridor?.val ?? 0;
const maxEntladeleistung_W = stateMaxEntladeleistung_W?.val ?? 0;
const maxLadeleistung_W = stateMaxLadeleistung_W?.val ?? 0;
const battSOC_Proz = stateSOC?.val ?? 0;
const Notstrom_Status = stateNotstromStatus?.val ?? 0; // aktueller Notstrom Status E3DC 0= nicht möglich 1=Aktiv 2= nicht Aktiv 3= nicht verfügbar 4=Inselbetrieb
const Power_Home_W = toInt(statePowerHome?.val + WallboxPower); // Aktueller Hausverbrauch + Ladeleistung Wallbox E3DC externe Wallbox ist bereits im Hausverbrauch enthalten.
const Ladeschwelle_Proz = stateLadeschwelle_Proz?.val ?? 0;
const Unload_Proz = stateUnload_Proz?.val ?? 0;
const Ladeende_Proz = stateLadeende_Proz?.val ?? 0;
const Ladeende2_Proz = stateLadeende2_Proz?.val ?? 0;
const PV_Leistung_Summe_W = toInt(PV_Leistung_E3DC_W + Math.abs(PV_Leistung_ADD_W)); // Summe PV-Leistung
bNotstromVerwenden = await CheckPrognose(); // Prüfen ob Notstrom verwendet werden kann bei hoher PV Prognose für den nächsten Tag
// Batterie SOC erst bei -2% oder + 1% oder 0% aktualisieren um Schwankungen der Batterie auszugleichen
if (battSOC_Proz > m_Batt_SOC_Proz || m_Batt_SOC_Proz - battSOC_Proz >= HystereseBattSoc || battSOC_Proz == 0) {
m_Batt_SOC_Proz = battSOC_Proz;
}
// === Debug-Logging nur alle 3 Sekunden ===
if (bDebugAusgabe && (currentTime - lastDebugLogTime >= 3000)) {
await DebugLog();
lastDebugLogTime = currentTime;
}
LogProgrammablauf = "";
// === Entladesperre prüfen ===
const jetzt = new Date();
const vorSonnenuntergang = jetzt < getAstroDate("sunset");
const darfEntladen =
Notstrom_Status === 1 || //Notstrom 1 = aktiv
Notstrom_Status === 4 || //Notstrom 4 = Inselbetrieb
bNotstromVerwenden ||
bTibberLaden ||
bLadenAufNotstromSOC ||
m_Batt_SOC_Proz > Notstrom_SOC_Proz ||
(PV_Leistung_E3DC_W > 100 && vorSonnenuntergang);
if (darfEntladen){
// === Entladen ist erlaubt ===
LogProgrammablauf += '1,';
await EMS(true); // EMS Laden/Entladen aktivieren
// Wenn bNotstromVerwenden einmal true war, wird mit dem Merker bM_Notstrom das Ausschalten der Lade/Enladeleistung bis Sonnenaufgang verhindert
if (bNotstromVerwenden && !bM_Notstrom){bM_Notstrom = true };
} else if (
m_Batt_SOC_Proz <= Notstrom_SOC_Proz &&
(
(new Date() > getAstroDate("sunset") && !bM_Notstrom) ||
(new Date() < getAstroDate("sunrise") && !bM_Notstrom)
)
) {
LogProgrammablauf += '2,';
await EMS(false); // EMS Laden/Endladen ausschalten
// Notstrom SOC um 2% erhöhen, um Pendelverhalten zu verhindern, da die Batterieladung nach dem ausschalten wieder ansteigen kann.
Notstrom_SOC_Proz = (await getStateAsync(sID_Notstrom_akt)).val +2
}
// Zwischen Sonnenuntergang und Sonnenaufgang kann Merker Notstrom entladen wieder zurückgesetzt werden.
if (new Date() < getAstroDate("sunset") && new Date() > getAstroDate("sunrise") && bM_Notstrom){bM_Notstrom = false;LogProgrammablauf += '3,';}
// Nur wenn PV-Leistung vorhanden ist oder Entladen freigegeben ist Regelung starten.
if((PV_Leistung_Summe_W > (UntererLadekorridor_W + Power_Home_W) || maxEntladeleistung_W > 0 || maxLadeleistung_W > 0) && !bTibberLaden){
LogProgrammablauf += '6,';
bStatus_Notstrom_SOC = await Notstrom_SOC_erreicht();
// Wenn Notstrom SOC nicht erreicht ist oder Notstrom SOC erreicht wurde und mehr PV-Leistung als benötigt vorhanden ist (Überschuss) regelung starten
if((PV_Leistung_Summe_W - Power_Home_W) > toInt(UntererLadekorridor_W) && (bStatus_Notstrom_SOC || bTibberEntladesperre) || (!bStatus_Notstrom_SOC && !bTibberEntladesperre)){
LogProgrammablauf += '7,';
// Wenn SOC Ladeschwelle erreicht wurde, mit der Laderegelung starten
if(m_Batt_SOC_Proz > Ladeschwelle_Proz){
LogProgrammablauf += '9,';
// Prüfen ob vor Regelbeginn
if (dAkt.getTime() < RB_AstroSolarNoon.getTime()) {
LogProgrammablauf += '11,';
// Vor Regelbeginn.
// Um auf SOC Unload zu entladen, muss der Parameter Ladeschwelle kleiner sein, ansonsten wird Unload ignoriert.
if(Ladeschwelle_Proz <= Unload_Proz){
LogProgrammablauf += '12,';
// Ist der Batterie SoC > Unload und PV Leistung vorhanden wird entladen
if ((m_Batt_SOC_Proz - Unload_Proz) > 0 && PV_Leistung_Summe_W > 0){
LogProgrammablauf += '13,';
// Batterie SoC > Unload und PV Leistung vorhanden
// Neuberechnung der Ladeleistung erfolgt, wenn der SoC sich ändert oder nach Ablauf von höchstens 5 Minuten oder tLadezeitende sich ändert oder die letzte Ladeleistung 0 W war oder die Parameter sich geändert haben.
if(m_Batt_SOC_Proz != Batterie_SOC_alt_Proz || (dAkt.getTime() - Zeit_alt_milisek) > 30000 || RB_AstroSolarNoon.getTime() != RB_AstroSolarNoon_alt_milisek || M_Power == 0 || M_Power == maximumLadeleistung_W || bCheckConfig){
Batterie_SOC_alt_Proz = m_Batt_SOC_Proz; bCheckConfig = false; RB_AstroSolarNoon_alt_milisek = RB_AstroSolarNoon.getTime(); Zeit_alt_milisek = dAkt.getTime();
LogProgrammablauf += '14,';
// Berechnen der Entladeleistung bis zum Unload SOC in W/sek.
M_Power = Math.round(((Unload_Proz - m_Batt_SOC_Proz)*Speichergroesse_kWh*10*3600) / (Math.trunc((RB_AstroSolarNoon.getTime()- dAkt.getTime())/1000)));
// Prüfen ob die PV-Leistung plus Entladeleistung Batterie die max. WR-Leistung übersteigt
if((PV_Leistung_E3DC_W - M_Power)> Max_wrleistung_W){
M_Power = PV_Leistung_E3DC_W - Max_wrleistung_W
}
}
}else if((PV_Leistung_Summe_W - Power_Home_W) > toInt(UntererLadekorridor_W) || (PV_Leistung_Summe_W - Power_Home_W) > 0 ){
// Unload SOC erreicht und PV-Leistung höher als Eigenverbrauch.Laden der Batterie erst nach Regelbeginn zulassen (0 W)
LogProgrammablauf += '15,';
bLadenEntladenStoppen = true
M_Power = 0;
}else if((PV_Leistung_Summe_W - Power_Home_W) <= 0 ){
// Unload SOC erreicht und PV-Leistung niedriger als Eigenverbrauch.(idle)
LogProgrammablauf += '16,';
M_Power = maximumLadeleistung_W;
}
}else{
// Ladeschwelle größer Unload. Standard Regelung E3dc überlassen (idle)
LogProgrammablauf += '17,';
M_Power = maximumLadeleistung_W;
}
// Prüfen ob nach Regelbeginn vor Regelende
}else if(dAkt.getTime() < RE_AstroSolarNoon.getTime()){
LogProgrammablauf += '18,';
// Nach Regelbeginn vor Regelende
// Neuberechnung der Ladeleistung erfolgt, wenn der SoC sich ändert oder nach Ablauf von höchstens 5 Minuten oder tLadezeitende sich ändert oder die letzte Ladeleistung 0 W war oder die Parameter sich geändert haben.
if(m_Batt_SOC_Proz != Batterie_SOC_alt_Proz || (dAkt.getTime() - Zeit_alt_milisek) > 30000 || RE_AstroSolarNoon.getTime() != RE_AstroSolarNoon_alt_milisek || M_Power == 0 || M_Power == maximumLadeleistung_W || bCheckConfig){
Batterie_SOC_alt_Proz = m_Batt_SOC_Proz; bCheckConfig = false; RE_AstroSolarNoon_alt_milisek = RE_AstroSolarNoon.getTime(); Zeit_alt_milisek = dAkt.getTime();
LogProgrammablauf += '19,';
// Berechnen der Ladeleistung bis zum Ladeende SOC in W/sek.
M_Power = Math.round(((Ladeende_Proz - m_Batt_SOC_Proz)*Speichergroesse_kWh*10*3600) / (Math.trunc((RE_AstroSolarNoon.getTime()-dAkt.getTime())/1000)));
if (M_Power < toInt(UntererLadekorridor_W) && PV_Leistung_Summe_W -Power_Home_W > 0){
LogProgrammablauf += '20,';
// Berechnete Ladeleistung ist niedriger als unterer Ladekorridor.Laden Stoppen (0 W)
bLadenEntladenStoppen = true
M_Power = 0;
}else if (M_Power < toInt(UntererLadekorridor_W) && PV_Leistung_Summe_W -Power_Home_W <= 0){
// Berechnete Ladeleistung ist niedriger als unterer Ladekorridor und PV-Leistung zu gering.Entladen freigeben (idle)
LogProgrammablauf += '21,';
M_Power = maximumLadeleistung_W;
}
}
// Prüfen ob nach Regelende vor Ladeende
}else if(dAkt.getTime() < LE_AstroSunset.getTime()){
LogProgrammablauf += '22,';
// Nach Regelende vor Ladeende
// Wenn SOC Ladeende_Proz oder Ladeende2_Proz erreicht wurde, Merker setzen um Batterieschwankungen -1% zu ignorieren.
if (m_Batt_SOC_Proz < Ladeende_Proz){
LogProgrammablauf += '23,';
M_Power = maximumLadeleistung_W;
}else if (m_Batt_SOC_Proz < Ladeende2_Proz){
LogProgrammablauf += '24,';
// Berechnen der Ladeleistung bis zum Ladeende2 SOC in W/sek.
// Neuberechnung der Ladeleistung erfolgt, wenn der SoC sich ändert oder nach Ablauf von höchstens 30 Sek. oder tLadezeitende sich ändert oder die letzte Ladeleistung 0 W war oder die Parameter sich geändert haben.
if(m_Batt_SOC_Proz != Batterie_SOC_alt_Proz || (dAkt.getTime() - Zeit_alt_milisek) > 30000 || RE_AstroSolarNoon.getTime() != RE_AstroSolarNoon_alt_milisek || M_Power == 0 || M_Power == maximumLadeleistung_W || bCheckConfig){
Batterie_SOC_alt_Proz = m_Batt_SOC_Proz; bCheckConfig = false; RE_AstroSolarNoon_alt_milisek = RE_AstroSolarNoon.getTime(); Zeit_alt_milisek = dAkt.getTime();
LogProgrammablauf += '25,';
M_Power = Math.round(((Ladeende2_Proz - m_Batt_SOC_Proz)*Speichergroesse_kWh*10*3600) / (Math.trunc((LE_AstroSunset.getTime()-dAkt.getTime())/1000)));
if (M_Power < toInt(UntererLadekorridor_W) && PV_Leistung_Summe_W -Power_Home_W > 0){
LogProgrammablauf += '26,';
// Berechnete Ladeleistung ist niedriger als unterer Ladekorridor.Laden Stoppen (0 W)
M_Power = 0;
bLadenEntladenStoppen = true
}else if (M_Power < toInt(UntererLadekorridor_W) && PV_Leistung_Summe_W -Power_Home_W <= 0){
LogProgrammablauf += '27,';
// Berechnete Ladeleistung ist niedriger als unterer Ladekorridor und PV-Leistung zu gering.Entladen freigeben (idle)
M_Power = maximumLadeleistung_W;
}
}
}else if(PV_Leistung_Summe_W -Power_Home_W > 0){
// Ladeende2 erreicht und PV-Leistung höher als Eigenverbrauch (0 W))
// Laden Entladen stoppen
LogProgrammablauf += '28,';
bLadenEntladenStoppen = true
M_Power = 0;
}else{
// Ladeende2 erreicht und PV-Leistung niedriger als Eigenverbrauch. (idle)
// Laderegelung an E3DC übergeben um Batterie zu entladen
LogProgrammablauf += '29,';
M_Power = maximumLadeleistung_W;
}
// Prüfen ob nach Ladeende
}else if(dAkt.getTime() > LE_AstroSunset.getTime()){
LogProgrammablauf += '30,';
// Nach Sommerladeende
// Wurde Batterie SOC Ladeende2 erreicht, dann Ladung beenden ansonsten mit maximal möglicher Ladeleistung Laden.
if (m_Batt_SOC_Proz < Ladeende2_Proz && PV_Leistung_Summe_W > toInt(UntererLadekorridor_W)){
// SOC Ladeende2 nicht erreicht und ausreichend PV-Leistung vorhanden. (idle)
LogProgrammablauf += '31,';
M_Power = maximumLadeleistung_W;
}else if(m_Batt_SOC_Proz >= Ladeende2_Proz && PV_Leistung_Summe_W -Power_Home_W > 0){
// SOC Ladeende2 erreicht und PV-Leistung höher als Eigenverbrauch. (0 W)
LogProgrammablauf += '32,';
bLadenEntladenStoppen = true
M_Power = 0;
}else if(m_Batt_SOC_Proz >= Ladeende2_Proz && PV_Leistung_Summe_W-Power_Home_W <= 0 ){
// SOC Ladeende2 erreicht und PV-Leistung < Eigenverbrauch. (idle)
LogProgrammablauf += '33,';
M_Power = maximumLadeleistung_W;
}
}
}else{
// SOC Ladeschwelle wurde nicht erreicht.Regelung E3DC übelassen (Standard:laden mit voller PV-Leistung)
LogProgrammablauf += '10,';
M_Power = maximumLadeleistung_W;
}
if (!bLadenEntladenStoppen) {
// Zähler wieviel Leistung mit Charge-Control gesichert wurde
let Power = Math.max(0, PV_Leistung_E3DC_W - (Einspeiselimit_kWh * 1000) - Power_Home_W);
let Power_WR = Math.max(0, PV_Leistung_E3DC_W - Max_wrleistung_W);
let MaxPower = Math.max(Power, Power_WR);
await setStateAsync(sID_Saved_Power_W, MaxPower);
if (MaxPower > 0 && M_Power < MaxPower) {
LogProgrammablauf += '38,';
M_Power = MaxPower;
bM_Abriegelung = true;
}
// Prüfen ob Berechnete Ladeleistung innerhalb der min. und max. Grenze ist
if (M_Power < Bat_Discharge_Limit_W*-1){LogProgrammablauf += '39,'; M_Power = Bat_Discharge_Limit_W*-1;}
if (M_Power > maximumLadeleistung_W){LogProgrammablauf += '40,'; M_Power = maximumLadeleistung_W;}
//Prüfen ob berechnete Ladeleistung M_Power zu Netzbezug führt nur wenn LadenStoppen = false ist
const ladeleistung = Math.max(0, M_Power);
const ueberschuss = PV_Leistung_Summe_W - (Power_Home_W + ladeleistung);
if (bDebugAusgabe){log(`ueberschuss = ${ueberschuss} hystereseWatt = ${hystereseWatt} bRegelungAktiv = ${bRegelungAktiv} M_Power=${M_Power}`)}
if (!bRegelungAktiv && ueberschuss > hystereseWatt) {
hystereseWatt = 2000 // Beim einschalten auf Standard Wert setzen
bRegelungAktiv = true; // Regelung übernimmt CC
} else if (bRegelungAktiv && ueberschuss < 500) {
hystereseWatt = Math.max(2000,M_Power) // Berechnete Ladeleistung Merken beim ausschalten
bRegelungAktiv = false; // Regelung übernimmt E3DC
}
if (!bRegelungAktiv) {
// Regelung E3DC überlassen
LogProgrammablauf += '34,';
M_Power = maximumLadeleistung_W;
}
// Prüfen ob Berechnete Leistung negativ ist und entladen wird wenn LadenStoppen = false ist
if (M_Power < 0 && !bLadenEntladenStoppen) {
const Entladeleistung = Math.abs(M_Power);
const PowerGrid = PV_Leistung_Summe_W - Power_Home_W + Entladeleistung;
if (PowerGrid < 0) {
// Netzbezug trotz Entladung → Entladeleistung erhöhen
LogProgrammablauf += '35,';
const neueEntladeleistung = Entladeleistung + Math.abs(PowerGrid);
M_Power = -neueEntladeleistung;
bCheckConfig = true;
}
}
}
}else{
if(bTibberEntladesperre){LogProgrammablauf += '37,';}else{LogProgrammablauf += '8,';}
// Notstrom SOC erreicht oder Tibber Entladesperre aktiv und nicht ausreichend PV-Leistung vorhanden
// Entladen der Batterie stoppen
bLadenEntladenStoppen = true
}
// Leerlauf beibehalten bis sich der Wert M_Power ändert oder LadenEntladenStoppen true ist
if(M_Power_alt != maximumLadeleistung_W || M_Power != maximumLadeleistung_W || bLadenEntladenStoppen ){
// Alle 6 sek. muss mindestens ein Steuerbefehl an e3dc.rscp Adapter gesendet werden sonst übernimmt E3DC die Steuerung
if((bLadenEntladenStoppen != bLadenEntladenStoppen_alt || M_Power != M_Power_alt || (dAkt.getTime()- ZeitE3DC_SetPowerAlt_ms)> 5000) && !bLadenAufNotstromSOC){
ZeitE3DC_SetPowerAlt_ms = dAkt.getTime();
M_Power_alt = M_Power;
bLadenEntladenStoppen_alt = bLadenEntladenStoppen
if(M_Power == 0 || bLadenEntladenStoppen){
// Entladen / Laden der Batterie stoppen
LogProgrammablauf += '41,';
Set_Power_Value_W = 0;
//log(`Entladen stoppen bLadenEntladenStoppen = ${bLadenEntladenStoppen}`,'warn')
await Promise.all([
setStateAsync(sID_SET_POWER_MODE,1), // Idle
setStateAsync(sID_SET_POWER_VALUE_W,0),
setStateAsync(sID_out_Akt_Ladeleistung_W,0)
]);
bLadenEntladenStoppen = false
}else if(M_Power == maximumLadeleistung_W ){
// E3DC die Steuerung überlassen, dann wird mit der maximal möglichen Ladeleistung geladen oder entladen
LogProgrammablauf += '42,';
Set_Power_Value_W = 0
//log(`Steuerung E3DC überlassen Set_Power_Value_W = ${Set_Power_Value_W}`,'warn')
await Promise.all([
setStateAsync(sID_SET_POWER_MODE,0), // Normal
setStateAsync(sID_out_Akt_Ladeleistung_W,maximumLadeleistung_W),
]);
}else if(M_Power > 0){
// Entladen / Laden der Batterie regeln
LogProgrammablauf += '43,';
// Beim ersten Aufruf oder wenn Berechnung Netzbezug bedeuten würde
// oder wenn Einspeisegrenze erreicht wurde, Wert M_Power übernehmen und erst dann langsam erhöhen oder senken
if (Set_Power_Value_W < 1) {
//log(`M_Power = ${M_Power} übernehmen`, 'warn');
Set_Power_Value_W = M_Power;
} else if (bM_Abriegelung) {
//log(`Einspeisegrenze erreicht M_Power = ${M_Power} übernehmen`, 'warn');
Set_Power_Value_W = M_Power + 100;
bM_Abriegelung = false;
}
// Leistung langsam erhöhen oder senken um Schwankungen zu verhindern
if(M_Power > Set_Power_Value_W){
Set_Power_Value_W ++
}else if(M_Power < Set_Power_Value_W){
Set_Power_Value_W -= 3;
}
//log(`Regelung Set_Power_Value_W ist = ${Set_Power_Value_W}`,'warn')
await Promise.all([
setStateAsync(sID_SET_POWER_MODE,3), // Laden
setStateAsync(sID_SET_POWER_VALUE_W,Set_Power_Value_W), // E3DC bleib beim Laden im Schnitt um ca 82 W unter der eingestellten Ladeleistung
setStateAsync(sID_out_Akt_Ladeleistung_W,Set_Power_Value_W),
]);
}else if(M_Power < 0 && m_Batt_SOC_Proz > Notstrom_SOC_Proz){
LogProgrammablauf += '44,';
// Beim ersten aufruf Wert M_Power übernehmen und erst dann langsam erhöhen oder senken
if(Set_Power_Value_W >= 0){Set_Power_Value_W=M_Power}
if(!bCheckConfig){
// Leistung langsam erhöhen oder senken um Schwankungen auszugleichen
if(M_Power > Set_Power_Value_W){
Set_Power_Value_W++
}else if(M_Power < Set_Power_Value_W){
Set_Power_Value_W--
}
}else{
Set_Power_Value_W = M_Power
}
await Promise.all([
setStateAsync(sID_SET_POWER_MODE,2), // Entladen
setStateAsync(sID_SET_POWER_VALUE_W,Math.abs(Set_Power_Value_W)), // E3DC bleib beim Entladen im Schnitt um ca 65 W über der eingestellten Ladeleistung
setStateAsync(sID_out_Akt_Ladeleistung_W,Set_Power_Value_W),
]);
}
}
}else{
// Absicherung falls bei den Adaptereinstellung e3dc-rscp SET_POWER Wiederholintervall nicht 0 eingestellt ist
if(SET_POWER_MODE > 0){
await Promise.all([
setStateAsync(sID_SET_POWER_MODE,0), // Normal
setStateAsync(sID_out_Akt_Ladeleistung_W,maximumLadeleistung_W),
]);
}
}
}else if(bScriptTibber && bTibberLaden){
LogProgrammablauf += '36,';
// Absicherung das Netzleistung nicht 22000W (32A * 3 ) übersteigt
const steigungsrate = 100;
const maxGesamtleistung = 20000;
if(tibberMaxLadeleistung_W === null){tibberMaxLadeleistung_W = tibberMaxLadeleistungUser_W}
let gesamtleistung
if (PV_Leistung_Summe_W >= Power_Home_W) {
gesamtleistung = tibberMaxLadeleistung_W;
} else {
gesamtleistung = Math.abs(PV_Leistung_Summe_W - Power_Home_W) + tibberMaxLadeleistung_W;
}
if (gesamtleistung > maxGesamtleistung) {
tibberMaxLadeleistung_W -= gesamtleistung - maxGesamtleistung;
}else{
const differenz = tibberMaxLadeleistungUser_W - tibberMaxLadeleistung_W;
// Annäherung in beide Richtungen mit Wert steigungsrate
if (Math.abs(differenz) >= steigungsrate &&
Power_Home_W + tibberMaxLadeleistung_W + Math.sign(differenz) * steigungsrate <= maxGesamtleistung) {
tibberMaxLadeleistung_W += Math.sign(differenz) * steigungsrate;
} else {
tibberMaxLadeleistung_W = tibberMaxLadeleistungUser_W;
}
}
if (tibberMaxLadeleistung_W < 0){tibberMaxLadeleistung_W = 0}
await Promise.all([
setStateAsync(sID_SET_POWER_MODE,4), // Laden
setStateAsync(sID_SET_POWER_VALUE_W,tibberMaxLadeleistung_W), // E3DC bleib beim Laden im Schnitt um ca 82 W unter der eingestellten Ladeleistung
]);
}
}
async function DebugLog()
{
log(`******************* Debug LOG Charge-Control *******************`)
if (bDebugAusgabeDetail){log(`10_Offset_sunriseEnd = ${Offset_sunriseEnd_min}`)}
if (bDebugAusgabeDetail){log(`10_minWertPrognose_kWh = ${minWertPrognose_kWh}`)}
if (bDebugAusgabeDetail){log(`10_maxEntladetiefeBatterie = ${Entladetiefe_Pro}`)}
if (bDebugAusgabeDetail){log(`10_Systemwirkungsgrad = ${Systemwirkungsgrad_Pro}`)}
if (bDebugAusgabeDetail){log(`40_minPvLeistungTag_kWh = ${nMinPvLeistungTag_kWh}`)}
if (bDebugAusgabeDetail){log(`40_maxPvLeistungTag_kWh = ${nMaxPvLeistungTag_kWh}`)}
if (bDebugAusgabeDetail){log(`40_KorrekturFaktor = ${nKorrFaktor}`)}
if (bDebugAusgabeDetail){log(`40_WirkungsgradModule = ${nWirkungsgradModule}`)}
if (bDebugAusgabeDetail){log(`bAutomatikAnwahl =${bAutomatikAnwahl}`)}
if (bDebugAusgabeDetail){log(`bAutomatikRegelung =${bAutomatikRegelung}`)}
if (bDebugAusgabeDetail){log(`Einstellungen =${EinstellungAnwahl}`)}
if (bDebugAusgabeDetail){log(`Start Regelzeitraum = ${RB_AstroSolarNoon.getHours().toString().padStart(2,"0")}:${RB_AstroSolarNoon.getMinutes().toString().padStart(2,"0")}`)}
if (bDebugAusgabeDetail){log(`Ende Regelzeitraum= ${RE_AstroSolarNoon.getHours().toString().padStart(2,"0")}:${RE_AstroSolarNoon.getMinutes().toString().padStart(2,"0")}`)}
if (bDebugAusgabeDetail){log(`Ladeende= ${LE_AstroSunset.getHours().toString().padStart(2,"0")}:${LE_AstroSunset.getMinutes().toString().padStart(2,"0")}`)}
if (bDebugAusgabeDetail){log(`Unload = ${(await getStateAsync(sID_Unload_Proz[EinstellungAnwahl])).val}`)}
if (bDebugAusgabeDetail){log(`Ladeende = ${(await getStateAsync(sID_Ladeende_Proz[EinstellungAnwahl])).val}`)}
if (bDebugAusgabeDetail){log(`Ladeende2 = ${(await getStateAsync(sID_Ladeende2_Proz[EinstellungAnwahl])).val}`)}
if (bDebugAusgabeDetail){log(`Ladeschwelle = ${(await getStateAsync(sID_Ladeschwelle_Proz[EinstellungAnwahl])).val}`)}
if (bDebugAusgabeDetail){log(`Unterer Ladekorridor = ${(await getStateAsync(sID_UntererLadekorridor_W[EinstellungAnwahl])).val}`)}
if (bDebugAusgabeDetail){log(`Offset Regelbeginn = ${(await getStateAsync(sID_RegelbeginnOffset[EinstellungAnwahl])).val}`)}
if (bDebugAusgabeDetail){log(`Offset Regelende = ${(await getStateAsync(sID_RegelendeOffset[EinstellungAnwahl])).val}`)}
if (bDebugAusgabeDetail){log(`Offset Ladeende = ${(await getStateAsync(sID_LadeendeOffset[EinstellungAnwahl])).val}`)}
if (bDebugAusgabeDetail){log(`Notstrom min = ${(await getStateAsync(sID_Notstrom_min_Proz)).val}`)}
if (bDebugAusgabeDetail){log(`Notstrom Sockel = ${(await getStateAsync(sID_Notstrom_sockel_Proz)).val}`)}
if (bDebugAusgabeDetail){log(`Eigenverbrauch Nacht = ${await Hausverbrauch('night')} Wh`)}
if (bDebugAusgabeDetail){log(`Power_Home_W (Hausverbrauch & Wallbox) = ${(await getStateAsync(sID_Power_Home_W)).val+(await getStateAsync(sID_Power_Wallbox_W)).val}W`)}
if (bDebugAusgabeDetail){log(`Batterie Leistung = ${(await getStateAsync(sID_Power_Bat_W)).val} W`)}
if (bDebugAusgabeDetail){log(`PV Leistung = ${(await getStateAsync(sID_PvLeistung_E3DC_W)).val+Math.abs((await getStateAsync(sID_PvLeistung_ADD_W)).val)} W`)}
if (bDebugAusgabeDetail){log(`Speichergroesse = ${Speichergroesse_kWh}kWh `)}
if (bDebugAusgabeDetail){log(`Batterie SoC = ${(await getStateAsync(sID_Batterie_SOC)).val} %`)}
if (bDebugAusgabeDetail){log(`Notstrom_SOC_Proz= ${Notstrom_SOC_Proz} %`)}
if (bDebugAusgabeDetail){log(`Notstrom_SOC_erreicht = ${bStatus_Notstrom_SOC}`)}
if (bDebugAusgabeDetail){log(`bNotstromVerwenden =${bNotstromVerwenden}`)}
if (bDebugAusgabeDetail){log(`bNotstromAusNetz =${bNotstromAusNetz}`)}
if (bDebugAusgabeDetail){log(`Notstrom_Status = ${(await getStateAsync(sID_Notrom_Status)).val}`)}
if (bDebugAusgabeDetail){log(`bM_Notstrom = ${bM_Notstrom}`)}