-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathCharge-Control_Ver_1.5.14.js
2549 lines (2305 loc) · 158 KB
/
Charge-Control_Ver_1.5.14.js
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
const sID_LeistungHeizstab_W = ``; // Pfad zu den Leistungswerte Heizstab eintragen ansonsten leer lassen
const sID_WallboxLadeLeistung_1_W = ``; // Pfad zu den Leistungswerte Wallbox1 die nicht vom E3DC gesteuert wird eintragen ansonsten leer lassen
const sID_WallboxLadeLeistung_2_W = ``; // Pfad zu den Leistungswerte Wallbox2 die nicht vom E3DC gesteuert wirdeintragen ansonsten leer lassen
const sID_LeistungLW_Pumpe_W = ''; // Pfad zu den Leistungswerte Wärmepumpe eintragen ansonsten leer lassen
const BUFFER_SIZE= 5; // Größe des Buffers für gleitenden Durchschnitt
//++++++++++++++++++++++++++++++++++++++++ ENDE USER ANPASSUNGEN +++++++++++++++++++++++++++++++++++++++
//------------------------------------------------------------------------------------------------------
let Logparser1 ='',Logparser2 ='';
if (LogparserSyntax){Logparser1 ='##{"from":"Charge-Control", "message":"';Logparser2 ='"}##'}
log(`${Logparser1} -==== Charge-Control Version 1.5.14 ====- ${Logparser2}`);
//******************************************************************************************************
//****************************************** Objekt ID anlegen *****************************************
//******************************************************************************************************
//*************************************** ID's Adapter e3dc.rscp ***************************************
const sID_Power_GRID_W =`${instanzE3DC_RSCP}.EMS.POWER_GRID`; // aktuelle Netzleistung
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_startDischargeDefault =`${instanzE3DC_RSCP}.EMS.SYS_SPECS.startDischargeDefault`; // Anfängliche Entladeleistung Standard
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
const 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
//************************************* 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_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');
const MAX_ENTRIES = 480; // 8 Stunden x 3600 Sekunden pro Tag /60 executionInterval
//******************** Globale Variable Array ********************
let hausverbrauchBuffer = []; // Buffer für Hausverbrauchswerte
let homeConsumption ={Montag: { night: [], day: [] },Dienstag: { night: [], day: [] },Mittwoch: { night: [], day: [] },
Donnerstag: { night: [], day: [] },Freitag: { night: [], day: [] },Samstag: { night: [], day: [] },Sonntag: { night: [], day: [] }
};
let homeAverage ={Montag: { night: [], day: [] },Dienstag: { night: [], day: [] },Mittwoch: { night: [], day: [] },
Donnerstag: { night: [], day: [] },Freitag: { night: [], day: [] },Samstag: { night: [], day: [] },Sonntag: { night: [], day: [] }
};
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,country,ProplantaOrt,ProplantaPlz,BewoelkungsgradGrenzwert,bSolcast;
let nModulFlaeche,nWirkungsgradModule,nKorrFaktor,nMinPvLeistungTag_kWh,nMaxPvLeistungTag_kWh;
let SolcastDachflaechen,Resource_Id_Dach=[],SolcastAPI_key,tibberMaxLadeleistungUser_W;
//******************************* 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;
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, bLadeschwelle_Proz_erreicht = false;
let bM_Abriegelung = false, bLadenAufNotstromSOC = false, bHeuteNotstromVerbraucht = false, bCheckConfig = true;
let bLadeende_Proz_erreicht = false, bLadeende2_Proz_erreicht = false, bLadeende2_Proz_erreicht2 = false;
let bNotstromAusNetz, bAutomatikAnwahl, bAutomatikRegelung, bManuelleLadungBatt, bTibberLaden = false, bTibberEntladesperre = false;
//*********************************** Globale Variable ***********************************
let LogProgrammablauf = "", Notstrom_Status, startDischargeDefault, Batterie_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;
//***************************************************************************************************
//**************************************** Function Bereich *****************************************
//***************************************************************************************************
// Wird nur beim Start vom Script aufgerufen
async function ScriptStart()
{
await CreateState();
log(`${Logparser1} -==== alle Objekt ID\'s angelegt ====- ${Logparser2}`);
await CheckState();
log(`${Logparser1} -==== alle Objekte ID\'s überprüft ====- ${Logparser2}`);
await pruefeAdapterEinstellungen();
// Proplanta Länderauswahl zuordnen
baseurl = await baseUrlsCountrys[country];
homeConsumption = JSON.parse((await getStateAsync(sID_arrayHausverbrauch)).val);
homeAverage = JSON.parse((await getStateAsync(sID_arrayHausverbrauchDurchschnitt)).val);
[arrayPrognoseProp_kWh, arrayPrognoseAuto_kWh, arrayPrognoseSolcast90_kWh, arrayPrognoseSolcast_kWh, arrayPV_LeistungTag_kWh
, bAutomatikAnwahl, bAutomatikRegelung, bNotstromAusNetz, Notstrom_Status,PrognoseAnwahl, EinstellungAnwahl, Max_wrleistung_W
, InstalliertPeakLeistung, Einspeiselimit_Pro, maximumLadeleistung_W, Bat_Discharge_Limit_W, startDischargeDefault, Batterie_SOC_Proz
]= await Promise.all([
getStateAsync(sID_PrognoseProp_kWh),
getStateAsync(sID_PrognoseAuto_kWh),
getStateAsync(sID_PrognoseSolcast90_kWh),
getStateAsync(sID_PrognoseSolcast_kWh),
getStateAsync(sID_arrayPV_LeistungTag_kWh),
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_startDischargeDefault), // Anfängliche Entladeleistung Standard
getStateAsync(sID_Batterie_SOC) // Aktueller Batterie SOC
]).then(states => states.map(state => state.val));
startDischargeDefault = 65;
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)
if ((await getStateAsync(sID_Manual_Charge_Energy)).val > 0){bManuelleLadungBatt = true}else{bManuelleLadungBatt = false}
// 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;
LogProgrammablauf += '0,';
}
// Alle nötigen Objekt ID's anlegen
async function CreateState(){
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':'%'});
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':'%'});
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'});
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'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Hausverbrauch`, {'def':0, 'name':'Reiner Hausverbrauch ohne WB, LW-Pumpe oder Heizstab' , 'type':'number', 'role':'value', 'unit':'W'});
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'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.arrayHausverbrauch`, {'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 Leistung Hausverbrauch ohne Wallbox und Heizstab' , 'type':'string', 'role':'value'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Notstrom_akt`, {'def':0, 'name':'aktuell berechnete Notstromreserve', 'type':'number', 'role':'value', 'desc':'aktuell berechnete Notstromreserve', 'unit':'%'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.EinstellungAnwahl`, {'def':0, 'name':'Aktuell manuell angewählte Einstellung', 'type':'number', 'role':'State'});
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'});
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'});
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'});
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'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.PrognoseBerechnung_kWh_heute`, {'def':0, 'name':'Prognose für Berechnung' , 'type':'number', 'role':'value', 'unit':'kWh'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Regelbeginn_MEZ`, {'def':'00:00', 'name':'Regelbeginn MEZ', 'type':'string', 'role':'string', 'desc':'Regelbeginn MEZ Zeit', 'unit':'Uhr'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Regelende_MEZ`, {'def':'00:00', 'name':'Regelende MEZ', 'type':'string', 'role':'string', 'desc':'Regelende MEZ Zeit', 'unit':'Uhr'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Ladeende_MEZ`, {'def':'00:00', 'name':'Ladeende MEZ', 'type':'string', 'role':'string', 'desc':'Ladeende MEZ Zeit', 'unit':'Uhr'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Saved_Power_W`, {'def':0, 'name':'Überschuss in W' , 'type':'number', 'role':'value', 'unit':'W'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Saved_PowerLM2_kWh`, {'def':0, 'name':'kWh Leistungsmesser 2' , 'type':'number', 'role':'value', 'unit':'kWh'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.IstPvErtragLM0_kWh`, {'def':0, 'name':'kWh Leistungsmesser 0 ' , 'type':'number', 'role':'value', 'unit':'kWh'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.IstPvErtragLM1_kWh`, {'def':0, 'name':'kWh Leistungsmesser 1 ' , 'type':'number', 'role':'value', 'unit':'kWh'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.EigenverbrauchDurchschnitt`, {'def':'', 'name':'Eigenverbrauch Durchschnitt Tag/Nacht ' , 'type':'string'});
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'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.FirmwareDate`, {'def':formatDate(new Date(), "DD.MM.YYYY hh:mm:ss"), 'name':'Datum Firmware Update' , 'type':'string', 'role':'value'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.LastFirmwareVersion`, {'def':"", 'name':'Alte Frimware Version' , 'type':'string', 'role':'value'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[1]}.Akt_Berechnete_Ladeleistung_W`, {'def':0, 'name':'Aktuell eingestellte ist Ladeleistung in W' , 'type':'number', 'role':'value', 'unit':'W'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[2]}.HistoryJSON`, {'def':'[]', 'name':'JSON für materialdesign json chart' ,'type':'string'});
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':'array'});
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':'array'});
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':'array'});
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':'array'});
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':'array'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[2]}.HistorySelect`, {'def':1, 'name':'Select Menü für materialdesign json chart' ,'type':'number'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.NaesteAktualisierung`, {'def':'0', 'name':'Aktualisierung Proplanta' ,'type':'string'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Bewoelkungsgrad_12`, {'def':NaN, 'name':'Bewölkungsgrad 12 Uhr Proplanta' ,'type':'number'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Bewoelkungsgrad_15`, {'def':NaN, 'name':'Bewölkungsgrad 15 Uhr Proplanta' ,'type':'number'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Max_Temperatur_Tag_0`, {'def':0, 'name':'Max Temperatur heute' ,'type':'number', 'unit':'°C'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Max_Temperatur_Tag_1`, {'def':0, 'name':'Max Temperatur Morgen' ,'type':'number', 'unit':'°C'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Max_Temperatur_Tag_2`, {'def':0, 'name':'Max Temperatur Übermorgen' ,'type':'number', 'unit':'°C'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Max_Temperatur_Tag_3`, {'def':0, 'name':'Max Temperatur in vier Tagen' ,'type':'number', 'unit':'°C'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Min_Temperatur_Tag_0`, {'def':0, 'name':'Min Temperatur heute' ,'type':'number', 'unit':'°C'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Min_Temperatur_Tag_1`, {'def':0, 'name':'Min Temperatur Morgen' ,'type':'number', 'unit':'°C'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Min_Temperatur_Tag_2`, {'def':0, 'name':'Min Temperatur Übermorgen' ,'type':'number', 'unit':'°C'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Min_Temperatur_Tag_3`, {'def':0, 'name':'Min Temperatur in vier Tagen' ,'type':'number', 'unit':'°C'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_LogHistoryLokal`, {'def':false,'name':'History Daten in Lokaler Datei speichern' ,'type':'boolean', 'unit':'','role':'state'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_LogHistoryPath`, {'def':'','name':'Pfad zur Sicherungsdatei History ' ,'type':'string', 'unit':'','role':'state'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_LogAusgabe`, {'def':false,'name':'Zusätzliche allgemeine LOG Ausgaben' ,'type':'boolean', 'unit':'','role':'state'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_DebugAusgabe`, {'def':false,'name':'Debug Ausgabe im LOG zur Fehlersuche' ,'type':'boolean', 'unit':'','role':'State'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_DebugAusgabeDetail`, {'def':false,'name':'Zusätzliche LOG Ausgaben der Lade-Regelung' ,'type':'boolean', 'unit':'','role':'state'});
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'});
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'});
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'});
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'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.10_ScriptTibber`, {'def':false,'name':'Wenn das Script Tibber verwendet wird auf True setzen)' ,'type':'boolean', 'unit':'','role':'state'});
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'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.20_ProplantaOrt`, {'def':'','name':'Wohnort für Abfrage Wetterdaten Proplanta' ,'type':'string', 'unit':'','role':'state'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.20_ProplantaPlz`, {'def':'','name':'Postleitzahl für Abfrage Wetterdaten Proplanta' ,'type':'string', 'unit':'','role':'state'});
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'});
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'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.30_SolcastDachflaechen`, {'def':0,'name':'Aktuell max. zwei Dachflächen möglich' ,'type':'number', 'unit':'Stück','role':'value'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.30_SolcastResource_Id_Dach1`, {'def':'','name':'Rooftop 1 Id von der Homepage Solcast' ,'type':'string', 'unit':'','role':'state'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.30_SolcastResource_Id_Dach2`, {'def':'','name':'Rooftop 2 Id von der Homepage Solcast' ,'type':'string', 'unit':'','role':'state'});
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[4]}.30_SolcastAPI_key`, {'def':'','name':'API Key von der Homepage Solcast' ,'type':'string', 'unit':'','role':'state'});
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'});
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'});
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'});
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'});
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){
createStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Datum_Tag_${i}`, {'def':'0', 'name':'Datum Proplanta' ,'type':'string'});
}
if(i <= 5){
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'});
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':'%'});
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':'%'});
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':'%'});
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'});
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'});
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'});
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'});
}
}
}
// 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_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: '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 prüfen' },
{ id: 'BatterieLaden', varName: 'bTibberLaden', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
{ id: 'maxLadeleistung', varName: 'tibberMaxLadeleistungUser_W', beschreibung: 'enthält keinen gültigen Wert, bitte prüfen' },
];
for (const obj of objekte) {
const value = (await getStateAsync(`${idUSER_ANPASSUNGEN}.${obj.id}`)).val;
if (value === undefined || value === null) {
logError(obj.beschreibung, `${idUSER_ANPASSUNGEN}.${obj.id}`);
} else {
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 value;
if(obj.id == 'maxLadeleistung'){
value = (await getStateAsync(`${idTibber}.USER_ANPASSUNGEN.${obj.id}`)).val;
}else{
value = (await getStateAsync(`${idTibber}.OutputSignal.${obj.id}`)).val;
}
if (value === undefined || value === null) {
logError(obj.beschreibung, `${idTibber}...${obj.id}`);
} else {
eval(`${obj.varName} = value`);
if (obj.min !== undefined && (value < obj.min || value > obj.max)) {
console.error(obj.errorMsg);
}
}
}
const regexPattern = new RegExp(`${idTibber}`);
TibberSubscribeID = on({id: regexPattern, change: "ne"}, async function (obj){
const logTxT = `-==== Tibber output signal ${obj.id.split('.')[4]} wurde in ${obj.state.val} geändert ====-`
if (obj.id.split('.')[4] == 'BatterieEntladesperre' ){bTibberEntladesperre = obj.state.val;log(logTxT,'warn')}
if (obj.id.split('.')[4] == 'BatterieLaden' ){bTibberLaden = obj.state.val;log(logTxT,'warn')}
if (obj.id.split('.')[4] == 'maxLadeleistung' ){tibberMaxLadeleistungUser_W = obj.state.val;log(logTxT,'warn')}
});
}else{
unsubscribe(TibberSubscribeID);
bTibberEntladesperre = false;
bTibberLaden = false;
}
if (bSolcast){
for (const obj of objekteSolcast) {
const value = (await getStateAsync(`${idUSER_ANPASSUNGEN}.${obj.id}`)).val;
if (value === undefined || value === null) {
logError(obj.beschreibung, `${idUSER_ANPASSUNGEN}.${obj.id}`);
} else {
eval(`${obj.varName} = value`);
if (obj.min !== undefined && (value < obj.min || value > obj.max)) {
console.error(obj.errorMsg);
}
}
}
// Daten von Solcast immer zwischen 04:01 und 04:59 Uhr abholen wenn const Solcast = true
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_startDischargeDefault, sID_Max_wrleistung_W,
sID_BAT0_Alterungszustand, sID_DISCHARGE_START_POWER, sID_PARAM_EP_RESERVE_W
];
for (const id of PruefeID) {
if (!existsObject(id)) {
logError('existiert nicht, bitte prüfen', id);
}
}
}
// Aktualisiert die Prognose Werte und das Diagramm PV-Prognosen in VIS
async function WetterprognoseAktualisieren()
{
//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
await Einstellung(await Ueberschuss_Prozent());
}
// 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 [netzLeistung_W,SET_POWER_MODE,PV_Leistung_E3DC_W, PV_Leistung_ADD_W, WallboxPower, wb1Power, wb2Power, UntererLadekorridor_W] = await Promise.all([
getStateAsync(sID_Power_GRID_W),
getStateAsync(sID_SET_POWER_MODE),
getStateAsync(sID_PvLeistung_E3DC_W),
getStateAsync(sID_PvLeistung_ADD_W),
getStateAsync(sID_Power_Wallbox_W),
getStateAsync(sID_WallboxLadeLeistung_1_W),
getStateAsync(sID_WallboxLadeLeistung_2_W),
getStateAsync(sID_UntererLadekorridor_W[EinstellungAnwahl])
]).then(states => [
states[0]?.val,
states[1]?.val ?? 0, // Wenn SET_POWER_MODE null oder undefined ist, 0 eintragen
states[2]?.val,
states[3]?.val,
states[4]?.val ?? 0, // Wenn WallboxPower null oder undefined ist, 0 eintragen,
states[5]?.val ?? 0, // Wenn wb1Power null oder undefined ist, 0 eintragen,
states[6]?.val ?? 0, // Wenn wb2Power null oder undefined ist, 0 eintragen,
states[7]?.val
]);
const Power_Home_W =toInt((await getStateAsync(sID_Power_Home_W)).val + WallboxPower); // Aktueller Hausverbrauch + Ladeleistung Wallbox E3DC externe Wallbox ist bereits im Hausverbrauch enthalten.
const PV_Leistung_Summe_W = toInt(PV_Leistung_E3DC_W + Math.abs(PV_Leistung_ADD_W)); // Summe PV-Leistung
Notstrom_Status = (await getStateAsync(sID_Notrom_Status)).val; // aktueller Notstrom Status E3DC 0= nicht möglich 1=Aktiv 2= nicht Aktiv 3= nicht verfügbar 4=Inselbetrieb
bNotstromVerwenden = await CheckPrognose(); // Prüfen ob Notstrom verwendet werden kann bei hoher PV Prognose für den nächsten Tag
// LOG nur alle 6 sek. aufrufen
if (bDebugAusgabe && (currentTime - lastDebugLogTime >= 6000)) {
await DebugLog();
lastDebugLogTime = currentTime;
}
// ProgrammAblauf kann nach LOG Erstellung gelöscht werden
LogProgrammablauf = "";
// Das Entladen aus dem Speicher wird freigegeben wenn:
// Notstrom oder Inselbetrieb aktiv ist oder bNotstromVerwenden = true oder bTibberLaden = true oder bLadenAufNotstromSOC = true
// oder der Batterie SOC > der berechneten Reserve liegt oder PV-Leistung > 100W ist und vor Sonnenuntergang
// Das Entladen aus dem Speicher wird gesperrt wenn:
// Notstrom SOC erreicht wurde und aktuelle Zeit zwischen Sonnenuntergang und Sonnenaufgang liegt und Merker bNotstromVerwenden nicht true ist.
if (Notstrom_Status == 1 || Notstrom_Status == 4 || bNotstromVerwenden|| bTibberLaden || bLadenAufNotstromSOC || Batterie_SOC_Proz > Notstrom_SOC_Proz || (PV_Leistung_E3DC_W > 100 && new Date() < getAstroDate("sunset"))){
// Notstrom_Status 0=nicht möglich 1=active 2= nicht active 3= nicht verfügbar 4= Inselbetrieb
// EMS Laden/Endladen einschalten
LogProgrammablauf += '1,';
await EMS(true);
// 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(Batterie_SOC_Proz <= Notstrom_SOC_Proz && (new Date() > getAstroDate("sunset") && !bM_Notstrom || new Date() < getAstroDate("sunrise") && !bM_Notstrom)){
// EMS Laden/Endladen ausschalten
LogProgrammablauf += '2,';
await EMS(false);
// Notstrom SOC um 2% erhöhen, um ein ständiges ein und ausschalten 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 = false;LogProgrammablauf += '3,';}
// Nur wenn PV-Leistung vorhanden ist oder Entladen freigegeben ist Regelung starten.
if((PV_Leistung_Summe_W > 0 || getState(sID_Max_Discharge_Power_W).val > 0 || getState(sID_Max_Charge_Power_W).val > 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,';
let Ladeschwelle_Proz = (await getStateAsync(sID_Ladeschwelle_Proz[EinstellungAnwahl])).val // Parameter Ladeschwelle
// Hysterese -1% um Batterieschwankungen auszugleiche und ein ständiges ein-/aus-schalten zu verhindern
if(Batterie_SOC_Proz > Ladeschwelle_Proz){bLadeschwelle_Proz_erreicht = true}else if(Batterie_SOC_Proz < Ladeschwelle_Proz-1){bLadeschwelle_Proz_erreicht = false}
// Wenn SOC Ladeschwelle erreicht wurde, mit der Laderegelung starten
if(bLadeschwelle_Proz_erreicht){
LogProgrammablauf += '9,';
// Prüfen ob vor Regelbeginn
if (dAkt.getTime() < RB_AstroSolarNoon.getTime()) {
LogProgrammablauf += '11,';
// Vor Regelbeginn.
let Unload_Proz = (await getStateAsync(sID_Unload_Proz[EinstellungAnwahl])).val;
// 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 ((Batterie_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(Batterie_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 = Batterie_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 - Batterie_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(Batterie_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 = Batterie_SOC_Proz; bCheckConfig = false; RE_AstroSolarNoon_alt_milisek = RE_AstroSolarNoon.getTime(); Zeit_alt_milisek = dAkt.getTime();
let Ladeende_Proz = (await getStateAsync(sID_Ladeende_Proz[EinstellungAnwahl])).val // Parameter Ladeende
LogProgrammablauf += '19,';
// Berechnen der Ladeleistung bis zum Ladeende SOC in W/sek.
M_Power = Math.round(((Ladeende_Proz - Batterie_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
let Ladeende_Proz = (await getStateAsync(sID_Ladeende_Proz[EinstellungAnwahl])).val // Parameter Ladeende
let Ladeende2_Proz = (await getStateAsync(sID_Ladeende2_Proz[EinstellungAnwahl])).val // Parameter Ladeende2
// Wenn SOC Ladeende_Proz oder Ladeende2_Proz erreicht wurde, Merker setzen um Batterieschwankungen -1% zu ignorieren.
if(Batterie_SOC_Proz > Ladeende_Proz){bLadeende_Proz_erreicht = true}else if(Batterie_SOC_Proz < Ladeende_Proz-1){bLadeende_Proz_erreicht = false}
if(Batterie_SOC_Proz > Ladeende2_Proz){bLadeende2_Proz_erreicht = true}else if(Batterie_SOC_Proz < Ladeende2_Proz-1){bLadeende2_Proz_erreicht = false}
if (!bLadeende_Proz_erreicht){
LogProgrammablauf += '23,';
M_Power = maximumLadeleistung_W;
}else if (!bLadeende2_Proz_erreicht){
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 5 Minuten oder tLadezeitende sich ändert oder die letzte Ladeleistung 0 W war oder die Parameter sich geändert haben.
if(Batterie_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 = Batterie_SOC_Proz; bCheckConfig = false; RE_AstroSolarNoon_alt_milisek = RE_AstroSolarNoon.getTime(); Zeit_alt_milisek = dAkt.getTime();
LogProgrammablauf += '25,';
M_Power = Math.round(((Ladeende2_Proz - Batterie_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){
LogProgrammablauf += '28,';
// Ladeende2 erreicht und PV-Leistung höher als Eigenverbrauch (0 W))
bLadenEntladenStoppen = true
M_Power = 0;
}else{
LogProgrammablauf += '29,';
// Ladeende2 erreicht und PV-Leistung niedriger als Eigenverbrauch. (idle)
M_Power = maximumLadeleistung_W;
}
// Prüfen ob nach Ladeende
}else if(dAkt.getTime() > LE_AstroSunset.getTime()){
LogProgrammablauf += '30,';
// Nach Sommerladeende
let Ladeende2_Proz = (await getStateAsync(sID_Ladeende2_Proz[EinstellungAnwahl])).val // Parameter Ladeende2
// Wurde Batterie SOC Ladeende2 erreicht, dann Ladung beenden ansonsten mit maximal möglicher Ladeleistung Laden.
if(Batterie_SOC_Proz > Ladeende2_Proz){bLadeende2_Proz_erreicht2 = true}else if(Batterie_SOC_Proz < Ladeende2_Proz-1){bLadeende2_Proz_erreicht2 = false}
if (!bLadeende2_Proz_erreicht2 && 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(bLadeende2_Proz_erreicht2 && 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(bLadeende2_Proz_erreicht2 && 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;
}
// 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) {
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){M_Power = Bat_Discharge_Limit_W*-1;}
if (M_Power > maximumLadeleistung_W){M_Power = maximumLadeleistung_W;}
//Prüfen ob berechnete Ladeleistung M_Power zu Netzbezug führt nur wenn LadenStoppen = false ist
if(M_Power >= 0 && !bLadenEntladenStoppen){
let PowerGrid = PV_Leistung_Summe_W -(Power_Home_W + M_Power)
if(PowerGrid < 500 && M_Power != maximumLadeleistung_W){// Führt zu Netzbezug, Steuerung ausschalten
LogProgrammablauf += '34,';
M_Power = maximumLadeleistung_W
}
}else if (!bLadenEntladenStoppen){
let PowerGrid = PV_Leistung_Summe_W -(Power_Home_W - M_Power)
if(PowerGrid < M_Power ){// Führt zu Netzbezug, Entladeleistung erhöhen
LogProgrammablauf += '35,';
M_Power = PowerGrid
// Merker um neu Berechnung zu triggern
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){
Set_Power_Value_W = 0;
await setStateAsync(sID_SET_POWER_MODE,1); // Idle
await setStateAsync(sID_SET_POWER_VALUE_W,0)
await 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
Set_Power_Value_W = 0
await setStateAsync(sID_SET_POWER_MODE,0); // Normal
await setStateAsync(sID_out_Akt_Ladeleistung_W,maximumLadeleistung_W);
}else if(M_Power > 0){
// Beim ersten aufruf Wert M_Power übernehmen oder wenn Einspeisegrenze erreicht wurde und erst dann langsam erhöhen oder senken
if(Set_Power_Value_W < 1 ){Set_Power_Value_W=M_Power}
if(bM_Abriegelung){Set_Power_Value_W=M_Power+100;bM_Abriegelung= false}
// 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--
}
await setStateAsync(sID_SET_POWER_MODE,3); // Laden
await setStateAsync(sID_SET_POWER_VALUE_W,Set_Power_Value_W) // E3DC bleib beim Laden im Schnitt um ca 82 W unter der eingestellten Ladeleistung
await setStateAsync(sID_out_Akt_Ladeleistung_W,Set_Power_Value_W);
}else if(M_Power < 0 && Batterie_SOC_Proz > Notstrom_SOC_Proz){
// 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 setStateAsync(sID_SET_POWER_MODE,2); // Entladen
await 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
await 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 setStateAsync(sID_SET_POWER_MODE,0); // Normal
await setStateAsync(sID_out_Akt_Ladeleistung_W,maximumLadeleistung_W);
}
}
}else if(bScriptTibber && bTibberLaden){
LogProgrammablauf += '36,';
// Absicherung das Netzleistung nicht 22000W (32A * 3 ) übersteigt
const steigungsrate = 10;
if(tibberMaxLadeleistung_W === null){tibberMaxLadeleistung_W = tibberMaxLadeleistungUser_W}
if(Power_Home_W + tibberMaxLadeleistung_W > 20000){
tibberMaxLadeleistung_W = tibberMaxLadeleistung_W - (Power_Home_W + tibberMaxLadeleistung_W -20000);
}else{
if (tibberMaxLadeleistung_W < tibberMaxLadeleistungUser_W && (tibberMaxLadeleistung_W + Power_Home_W + steigungsrate) <= 20000) {
tibberMaxLadeleistung_W = tibberMaxLadeleistung_W + steigungsrate; // Erhöhe schrittweise
if (tibberMaxLadeleistung_W > tibberMaxLadeleistungUser_W) {
tibberMaxLadeleistung_W = tibberMaxLadeleistungUser_W;
}
}
}
if (tibberMaxLadeleistung_W < 0){tibberMaxLadeleistung_W = 0}
await setStateAsync(sID_SET_POWER_MODE,4); // Laden
await 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}`)}
if (bDebugAusgabeDetail){log(`M_Power = ${M_Power}`)}
if (bDebugAusgabeDetail){log(`Set_Power_Value_W = ${Set_Power_Value_W}`)}
log(`ProgrammAblauf = ${LogProgrammablauf} `,'warn')
}
// Prüfen ob Notstrom SOC erreicht wurde um das entladen der Batterie zu verhindern.
async function Notstrom_SOC_erreicht()
{
if (Notstrom_Status == 1 || Notstrom_Status == 4 || Batterie_SOC_Proz > Notstrom_SOC_Proz || bNotstromVerwenden || Batterie_SOC_Proz == 0){
// Entladen einschalten
Notstrom_SOC_Proz = (await getStateAsync(sID_Notstrom_akt)).val
LogProgrammablauf += '4,';
return false;
}else{
// Endladen ausschalten
// Notstrom SOC um 2% erhöhen, um ein ständiges aus und einschalten zu vermeiden.
Notstrom_SOC_Proz = (await getStateAsync(sID_Notstrom_akt)).val +2
LogProgrammablauf += '5,';
return true;
}
}
// EMS laden und entladen der Batterie aus/ein schalten
// Führt zu Schreibzugriffe auf die interne SSD vom Hauskraftwerk und sollte nicht ständig geändert werden.
async function EMS(bState)
{
const [Akk_max_Discharge_Power_W, Akk_max_Charge_Power_W] = await Promise.all([
getStateAsync(sID_Max_Discharge_Power_W), // Aktuell eingestellte Entladeleistung
getStateAsync(sID_Max_Charge_Power_W) // Aktuell eingestellte Ladeleistung
]).then(states => states.map(state => state.val));
Batterie_SOC_Proz = (await getStateAsync(sID_Batterie_SOC)).val;
// EMS einschalten
if(bState && (Akk_max_Discharge_Power_W == 0 || Akk_max_Charge_Power_W == 0)){
await Promise.all([
setStateAsync(sID_POWER_LIMITS_USED,true),
setStateAsync(sID_Max_Discharge_Power_W, Bat_Discharge_Limit_W),
setStateAsync(sID_DISCHARGE_START_POWER, startDischargeDefault),
setStateAsync(sID_Max_Charge_Power_W, maximumLadeleistung_W)
]);
log(`${Logparser1} -==== EMS Laden/Entladen der Batterie ist eingeschaltet ====- ${Logparser2}`,'warn')
}
// EMS ausschalten
if(!bState && Batterie_SOC_Proz !=0 && (Akk_max_Discharge_Power_W != 0 || Akk_max_Charge_Power_W != 0)){
await Promise.all([
setStateAsync(sID_POWER_LIMITS_USED, true),
setStateAsync(sID_DISCHARGE_START_POWER, 0),
setStateAsync(sID_Max_Discharge_Power_W, 0),
setStateAsync(sID_Max_Charge_Power_W, 0),
setStateAsync(sID_Powersave, true)
]);
log(`${Logparser1} -==== Notstrom Reserve erreicht, Laden/Entladen der Batterie ist ausgeschaltet ====- ${Logparser2}`,'warn')
}
}
// Notstromreserve berechnen (Notstrom_min_Proz = Speicherreserve in % bei Wintersonnenwende 21.12 / Notstrom_sockel_Proz = min. SOC Wert bei Tag-/Nachtgleiche 21.3./21.9. )
async function Notstromreserve()
{
let dAkt = new Date();
let dStart = new Date(dAkt.getFullYear()+',1,1');
if ((await getStateAsync(sID_PARAM_EP_RESERVE_W)).val == 0){
// @ts-ignore
let tm_yday = Math.round(Math.abs(dAkt - dStart) / (1000 * 60 * 60 * 24 ));
const [Notstrom_sockel_Proz,Notstrom_min_Proz] = await Promise.all([
getStateAsync(sID_Notstrom_sockel_Proz), // Parameter Charge-Control Notstrom Sockel
getStateAsync(sID_Notstrom_min_Proz) // Parameter Charge-Control Notstrom min
]).then(states => states.map(state => state.val));
Notstrom_SOC_Proz = Math.max(0,Math.round(Notstrom_sockel_Proz + (Notstrom_min_Proz - Notstrom_sockel_Proz) * Math.cos((tm_yday+9)*2*3.14/365)))
await setStateAsync(sID_Notstrom_akt,Notstrom_SOC_Proz)
}else{
log(`${Logparser1} -==== Notstromreserve wurde beim Hauskraftwerk eingestellt und wird nicht von Charge-Control gesteuert ====- ${Logparser2}`,'warn')
await setStateAsync(sID_Notstrom_akt,0)
Notstrom_SOC_Proz = 0;
}
}
// Einstellungen 1-5 je nach Überschuss PV Leistung Wetterprognose und Bewölkung anwählen
async function Einstellung(UeberschussPrognoseProzent)
{
let Bedeckungsgrad12,Bedeckungsgrad15;
EinstellungAnwahl = (await getStateAsync(sID_EinstellungAnwahl)).val
if (UeberschussPrognoseProzent== null){
log(`${Logparser1} -==== Überschuss PV-Leistung konnte nicht berechnet werden. Ueberschuss=${UeberschussPrognoseProzent} ====- ${Logparser2}`,'error');
return
}
// Bewölkung für weitere Entscheidung ermitteln
Bedeckungsgrad12 = (await getStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Bewoelkungsgrad_12`)).val;
Bedeckungsgrad15 = (await getStateAsync(`${instanz}.${PfadEbene1}.${PfadEbene2[3]}.Bewoelkungsgrad_15`)).val;
if (bLogAusgabe){log(`${Logparser1} Bewölkungsgrad 12 Uhr Proplanta ${Bedeckungsgrad12}${Logparser2}`);}
if (bLogAusgabe){log(`${Logparser1} Bewölkungsgrad 15 Uhr Proplanta ${Bedeckungsgrad15}${Logparser2}`);}
if (Number.isNaN(Bedeckungsgrad12) && bAutomatikAnwahl || Number.isNaN(Bedeckungsgrad15) && bAutomatikAnwahl )
{
log(`${Logparser1} -==== Bewölkungsgrad_12 oder Bewölkungsgrad_15 wurde nicht abgerufen. 12=${Bedeckungsgrad12} 15=${Bedeckungsgrad15} ====- ${Logparser2}`,'warn');
return
}
// Einstellung 1
// Prognose PV-Leistung geringer als benötigter Eigenverbrauch, Überschuss zu 100% in Batterie speichern
if (UeberschussPrognoseProzent === 0 && bAutomatikAnwahl)
{
if (bLogAusgabe){log(`${Logparser1}-==== Einstellung 1 aktiv ====-${Logparser2}`);}
if(EinstellungAnwahl != 1){
await setStateAsync(sID_EinstellungAnwahl,1);
}
}
// Einstellung 2
// Prognose PV-Leistung höher als benötigter Eigenverbrauch,Batterie laden und Überschuss ins Netz einspeisen
// und keine Bewölkung > 90%
if (UeberschussPrognoseProzent > 0 && Bedeckungsgrad12 < BewoelkungsgradGrenzwert && Bedeckungsgrad15 < BewoelkungsgradGrenzwert && bAutomatikAnwahl)
{
if (bLogAusgabe){log(`${Logparser1}-==== Einstellung 2 aktiv ====-${Logparser2}`);}
if(EinstellungAnwahl != 2){
await setStateAsync(sID_EinstellungAnwahl,2);
}
}
// Einstellung 3
// Prognose PV-Leistung höher als benötigter Eigenverbrauch,Batterie laden und Überschuss ins Netz einspeisen.
// ab 12:00 - 18:00 Uhr Bewölkung > 90%
if ((UeberschussPrognoseProzent > 0 && Bedeckungsgrad12 >= BewoelkungsgradGrenzwert && Bedeckungsgrad15 >= BewoelkungsgradGrenzwert && bAutomatikAnwahl) || (bAutomatikAnwahl === false && EinstellungAnwahl ===3))
{
if (bLogAusgabe){log(`${Logparser1}-==== Einstellung 3 aktiv ====-${Logparser2}`);}
if(EinstellungAnwahl != 3){
await setStateAsync(sID_EinstellungAnwahl,3);
}
}
// Einstellung 4
// Prognose PV-Leistung höher als benötigter Eigenverbrauch,Batterie laden und Überschuss ins Netz einspeisen.
// ab 12:00 - 15:00 Uhr Bewölkung > 90%
if ((UeberschussPrognoseProzent > 0 && Bedeckungsgrad12 >= BewoelkungsgradGrenzwert && Bedeckungsgrad15 < BewoelkungsgradGrenzwert && bAutomatikAnwahl) || (bAutomatikAnwahl === false && EinstellungAnwahl ===4))
{
if (bLogAusgabe){log(`${Logparser1}-==== Einstellung 4 aktiv ====-${Logparser2}`);}
if(EinstellungAnwahl != 4){
await setStateAsync(sID_EinstellungAnwahl,4);
}
}
// Einstellung 5
// Prognose PV-Leistung höher als benötigter Eigenverbrauch,Batterie laden und Überschuss ins Netz einspeisen.
// ab 15:00 - 18:00 Uhr Bewölkung > 90%
if ((UeberschussPrognoseProzent > 0 && Bedeckungsgrad12 < BewoelkungsgradGrenzwert && Bedeckungsgrad15 >= BewoelkungsgradGrenzwert && bAutomatikAnwahl) || (bAutomatikAnwahl === false && EinstellungAnwahl ===5))
{
if (bLogAusgabe){log(`${Logparser1}-==== Einstellung 5 aktiv ====-${Logparser2}`);}
if(EinstellungAnwahl != 5){
await setStateAsync(sID_EinstellungAnwahl,5);
}
}
}
// Die Funktion ändert die Prognosewerte für das Diagramm und berechnet die Prognose in kWh je nach Auswahl
async function Prognosen_Berechnen() {
let Tag = [], PrognoseProplanta_kWh_Tag = [], PrognoseSolcast_kWh_Tag = [], PrognoseSolcast90_kWh_Tag = [], Prognose_kWh_Tag = [];
let DatumAk = new Date();
let TagHeute = DatumAk.getDate();
let IstSummePvLeistung_kWh = arrayPV_LeistungTag_kWh[TagHeute];
// Lokale Kopien der Array-Werte für schnelleren Zugriff
let arrayProp = arrayPrognoseProp_kWh;
let arraySolcast = arrayPrognoseSolcast_kWh;
let arraySolcast90 = arrayPrognoseSolcast90_kWh;
// Initialisierung der Tag- und Prognose-Daten
for (let i = 0; i < 7; i++) {
let nextTag = nextDay(i);
Tag[i] = nextTag;
PrognoseProplanta_kWh_Tag[i] = arrayProp[nextTag] || 0;
PrognoseSolcast_kWh_Tag[i] = arraySolcast[nextTag] || 0;
PrognoseSolcast90_kWh_Tag[i] = arraySolcast90[nextTag] || 0;
}
// Schleife zur Berechnung der Prognose
for (let i = 0; i < 7; i++) {
let prop = PrognoseProplanta_kWh_Tag[i];
let solcast = PrognoseSolcast_kWh_Tag[i];
let solcast90 = PrognoseSolcast90_kWh_Tag[i];
// Frühzeitiges Abbrechen der Berechnung, wenn keine Prognosedaten vorliegen
if (prop === 0 && solcast === 0 && solcast90 === 0) {
Prognose_kWh_Tag[i] = 0;
continue;
}
// Auswahl der Prognose basierend auf PrognoseAnwahl, mit zwischengespeicherten Werten