iobroker.sprinklecontrol 0.2.10 → 0.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +47 -51
  2. package/admin/index_m.html +115 -37
  3. package/admin/index_m.js +108 -12
  4. package/admin/words.js +131 -118
  5. package/docs/de/img/E-Mail.jpg +0 -0
  6. package/docs/de/img/Extraeinstellungen.jpg +0 -0
  7. package/docs/de/img/Pumpeneinstellung.jpg +0 -0
  8. package/docs/de/img/Pushover.jpg +0 -0
  9. package/docs/de/img/Select_ID.jpg +0 -0
  10. package/docs/de/img/Telegram.jpg +0 -0
  11. package/docs/de/img/Ventil-Haupteinstellung.jpg +0 -0
  12. package/docs/de/img/Ventil-Pumpeneinstellung.jpg +0 -0
  13. package/docs/de/img/WhatsApp.jpg +0 -0
  14. package/docs/de/img/Zeiteinstellung.jpg +0 -0
  15. package/docs/de/img/addTime.jpg +0 -0
  16. package/docs/de/img/analog.jpg +0 -0
  17. package/docs/de/img/ber-verdunstung.jpg +0 -0
  18. package/docs/de/img/bew-einstellung.jpg +0 -0
  19. package/docs/de/img/bew-feste-tage.jpg +0 -0
  20. package/docs/de/img/bistabil.jpg +0 -0
  21. package/docs/de/img/bodenf-analog.jpg +0 -0
  22. package/docs/de/img/bodenf-bistabil.jpg +0 -0
  23. package/docs/de/img/calculation.jpg +0 -0
  24. package/docs/de/img/einschaltpunkt-giessen.jpg +0 -0
  25. package/docs/de/img/festeTage.jpg +0 -0
  26. package/docs/de/img/main.jpg +0 -0
  27. package/docs/de/img/main_tab.jpg +0 -0
  28. package/docs/de/img/max-bodenfeuchtigkeit.jpg +0 -0
  29. package/docs/de/img/verdunstDiagra.jpg +0 -0
  30. package/docs/de/img/zus-bew-einstellung.jpg +0 -0
  31. package/docs/de/sprinklecontrol.md +123 -55
  32. package/io-package.json +63 -69
  33. package/lib/evaporation.js +9 -2
  34. package/lib/myConfig.js +79 -31
  35. package/lib/tools.js +9 -2
  36. package/lib/valveControl.js +17 -10
  37. package/main.js +432 -147
  38. package/package.json +20 -17
  39. package/.commitmessage +0 -4
package/main.js CHANGED
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
- /*
3
- info: log aufbau main.js: #0.*
4
- */
2
+
5
3
  // Load your modules here, e.g.: => // Laden Sie Ihre Module hier, z.B.
6
4
  // const fs = require("fs");
7
5
 
@@ -29,19 +27,27 @@ const adapterName = require('./package.json').name.split('.').pop();
29
27
  let publicHolidayStr;
30
28
  /** @type {any} */
31
29
  let publicHolidayTomorrowStr;
32
- /* DasWetter.com */
30
+ /* Regenvorhersage - DasWetter.com */
31
+ /** @type {string}
32
+ * - Pfad zur Regenvorhersage in mm */
33
+ let weatherForecastTodayPfadStr;
33
34
  /** @type {number}
34
35
  * - heutige Regenvorhersage in mm */
35
36
  let weatherForecastTodayNum = 0;
36
37
  /** @type {number}
37
38
  * - morgige Regenvorhersage in mm */
38
39
  let weatherForecastTomorrowNum = 0;
40
+ /** @type {boolean}
41
+ * - Externer Schalter für Zusatzbewässerung */
42
+ let addStartTimeSwitch = false;
39
43
 
40
44
  /** @type {string} */
41
45
  let startTimeStr;
42
46
  /** @type {string} */
43
47
  let sunriseStr;
44
48
  /** @type {string} */
49
+ let sunsetStr;
50
+ /** @type {string} */
45
51
  let goldenHourEnd;
46
52
  /** switch => sprinklecontrol.*.control.Holiday
47
53
  * - Wenn (Holiday == true) ist, soll das Wochenendprogramm gefahren werden.
@@ -73,7 +79,13 @@ function startAdapter(options) {
73
79
  adapter = new utils.Adapter(options);
74
80
 
75
81
  // start here!
76
- adapter.on('ready', () => main(adapter));
82
+ adapter.on('ready', () => {
83
+ // init createConfig
84
+ myConfig.createConfig(adapter);
85
+ // Hauptpumpe zur Bewässerung setzen
86
+ valveControl.initValveControl(adapter);
87
+ main(adapter)
88
+ });
77
89
 
78
90
  /**
79
91
  * +++++++++++++++++++++++++ is called when adapter shuts down +++++++++++++++++++++++++
@@ -94,6 +106,7 @@ function startAdapter(options) {
94
106
  /*Startzeiten der Timer löschen*/
95
107
  schedule.cancelJob('calcPosTimer');
96
108
  schedule.cancelJob('sprinkleStartTime');
109
+ schedule.cancelJob('sprinkleAddStartTime');
97
110
  /* alle Ventile und Aktoren deaktivieren */
98
111
  valveControl.clearEntireList();
99
112
 
@@ -108,7 +121,7 @@ function startAdapter(options) {
108
121
  * -------------- Antwortet bei Aufrufen von getTelegramUser von index_m ---------------
109
122
  * @param {object} obj
110
123
  */
111
- adapter.on('message', (obj) => {
124
+ adapter.on ('message', (obj) => {
112
125
  if (obj) {
113
126
  switch (obj.command) {
114
127
  case 'getTelegramUser':
@@ -156,14 +169,30 @@ function startAdapter(options) {
156
169
  adapter.log.debug(`state ${id} changed: ${state.val} (ack = ${state.ack})`);
157
170
 
158
171
  // wenn (Holiday == true) ist, soll das Wochenendprogramm gefahren werden.
159
- if (id === adapter.namespace + '.control.Holiday') {
172
+ if (id === adapter.namespace + '.control.Holiday' && state.ack === false) {
160
173
  holidayStr = state.val;
174
+ adapter.setState(id, {
175
+ val: state.val,
176
+ ack: true
177
+ });
161
178
  startTimeSprinkle();
162
179
  }
180
+ // wenn (addStartTimeSwitch == true) wird die zusätzliche Bewässerung aktiviert
181
+ if (id === `${adapter.namespace}.control.addStartTimeSwitch` && typeof state.val === 'boolean' && state.ack === false) {
182
+ addStartTimeSwitch = state.val;
183
+ adapter.setState(id, {
184
+ val: state.val,
185
+ ack: true
186
+ });
187
+ }
163
188
  // wenn (autoOnOff == false) so werden alle Sprenger nicht mehr automatisch gestartet.
164
- if (id === adapter.namespace + '.control.autoOnOff') {
189
+ if ((id === adapter.namespace + '.control.autoOnOff') && (state.ack === false)) {
165
190
  autoOnOffStr = state.val;
166
191
  adapter.log.info(`startAdapter: control.autoOnOff: ${state.val}`);
192
+ adapter.setState(id, {
193
+ val: state.val,
194
+ ack: true
195
+ });
167
196
  if (!state.val) {
168
197
  valveControl.clearEntireList();
169
198
  }
@@ -182,11 +211,15 @@ function startAdapter(options) {
182
211
  sprinkleID: found.sprinkleID,
183
212
  wateringTime: (state.val <= 0) ? state.val : Math.round(60 * state.val)
184
213
  }]);
214
+ adapter.setState(id, {
215
+ val: state.val,
216
+ ack: true
217
+ });
185
218
  }
186
219
  }
187
220
  }
188
221
  }
189
- // wenn in der config unter methodControlSM !== 'analog' oder 'bistable' eingegeben wurde, dann Bodenfeuchte-Sensor auslesen
222
+ // wenn in der config unter methodControlSM!== 'analog' oder 'bistable' eingegeben wurde, dann Bodenfeuchte-Sensor auslesen
190
223
  if (myConfig.config) {
191
224
  function filterByID(obj){
192
225
  return (((obj.methodControlSM === 'analog') || (obj.methodControlSM === 'bistable')) && (obj.triggerSM === id));
@@ -205,13 +238,42 @@ function startAdapter(options) {
205
238
  }
206
239
  }
207
240
  }
208
-
209
241
  // wenn (...sprinkleName.autoOn == false[off]) so wird der aktuelle Sprenger [sprinkleName]
210
242
  // bei false nicht automatisch gestartet
211
- if (myConfig.config && (typeof state.val === 'boolean')) {
243
+ if (myConfig.config && (typeof state.val === 'boolean') && (state.ack === false)) {
212
244
  const found = myConfig.config.find(d => d.autoOnID === id);
213
- if (found && id === myConfig.config[found.sprinkleID].autoOnID) { myConfig.config[found.sprinkleID].autoOn = state.val; }
245
+ if (found && id === myConfig.config[found.sprinkleID].autoOnID) {
246
+ myConfig.config[found.sprinkleID].autoOn = state.val;
247
+ adapter.setState(id, { // Bestätigung
248
+ val: state.val,
249
+ ack: true
250
+ });
251
+ adapter.log.info(`set ${found.objectName}.autoOn = ${state.val}, id: ${id}`);
252
+ if (state.val === false) {
253
+ valveControl.addList(
254
+ [{
255
+ auto: false,
256
+ sprinkleID: found.sprinkleID,
257
+ wateringTime: 0
258
+ }]
259
+ );
260
+ }
261
+ }
214
262
  }
263
+
264
+ // postponeByOneDay → um einen Tag verschieben bei fixDay (twoNd & threeRd)
265
+ let idSplit = id.split('.', 5);
266
+ if (idSplit[4] === `postponeByOneDay` && state.ack === false) {
267
+ const found = myConfig.config.find(d => d.objectName === idSplit[3]);
268
+ if (found) {
269
+ myConfig.postponeByOneDay(found.sprinkleID).catch((e) => {adapter.log.warn(`postponeByOneDay: ${e}`)});
270
+ adapter.setState(id, {
271
+ val: false,
272
+ ack: true
273
+ });
274
+ }
275
+ }
276
+
215
277
  // Change in outside temperature → Änderung der Außentemperatur
216
278
  if (id === adapter.config.sensorOutsideTemperature) { /*Temperatur*/
217
279
  if (!Number.isNaN(Number.parseFloat(state.val))) {
@@ -267,7 +329,7 @@ function startAdapter(options) {
267
329
  }
268
330
  // Wettervorhersage
269
331
  if (adapter.config.weatherForecast === true) {
270
- if (id === adapter.config.weatherForInstance + '.NextDaysDetailed.Location_1.Day_1.rain_value') {
332
+ if (id === weatherForecastTodayPfadStr) {
271
333
  if (typeof state.val == 'string') {
272
334
  weatherForecastTodayNum = parseFloat(state.val);
273
335
  } else if (typeof state.val == 'number') {
@@ -320,7 +382,7 @@ async function GetSystemData() {
320
382
 
321
383
  adapter.log.debug(`longitude: ${adapter.config.longitude} | latitude: ${adapter.config.latitude}`);
322
384
  } else {
323
- adapter.log.error('system settings cannot be called up. Please check configuration!');
385
+ adapter.log.error('system settings cannot be called up. Please check the geo data');
324
386
  }
325
387
  } catch (err) {
326
388
  adapter.log.warn('system settings cannot be called up. Please check configuration!');
@@ -340,11 +402,12 @@ function curNextFixDay (sprinkleID, returnOn) {
340
402
  const weekDayArray = myConfig.config[sprinkleID].startFixDay;
341
403
  const objPfad = 'sprinkle.' + myConfig.config[sprinkleID].objectName;
342
404
  const weekday = ['Sun','Mon','Tue','Wed','Thur','Fri','Sat'];
405
+ let found = false;
343
406
  let curDay = formatTime(adapter, '', 'day');
344
407
  for ( let i=0; i<7; i++ ) {
345
- curDay++;
346
408
  if (curDay > 6) {curDay = curDay - 7;}
347
409
  if (weekDayArray[curDay] === true) {
410
+ found = true;
348
411
  if (returnOn) {
349
412
  return weekday[curDay];
350
413
  } else {
@@ -355,7 +418,9 @@ function curNextFixDay (sprinkleID, returnOn) {
355
418
  }
356
419
  break;
357
420
  }
421
+ curDay++;
358
422
  }
423
+ if (returnOn && found === false) {return 'off'}
359
424
  }
360
425
 
361
426
  //
@@ -364,7 +429,6 @@ function curNextFixDay (sprinkleID, returnOn) {
364
429
  * → Setzt den Status beim Start auf einen definierten Wert
365
430
  */
366
431
  function checkStates() {
367
- //
368
432
  /**
369
433
  * control.Holiday
370
434
  * @param {string|null} err
@@ -381,7 +445,9 @@ function checkStates() {
381
445
  * @param {ioBroker.State|null|undefined} state
382
446
  */
383
447
  adapter.getState('control.autoOnOff', (err, state) => {
384
- if (state && (state.val == null)) {
448
+ if (state && (typeof state.val === "boolean")) {
449
+ autoOnOffStr = state.val;
450
+ } else {
385
451
  autoOnOffStr = true;
386
452
  adapter.setState('control.autoOnOff', {
387
453
  val: autoOnOffStr,
@@ -422,21 +488,21 @@ async function checkActualStates () {
422
488
  try {
423
489
  /**
424
490
  * switch Holiday
425
- * @type {ioBroker.GetStatePromise}
426
- * @private {obj} _holiday
491
+ * @type {ioBroker.State | null}
492
+ * @private
427
493
  */
428
494
  const _holiday = await adapter.getStateAsync('control.Holiday');
429
- if (_holiday && _holiday.val) {
495
+ if (_holiday && _holiday.val && typeof _holiday.val === "boolean") {
430
496
  holidayStr = _holiday.val;
431
497
  }
432
498
 
433
499
  /**
434
500
  * switch autoOnOff
435
- * @type {ioBroker.GetStatePromise}
436
- * @private {obj} _autoOnOff
501
+ * @type {ioBroker.State | null}
502
+ * @private
437
503
  */
438
504
  const _autoOnOff = await adapter.getStateAsync('control.autoOnOff');
439
- if (_autoOnOff && _autoOnOff.val) {
505
+ if (_autoOnOff && _autoOnOff.val && typeof _autoOnOff.val === "boolean") {
440
506
  autoOnOffStr = _autoOnOff.val;
441
507
  }
442
508
 
@@ -472,7 +538,7 @@ async function checkActualStates () {
472
538
  * @private
473
539
  */
474
540
  const _weatherForInstanceToday = await adapter.getForeignStateAsync(
475
- adapter.config.weatherForInstance + '.NextDaysDetailed.Location_1.Day_1.rain_value'
541
+ weatherForecastTodayPfadStr
476
542
  ).catch((e) => adapter.log.warn(e));
477
543
  if (_weatherForInstanceToday && _weatherForInstanceToday.val) {
478
544
  if (typeof _weatherForInstanceToday.val == 'string') {
@@ -506,16 +572,41 @@ async function checkActualStates () {
506
572
  );
507
573
  }
508
574
  }
575
+
576
+ // wenn (...sprinkleName.autoOn == false[off]) so wird der aktuelle Sprenger [sprinkleName]
577
+ // bei false nicht automatisch gestartet
578
+ /**
579
+ * Abfrage von ...sprinkleName.autoOn
580
+ * @type {[myConfig.config]}
581
+ */
582
+ const result = myConfig.config;
583
+ if (result) {
584
+ for (const res of result) {
585
+ /**
586
+ * Abfrage ... .autoOn beim Start
587
+ * @type {ioBroker.State | void}
588
+ * @private
589
+ */
590
+ const _autoOn = await adapter.getForeignStateAsync(
591
+ res.autoOnID
592
+ ).catch((e) => adapter.log.warn(e));
593
+ if (_autoOn && typeof _autoOn.val === 'boolean') {
594
+ res.autoOn = _autoOn.val;
595
+ if (_autoOn.val === false) {adapter.log.info(`get ${res.objectName}.autoOn = ${res.autoOn}`)}
596
+ }
597
+ }
598
+ }
599
+
509
600
  if (adapter.config.actualValueLevel){
510
601
  /**
511
- * Füllstand der Zisterne in %
602
+ * Füllstand der Zisterne in % holen
512
603
  * @type {ioBroker.State | void}
513
604
  * @private
514
605
  */
515
606
  const _actualValueLevel = await adapter.getForeignStateAsync(
516
607
  adapter.config.actualValueLevel
517
608
  ).catch((e) => adapter.log.warn(e));
518
- if (_actualValueLevel && typeof _actualValueLevel.val !== undefined) {
609
+ if (_actualValueLevel && typeof parseFloat(_actualValueLevel.val) === "number") {
519
610
  valveControl.setFillLevelCistern(parseFloat(_actualValueLevel.val));
520
611
  }
521
612
  }
@@ -528,9 +619,6 @@ async function checkActualStates () {
528
619
  const _list = await adapter.getForeignObjectsAsync(adapter.namespace + '.sprinkle.*', 'channel').catch((e) => adapter.log.warn(e));
529
620
  if (_list) {
530
621
  ObjSprinkle = _list;
531
- await createSprinklers();
532
- await sleep(100);
533
- startTimeSprinkle();
534
622
  }
535
623
 
536
624
  } catch (e) {
@@ -583,6 +671,7 @@ const calcPos = schedule.scheduleJob('calcPosTimer', '5 0 * * *', function() {
583
671
  // Startzeit Festlegen → verzögert wegen Daten von SunCalc
584
672
  setTimeout(() => {
585
673
  startTimeSprinkle();
674
+ addStartTimeSprinkle();
586
675
  },1000);
587
676
 
588
677
  });
@@ -595,11 +684,119 @@ function sunPos() {
595
684
  // format sunrise time from the Date object → Formatieren Sie die Sonnenaufgangszeit aus dem Date-Objekt
596
685
  sunriseStr = ('0' + times.sunrise.getHours()).slice(-2) + ':' + ('0' + times.sunrise.getMinutes()).slice(-2);
597
686
 
598
- // format golden hour end time from the Date object => Formatiere golden hour end time aus dem Date-Objekt
687
+ // format golden hour end time from the Date object Formatiere golden hour end time aus dem Date-Objekt
599
688
  goldenHourEnd = ('0' + times.goldenHourEnd.getHours()).slice(-2) + ':' + ('0' + times.goldenHourEnd.getMinutes()).slice(-2);
689
+
690
+ // format sunset time from the Date object → formatieren Sie die Sonnenuntergangszeit aus dem Date-Objekt
691
+ sunsetStr = sunsetStr = ('0' + times.sunset.getHours()).slice(-2) + ':' + ('0' + times.sunset.getMinutes()).slice(-2);
600
692
 
601
693
  }
602
694
 
695
+ function addStartTimeSprinkle() {
696
+ schedule.cancelJob('sprinkleAddStartTime');
697
+ if (adapter.config.selectAddStartTime === 'greaterETpCurrent' || adapter.config.selectAddStartTime === 'withExternalSignal') {
698
+ let addStartTimeSplit = adapter.config.addWateringStartTime.split(':');
699
+ const scheduleAddStartTime = schedule.scheduleJob('sprinkleAddStartTime', addStartTimeSplit[1] + ' ' + addStartTimeSplit[0] + ' * * *', function() {
700
+ // if (autoOnOff == false) => keine auto Start
701
+ if (!autoOnOffStr) {
702
+ schedule.cancelJob('sprinkleAddStartTime');
703
+ return;
704
+ }
705
+ if (((adapter.config.selectAddStartTime === 'greaterETpCurrent') && (adapter.config.triggerAddStartTimeETpCur < evaporation.getETpTodayNum()))
706
+ || (adapter.config.selectAddStartTime === 'withExternalSignal' && addStartTimeSwitch)) {
707
+ let messageText = '';
708
+
709
+ // Filter enabled
710
+ const result = myConfig.config.filter(d => d.enabled === true);
711
+ if (result) {
712
+ /**
713
+ * Array zum flüchtigen Sammeln von Bewässerungsaufgaben
714
+ * @type {Array.<{auto: Boolean, sprinkleID: Number, wateringTime: Number}>}
715
+ */
716
+ const memAddList = [];
717
+
718
+ /**
719
+ * result Rain
720
+ * - (aktuelle Wettervorhersage - Schwellwert der Regenberücksichtigung) wenn Sensor sich im Freien befindet
721
+ * - (> 0) es regnet - Abbruch -
722
+ * - (≤ 0) Start der Bewässerung
723
+ * @param {boolean} inGreenhouse - Sensor befindet sich im Gewächshaus
724
+ * @returns {number} - resultierende Regenmenge
725
+ */
726
+ function resRain (inGreenhouse) {
727
+ return (adapter.config.weatherForecast && !inGreenhouse) ? (((+ weatherForecastTodayNum) - parseFloat(adapter.config.thresholdRain)).toFixed(1)) : 0;
728
+ }
729
+
730
+ for(const res of result) {
731
+ if (res.autoOn // Ventil aktiv
732
+ && (res.addWateringTime > 0) // zusätzliche Bewässerung aktiv time > 0
733
+ && (resRain(res.inGreenhouse) <= 0)) { // keine Regenvorhersage
734
+
735
+ switch (res.methodControlSM) {
736
+ case 'bistable':
737
+ if (res.soilMoisture.bool) {
738
+ messageText += `<b>${res.objectName}</b> (${res.soilMoisture.bool})\n`
739
+ + ` START => ${addTime(res.addWateringTime, '')}\n`;
740
+ memAddList.push({
741
+ auto: true,
742
+ sprinkleID: res.sprinkleID,
743
+ wateringTime: res.addWateringTime
744
+ });
745
+ }
746
+ break;
747
+ case 'fixDay':
748
+ messageText += `<b>${res.objectName}</b>\n`
749
+ + ` START => ${addTime(Math.round(60 * res.addWateringTime), '')}\n`;
750
+ memAddList.push({
751
+ auto: true,
752
+ sprinkleID: res.sprinkleID,
753
+ wateringTime: Math.round(60 * res.addWateringTime)
754
+ });
755
+ break;
756
+ case 'calculation':
757
+ let addCountdown = res.wateringTime * (res.soilMoisture.maxIrrigation - res.soilMoisture.val) / (res.soilMoisture.maxIrrigation - res.soilMoisture.triggersIrrigation) - res.wateringTime;
758
+ adapter.log.debug(`addCountdown: ${addCountdown}, addWateringTime: ${res.addWateringTime}, if(${(addCountdown - res.addWateringTime) > 0})`);
759
+ if ((addCountdown - res.addWateringTime) > 0) {
760
+ messageText += `<b>${res.objectName}</b> ${res.soilMoisture.pct}% (${res.soilMoisture.pctTriggerIrrigation}%)\n`
761
+ + ` START => ${addTime(Math.round(60 * addCountdown), '')}\n`;
762
+ memAddList.push({
763
+ auto: true,
764
+ sprinkleID: res.sprinkleID,
765
+ wateringTime: Math.round(60 * addCountdown)
766
+ });
767
+ }
768
+ break;
769
+ case 'analog':
770
+ if (res.soilMoisture.pct < res.soilMoisture.pctAddTriggersIrrigation) {
771
+ messageText += `<b>${res.objectName}</b> ${res.soilMoisture.pct} %(${res.soilMoisture.pctAddTriggersIrrigation}%)\n`
772
+ + ` START => ${addTime(Math.round(60 * res.addWateringTime), '')}\n`;
773
+ memAddList.push({
774
+ auto: true,
775
+ sprinkleID: res.sprinkleID,
776
+ wateringTime: Math.round(60 * res.addWateringTime)
777
+ });
778
+ }
779
+ break;
780
+ }
781
+ } else {
782
+ adapter.log.debug(`${res.objectName}: autoOn (${res.autoOn}) && addWateringTime (${res.addWateringTime} > 0) && resRain (${resRain(res.inGreenhouse)}) <= 0, if(${res.autoOn && (res.addWateringTime > 0) && (resRain(res.inGreenhouse) <= 0)})`);
783
+ }
784
+ }
785
+ valveControl.addList(memAddList);
786
+ }
787
+ if(!sendMessageText.onlySendError() && messageText.length > 0){
788
+ sendMessageText.sendMessage(messageText);
789
+ }
790
+ } else {
791
+ adapter.log.debug(`greaterETpCurrent: ${(adapter.config.selectAddStartTime === 'greaterETpCurrent')} & ${(adapter.config.triggerAddStartTimeETpCur < evaporation.getETpTodayNum())}, withExternalSignal; ${(adapter.config.selectAddStartTime === 'withExternalSignal')} & ${addStartTimeSwitch}`);
792
+ }
793
+ setTimeout(()=>{
794
+ schedule.cancelJob('sprinkleAddStartTime');
795
+ }, 200);
796
+ });
797
+ }
798
+ }
799
+
603
800
  // Determination of the irrigation time => Bestimmung der Bewässerungszeit
604
801
  function startTimeSprinkle() {
605
802
  let startTimeSplit = [];
@@ -608,9 +805,9 @@ function startTimeSprinkle() {
608
805
 
609
806
  schedule.cancelJob('sprinkleStartTime');
610
807
 
611
- // if autoOnOff == false => keine auto Start
808
+ // if (autoOnOff == false) => keine auto Start
612
809
  if (!autoOnOffStr) {
613
- adapter.log.info(`Sprinkle: autoOnOff == Aus( ${autoOnOffStr} )`);
810
+ adapter.log.info(`Sprinkle: autoOnOff == Aus ( ${autoOnOffStr} )`);
614
811
  adapter.setState('info.nextAutoStart', {
615
812
  val: 'autoOnOff = off(0)',
616
813
  ack: true
@@ -654,7 +851,7 @@ function startTimeSprinkle() {
654
851
  break;
655
852
  case 'livingSunrise' : /*Startauswahl = Sonnenaufgang*/
656
853
  infoMessage = 'Start mit Sonnenaufgang ';
657
- // format sunset/sunrise time from the Date object
854
+ // format sunrise time from the Date object
658
855
  newStartTime = addTime(sunriseStr, parseInt(adapter.config.timeShift));
659
856
  break;
660
857
  case 'livingGoldenHourEnd' : /*Startauswahl = Ende der Golden Hour*/
@@ -662,9 +859,14 @@ function startTimeSprinkle() {
662
859
  // format goldenHourEnd time from the Date object
663
860
  newStartTime = goldenHourEnd;
664
861
  break;
862
+ case 'livingSunset' : /*Startauswahl = Sonnenuntergang*/
863
+ infoMessage = 'Start mit Sonnenuntergang ';
864
+ // format sunset time from the Date object
865
+ newStartTime = addTime(sunsetStr, parseInt(adapter.config.timeShift));
866
+ break;
665
867
  }
666
868
  // Start am Wochenende →, wenn andere Zeiten verwendet werden soll
667
- if((adapter.config.publicWeekend) && ((myWeekday) === 6 || (myWeekday) === 0)){
869
+ if((adapter.config.publicWeekend) && ((myWeekday === 6) || (myWeekday === 0))){
668
870
  infoMessage = 'Start am Wochenende ';
669
871
  newStartTime = adapter.config.weekEndLiving;
670
872
  }
@@ -792,9 +994,10 @@ function startTimeSprinkle() {
792
994
  // --- fixDay -- Start an festen Tagen ohne Sensoren --- //
793
995
  // -- Bewässerungstag erreicht //
794
996
  case 'fixDay':
795
- if (res.startFixDay[today]) {
796
- /* Wenn in der Config Regenvorhersage aktiviert: Startvorgang abbrechen, wenn der Regen den eingegebenen Schwellwert überschreitet. */
797
- if (resRain(false) <= 0) {
997
+ /* Wenn in der Config Regenvorhersage aktiviert: Startvorgang abbrechen, wenn der Regen den eingegebenen Schwellwert überschreitet. */
998
+ if (resRain(false) <= 0) {
999
+ // Bewässerungstag erreicht
1000
+ if (res.startFixDay[today]) {
798
1001
  const curWateringTime = Math.round(60 * res.wateringTime * evaporation.timeExtension(res.wateringAdd));
799
1002
  memAddList.push({
800
1003
  auto: true,
@@ -809,14 +1012,22 @@ function startTimeSprinkle() {
809
1012
  res.startFixDay[today] = false;
810
1013
  res.startFixDay[(+ today + 2 > 6) ? (+ today-5) : (+ today+2)] = true;
811
1014
  }
812
- } else if (adapter.config.weatherForecast){
813
- messageText += ' ' + '<i>' + 'Start verschoben, da heute ' + weatherForecastTodayNum + 'mm Niederschlag' + '</i> ' + '\n';
814
- adapter.log.info(`${res.objectName}: Start verschoben, da Regenvorhersage für Heute ${weatherForecastTodayNum} mm [ ${resRain(false)} > 0 ]`);
815
- res.startFixDay[today] = false;
816
- res.startFixDay[(+ today + 1 > 6) ? (+ today-6) : (+ today+1)] = true;
817
1015
  }
818
- curNextFixDay(res.sprinkleID, false);
1016
+ } else if (adapter.config.weatherForecast){
1017
+ messageText += ' ' + '<i>' + 'Start verschoben, da heute ' + weatherForecastTodayNum + 'mm Niederschlag' + '</i> ' + '\n';
1018
+ adapter.log.info(`${res.objectName}: Start verschoben, da Regenvorhersage für Heute ${weatherForecastTodayNum} mm [ ${resRain(false)} > 0 ]`);
1019
+ if ((res.startDay === 'threeRd') || (res.startDay === 'twoNd')) {
1020
+ let startDay = -1;
1021
+ res.startFixDay.forEach((item, index) => {if (item) {startDay = index}});
1022
+ if (startDay !== -1) {
1023
+ res.startFixDay[startDay] = false;
1024
+ res.startFixDay[(+ startDay + 1 > 6) ? (+ startDay-6) : (+ startDay+1)] = true;
1025
+ } else {
1026
+ adapter.log.warn(`${res.objectName}: no start day found`)
1027
+ }
1028
+ }
819
1029
  }
1030
+ curNextFixDay(res.sprinkleID, false);
820
1031
  break;
821
1032
  // --- calculation -- Berechnung der Bodenfeuchte --- //
822
1033
  // -- Bodenfeuchte zu gering -- //
@@ -837,7 +1048,7 @@ function startTimeSprinkle() {
837
1048
  } else if (adapter.config.weatherForecast) {
838
1049
  /* Bewässerung unterdrückt da ausreichende Regenvorhersage */
839
1050
  messageText += ' ' + '<i>' + 'Start verschoben, da heute ' + weatherForecastTodayNum + 'mm Niederschlag' + '</i> ' + '\n';
840
- adapter.log.info(`${res.objectName}: Start verschoben, da Regenvorhersage für Heute ${weatherForecastTodayNum} mm [ ${res.soilMoisture.val} (${resMoisture}) <= ${res.soilMoisture.triggersIrrigation} ]`);
1051
+ adapter.log.info(`${res.objectName}: Start verschoben, da Regenvorhersage für Heute ${weatherForecastTodayNum} mm [ ${res.soilMoisture.val.toFixed(1)} (${resMoisture.toFixed(1)}) <= ${res.soilMoisture.triggersIrrigation} ]`);
841
1052
  }
842
1053
  }
843
1054
  break;
@@ -862,6 +1073,43 @@ function startTimeSprinkle() {
862
1073
 
863
1074
  //
864
1075
  async function createSprinklers() {
1076
+ /**Creates an Object .control.addStartTimeSwitch, when additional watering has been activated via an external signal
1077
+ * - Erzeugt ein Object .control.addStartTimeSwitch, wenn die Zusatzbewässerung über ein externes Signal aktiviert wurde
1078
+ * @type {{id: string, name: string} | void}
1079
+ * @private
1080
+ */
1081
+ const _addStartTimeSwitch = await adapter.findForeignObjectAsync(`${adapter.namespace}.control.addStartTimeSwitch`, 'boolean').catch((e) => adapter.log.warn(`.control.addStartTimeSwitch ${e}`));
1082
+ if (_addStartTimeSwitch.id !== `${adapter.namespace}.control.addStartTimeSwitch` && adapter.config.selectAddStartTime === 'withExternalSignal') {
1083
+ adapter.setObjectNotExistsAsync(`${adapter.namespace}.control.addStartTimeSwitch`, {
1084
+ 'type': 'state',
1085
+ 'common': {
1086
+ "role": "switch",
1087
+ 'name': 'additional irrigation enabled',
1088
+ 'type': 'boolean',
1089
+ 'read': true,
1090
+ 'write': true,
1091
+ 'def': false
1092
+ },
1093
+ 'native': {}
1094
+ }).catch((e) => adapter.log.warn(`.control.addStartTimeSwitch ${e}`));
1095
+ } else if (_addStartTimeSwitch.id === `${adapter.namespace}.control.addStartTimeSwitch`) {
1096
+ if (adapter.config.selectAddStartTime !== 'withExternalSignal') {
1097
+ adapter.delObjectAsync(`${adapter.namespace}.control.addStartTimeSwitch`).catch((e) => adapter.log.warn(`.control.addStartTimeSwitch ${e}`));
1098
+ addStartTimeSwitch = false;
1099
+ } else {
1100
+ /** auslesen .control.addStartTimeSwitch.val
1101
+ * @type {ioBroker.State | void}
1102
+ * @private
1103
+ */
1104
+ const _state = await adapter.getStateAsync(`${adapter.namespace}.control.addStartTimeSwitch`).catch((e) => adapter.log.warn(`.control.addStartTimeSwitch ${e}`));
1105
+ if (typeof _state.val === 'boolean') {
1106
+ addStartTimeSwitch = _state.val;
1107
+ }
1108
+ }
1109
+ }
1110
+
1111
+
1112
+
865
1113
  const result = adapter.config.events;
866
1114
  if (result) {
867
1115
  for(const res of result) {
@@ -880,7 +1128,7 @@ async function createSprinklers() {
880
1128
 
881
1129
  let nameMetConSM, objMetConSM;
882
1130
  await fillMetConSM(res);
883
- function fillMetConSM(res) {
1131
+ async function fillMetConSM(res) {
884
1132
  //adapter.log.debug(JSON.stringify(res));
885
1133
  switch (res.methodControlSM) {
886
1134
  case 'calculation':
@@ -983,7 +1231,7 @@ async function createSprinklers() {
983
1231
  'name': res.sprinkleName
984
1232
  },
985
1233
  'native': {},
986
- }).catch((e) => adapter.log.warn(`sprinkle.${objectName} ${e}`));
1234
+ });
987
1235
  // Create Object for .history
988
1236
  const _historyNotExist = await adapter.setObjectNotExistsAsync('sprinkle.' + objectName + '.history', {
989
1237
  'type': 'channel',
@@ -991,7 +1239,7 @@ async function createSprinklers() {
991
1239
  'name': res.sprinkleName + ' => History'
992
1240
  },
993
1241
  'native': {},
994
- }).catch((e) => adapter.log.warn(`${objectName}.history ${e}`));
1242
+ });
995
1243
  // Create Object for .history.curCalWeekConsumed
996
1244
  // Sprinkler consumption of the current calendar week => History - Sprinkler-Verbrauch der aktuellen Kalenderwoche (783 Liter)
997
1245
  const _curCalWeekConsumedNotExist = adapter.setObjectNotExistsAsync(objPfad + '.history.curCalWeekConsumed', {
@@ -1006,7 +1254,7 @@ async function createSprinklers() {
1006
1254
  'def': 0
1007
1255
  },
1008
1256
  'native': {},
1009
- }).catch((e) => adapter.log.warn(`${objectName}.curCalWeekConsumed ${e}`));
1257
+ });
1010
1258
  // Create Object for .history.curCalWeekRunningTime
1011
1259
  // Sprinkler running time of the current calendar week => History - Sprinkler-Laufzeit der aktuellen Kalenderwoche (783 Liter)
1012
1260
  const _curCalWeekRunningTimeNotExist = adapter.setObjectNotExistsAsync(objPfad + '.history.curCalWeekRunningTime', {
@@ -1020,7 +1268,7 @@ async function createSprinklers() {
1020
1268
  'def': '00:00'
1021
1269
  },
1022
1270
  'native': {},
1023
- }).catch((e) => adapter.log.warn(`${objectName}.curCalWeekRunningTime ${e}`));
1271
+ });
1024
1272
  // Create Object for .history.lastCalWeekConsumed
1025
1273
  // Sprinkler consumption of the last calendar week => History - Sprinkler-Verbrauch der letzten Kalenderwoche (783 Liter)
1026
1274
  const _lastCalWeekConsumedNotExist = adapter.setObjectNotExistsAsync(objPfad + '.history.lastCalWeekConsumed', {
@@ -1035,7 +1283,7 @@ async function createSprinklers() {
1035
1283
  'def': 0
1036
1284
  },
1037
1285
  'native': {},
1038
- }).catch((e) => adapter.log.warn(`${objectName}.lastCalWeekConsumed ${e}`));
1286
+ });
1039
1287
  // Create Object for .history.lastCalWeekRunningTime
1040
1288
  // Sprinkler running time of the last calendar week => History - Sprinkler-Laufzeit der letzten Kalenderwoche (783 Liter)
1041
1289
  const _lastCalWeekRunningTimeNotExist = adapter.setObjectNotExistsAsync(objPfad + '.history.lastCalWeekRunningTime', {
@@ -1049,7 +1297,7 @@ async function createSprinklers() {
1049
1297
  'def': '00:00'
1050
1298
  },
1051
1299
  'native': {},
1052
- }).catch((e) => adapter.log.warn(`${objectName}.curCalWeekRunningTime ${e}`));
1300
+ });
1053
1301
  // Create Object for .history.lastConsumed
1054
1302
  // Last consumed of sprinkler => History - Letzte Verbrauchsmenge des Ventils (783 Liter)
1055
1303
  const _lastConsumedNotExist = adapter.setObjectNotExistsAsync(objPfad + '.history.lastConsumed', {
@@ -1064,7 +1312,7 @@ async function createSprinklers() {
1064
1312
  'def': 0
1065
1313
  },
1066
1314
  'native': {},
1067
- }).catch((e) => adapter.log.warn(`${objectName}.lastConsumed ${e}`));
1315
+ });
1068
1316
  // Create Object for .history.lastOn
1069
1317
  // Last On of sprinkler => History - Letzter Start des Ventils (30.03 06:30)
1070
1318
  const _lastOnNotExist = adapter.setObjectNotExistsAsync(objPfad + '.history.lastOn', {
@@ -1078,7 +1326,7 @@ async function createSprinklers() {
1078
1326
  'def': '-'
1079
1327
  },
1080
1328
  'native': {},
1081
- }).catch((e) => adapter.log.warn(`${objectName}.lastOn ${e}`));
1329
+ });
1082
1330
  // Create Object for .history.lastRunningTime
1083
1331
  // Last running time of sprinkler => History - Letzte Laufzeit des Ventils (0 sek, 47:00 min, 1:03:45 )
1084
1332
  const _lastRunningTimeNotExist = adapter.setObjectNotExistsAsync(objPfad + '.history.lastRunningTime', {
@@ -1092,24 +1340,70 @@ async function createSprinklers() {
1092
1340
  'def': '00:00'
1093
1341
  },
1094
1342
  'native': {},
1095
- }).catch((e) => adapter.log.warn(`${objectName}.lastRunningTime ${e}`));
1343
+ });
1096
1344
  // Create Object for .autoOn
1097
- const _autoOnNotExist = await adapter.setObjectNotExistsAsync(objPfad + '.autoOn', {
1098
- 'type': 'state',
1099
- 'common': {
1100
- 'role': 'state',
1101
- 'name': objectName + ' => Switch automatic mode on / off',
1102
- 'type': 'boolean',
1103
- 'read': true,
1104
- 'write': true,
1105
- 'def': true
1106
- },
1107
- 'native': {},
1108
- }).catch((e) => adapter.log.warn(`${objectName}.autoOn ${e}`));
1345
+ const _autoOnNotExist = adapter.setObjectNotExistsAsync(objPfad + '.autoOn', {
1346
+ 'type': 'state',
1347
+ 'common': {
1348
+ 'role': 'Switch',
1349
+ 'name': objectName + ' => Switch automatic mode on / off',
1350
+ 'type': 'boolean',
1351
+ "states": {
1352
+ "false": "off",
1353
+ "true": "on"
1354
+ },
1355
+ 'read': true,
1356
+ 'write': true,
1357
+ 'def': true
1358
+ },
1359
+ 'native': {},
1360
+ }).catch((e) => adapter.log.warn(`setObjectNotExistsAsync ${objectName}.autoOn ${e}`));
1109
1361
  // Create Object for .actualSoilMoisture
1110
- const _actualSoilMoistureNotExist = await adapter.setObjectNotExistsAsync(objPfad + '.actualSoilMoisture',
1111
- objMetConSM
1112
- ).catch((e) => adapter.log.warn(`${objectName}.actualSoilMoisture ${e}`));
1362
+ const _actualSoilMoistureFind = await adapter.findForeignObjectAsync(`${adapter.namespace}.${objPfad}.actualSoilMoisture`, `${objMetConSM.common.type}`);
1363
+ if (_actualSoilMoistureFind.id !== `${adapter.namespace}.${objPfad}.actualSoilMoisture` || _actualSoilMoistureFind.name !== nameMetConSM) {
1364
+ await adapter.setObjectAsync(
1365
+ objPfad + '.actualSoilMoisture',
1366
+ objMetConSM
1367
+ ).catch((e) => adapter.log.warn(e));
1368
+ adapter.log.info(`sprinkleControl [sprinkle.${objectName}.actualSoilMoisture] was updated`);
1369
+ }
1370
+
1371
+ // postponeByOneDay → um einen Tag verschieben bei fixDay (twoNd & threeRd)
1372
+ const _postponeByOneDay = await adapter.findForeignObjectAsync(`${adapter.namespace}.${objPfad}.postponeByOneDay`, `boolean`);
1373
+ if (_postponeByOneDay.id !== `${adapter.namespace}.${objPfad}.postponeByOneDay`
1374
+ && res.methodControlSM === "fixDay"
1375
+ && (res.startDay === "twoNd"
1376
+ || res.startDay === "threeRd")) {
1377
+ await adapter.setObjectNotExistsAsync(objPfad + '.postponeByOneDay', {
1378
+ 'type': 'state',
1379
+ 'common': {
1380
+ "role": 'button',
1381
+ "name": objectName + 'Postpone start by one day',
1382
+ "type": 'boolean',
1383
+ "read": true,
1384
+ "write": true,
1385
+ "def": false
1386
+ },
1387
+ 'native': {
1388
+ "UNIT": "",
1389
+ "TAB_ORDER": 0,
1390
+ "OPERATIONS": 6,
1391
+ "FLAGS": 1,
1392
+ "TYPE": "ACTION",
1393
+ "MIN": false,
1394
+ "MAX": true,
1395
+ "DEFAULT": false
1396
+ }
1397
+ });
1398
+ adapter.subscribeStates(`${adapter.namespace}.${objPfad}.postponeByOneDay`);
1399
+ } else if (res.methodControlSM === "fixDay"
1400
+ && (res.startDay === "twoNd"
1401
+ || res.startDay === "threeRd")) {
1402
+ adapter.subscribeStates(`${adapter.namespace}.${objPfad}.postponeByOneDay`);
1403
+ } else {
1404
+ await adapter.delObjectAsync(`${adapter.namespace}.${objPfad}.postponeByOneDay`); // "sprinklecontrol.0.sprinkle.???.actualSoilMoisture"
1405
+ }
1406
+
1113
1407
  // Create Object for .countdown => Countdown des Ventils
1114
1408
  const _countdownNotExist = adapter.setObjectNotExistsAsync(objPfad + '.countdown', {
1115
1409
  'type': 'state',
@@ -1122,7 +1416,7 @@ async function createSprinklers() {
1122
1416
  'def': '-'
1123
1417
  },
1124
1418
  'native': {},
1125
- }).catch((e) => adapter.log.warn(`${objectName}.countdown ${e}`));
1419
+ });
1126
1420
  // Create Object for .runningTime => Laufzeit des Ventils
1127
1421
  const _runningTimeNotExist = await adapter.setObjectNotExistsAsync(objPfad + '.runningTime', {
1128
1422
  'type': 'state',
@@ -1135,7 +1429,7 @@ async function createSprinklers() {
1135
1429
  'def': '-'
1136
1430
  },
1137
1431
  'native': {},
1138
- }).catch((e) => adapter.log.warn(`${objectName}.runningTime ${e}`));
1432
+ });
1139
1433
  // Create Object for .sprinklerState => Zustand des Ventils im Thread
1140
1434
  // <<< 1 = warten >>> ( 0:off; 1:wait; 2:on; 3:break; 4:Boost(on); 5:off(Boost) )
1141
1435
  // Create .sprinklerState
@@ -1159,8 +1453,8 @@ async function createSprinklers() {
1159
1453
  'write': false,
1160
1454
  'def': 0
1161
1455
  },
1162
- 'native': {}
1163
- }).catch((e) => adapter.log.warn(`${objectName}.sprinklerState ${e}`));
1456
+ 'native': {},
1457
+ });
1164
1458
  // Create Object for triggerPoint → Schaltpunkt der Bodenfeuchte
1165
1459
  const _triggerPointNotExist = await adapter.setObjectNotExistsAsync(objPfad + '.triggerPoint', {
1166
1460
  'type': 'state',
@@ -1173,10 +1467,10 @@ async function createSprinklers() {
1173
1467
  'def': '-'
1174
1468
  },
1175
1469
  'native': {},
1176
- }).catch((e) => adapter.log.warn(`${objectName}.triggerPoint ${e}`));
1470
+ });
1177
1471
  // Object created
1178
1472
  let value = true;
1179
- (await Promise.all([
1473
+ await (await Promise.all([
1180
1474
  _sprinkleNotExist,
1181
1475
  _historyNotExist,
1182
1476
  _curCalWeekConsumedNotExist,
@@ -1187,15 +1481,14 @@ async function createSprinklers() {
1187
1481
  _lastOnNotExist,
1188
1482
  _lastRunningTimeNotExist,
1189
1483
  _autoOnNotExist,
1190
- _actualSoilMoistureNotExist,
1191
1484
  _countdownNotExist,
1192
1485
  _runningTimeNotExist,
1193
1486
  _sprinklerStateNotExists,
1194
1487
  _triggerPointNotExist
1195
1488
  ])).forEach((val) => {
1196
- value += val;
1489
+ value &= val;
1197
1490
  });
1198
- if (value){
1491
+ if(value) {
1199
1492
  adapter.log.info(`sprinkleControl [sprinkle.${objectName}] was created`);
1200
1493
  }
1201
1494
 
@@ -1203,34 +1496,6 @@ async function createSprinklers() {
1203
1496
  // +++++ zustände der States aktualisieren +++++ //
1204
1497
  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //
1205
1498
 
1206
- // Abfrage, ob sich die Bewässerungsart geändert hat
1207
- const _actualSoilMoistureObj = await adapter.getObjectAsync(objPfad + '.actualSoilMoisture').catch((e) => adapter.log.warn(e));
1208
- if (_actualSoilMoistureObj) {
1209
- if (typeof _actualSoilMoistureObj.common.name !== 'string' || _actualSoilMoistureObj.common.name !== nameMetConSM) { // Objekt wurde ausgelesen
1210
- await adapter.setObjectAsync(
1211
- objPfad + '.actualSoilMoisture',
1212
- objMetConSM
1213
- ).catch((e) => adapter.log.warn(e));
1214
- adapter.log.info(`sprinkleControl [sprinkle.${objectName}.actualSoilMoisture] was updated`);
1215
-
1216
- }
1217
- }
1218
- //
1219
- if (await _autoOnNotExist) {
1220
- const _autoOn = await adapter.getStateAsync(objPfad + '.autoOn').catch((e) => adapter.log.warn(e));
1221
- if (_autoOn && _autoOn.val) {
1222
- if (typeof _autoOn.val === 'boolean' && ((new Date () - _autoOn.ts) > 60000)) {
1223
- myConfig.config[j].autoOn = _autoOn.val;
1224
- } else {
1225
- adapter.setStateAsync(
1226
- objPfad + '.autoOn',
1227
- true,
1228
- true
1229
- ).catch((e) => adapter.log.warn(`${objectName}.autoOn ${e}`));
1230
- myConfig.config[j].autoOn = true;
1231
- }
1232
- }
1233
- }
1234
1499
  //
1235
1500
  if(await _countdownNotExist){
1236
1501
  const _countdown = await adapter.getStateAsync(objPfad + '.countdown').catch((e) => adapter.log.warn(`${objectName}.countdown ${e}`));
@@ -1315,7 +1580,7 @@ async function createSprinklers() {
1315
1580
  * false → Zweitage-modus (twoNd)
1316
1581
  */
1317
1582
  async function setNewDay (threeRd) {
1318
- const today = formatTime(adapter,'', 'day');
1583
+ const today = await formatTime(adapter,'', 'day');
1319
1584
  /**
1320
1585
  *
1321
1586
  * @type {ioBroker.GetStatePromise} _actualSoilMoisture
@@ -1347,7 +1612,6 @@ async function createSprinklers() {
1347
1612
  } else if (myConfig.config[j].startDay === 'twoNd') {
1348
1613
  await setNewDay(false);
1349
1614
  } else if (myConfig.config[j].startDay === 'fixDay') {
1350
- adapter.log.info(`set Day (fixDay): ${myConfig.config[j].objectName}`);
1351
1615
  curNextFixDay(myConfig.config[j].sprinkleID, false);
1352
1616
  }
1353
1617
 
@@ -1387,7 +1651,7 @@ async function createSprinklers() {
1387
1651
  ).catch((e) => adapter.log.warn(e));
1388
1652
  break;
1389
1653
 
1390
- }
1654
+ }
1391
1655
 
1392
1656
  } catch (e) {
1393
1657
  adapter.log.warn(`sprinkleControl cannot created ... Please check your sprinkleControl config: ${e}`);
@@ -1419,27 +1683,44 @@ async function createSprinklers() {
1419
1683
  if (fullRes.indexOf(resultID) === -1) {
1420
1684
  try {
1421
1685
  // object deleted
1686
+ /**
1687
+ * del when exist Object Async
1688
+ * @param id - the id of the object
1689
+ * @param type - common.type of the state
1690
+ * @returns {Promise<void>}
1691
+ */
1692
+ const delWhenExistObjectAsync = async (id, type) => {
1693
+ const _find = await adapter.findForeignObjectAsync(`${id}`, `${type}`);
1694
+ if (_find && _find.id === `${id}`) {
1695
+ await adapter.delObjectAsync(`${id}`).catch((e) => adapter.log.warn(e)); // "sprinklecontrol.0.sprinkle.???.postponeByOneDay"
1696
+ }
1697
+ }
1698
+
1422
1699
  Promise.all([
1423
- adapter.delObjectAsync(resID + '.actualSoilMoisture'), // "sprinklecontrol.0.sprinkle.???.actualSoilMoisture"
1424
- adapter.delObjectAsync(resID + '.triggerPoint'), // "sprinklecontrol.0.sprinkle.???.triggerPoint"
1425
- adapter.delObjectAsync(resID + '.sprinklerState'), // "sprinklecontrol.0.sprinkle.???.sprinklerState"
1426
- adapter.delObjectAsync(resID + '.runningTime'), // "sprinklecontrol.0.sprinkle.???.runningTime"
1427
- adapter.delObjectAsync(resID + '.countdown'), // "sprinklecontrol.0.sprinkle.???.countdown"
1428
- adapter.delObjectAsync(resID + '.autoOn'), // "sprinklecontrol.0.sprinkle.???.autoOn"
1429
- adapter.delObjectAsync(resID + '.history.lastOn'), // "sprinklecontrol.0.sprinkle.???..history.lastOn"
1430
- adapter.delObjectAsync(resID + '.history.lastConsumed'), // "sprinklecontrol.0.sprinkle.???..history.lastConsumed"
1431
- adapter.delObjectAsync(resID + '.history.lastRunningTime'), // "sprinklecontrol.0.sprinkle.???.history.lastRunningTime"
1432
- adapter.delObjectAsync(resID + '.history.curCalWeekConsumed'), // "sprinklecontrol.0.sprinkle.???.history.curCalWeekConsumed"
1433
- adapter.delObjectAsync(resID + '.history.lastCalWeekConsumed'), // "sprinklecontrol.0.sprinkle.???.history.lastCalWeekConsumed"
1434
- adapter.delObjectAsync(resID + '.history.curCalWeekRunningTime'), // "sprinklecontrol.0.sprinkle.???.history.curCalWeekRunningTime"
1435
- adapter.delObjectAsync(resID + '.history.lastCalWeekRunningTime'), // "sprinklecontrol.0.sprinkle.???.history.lastCalWeekRunningTime"
1700
+ adapter.delObjectAsync(resID + '.actualSoilMoisture'), // "sprinklecontrol.0.sprinkle.???.actualSoilMoisture"
1701
+ adapter.delObjectAsync(resID + '.triggerPoint'), // "sprinklecontrol.0.sprinkle.???.triggerPoint"
1702
+ adapter.delObjectAsync(resID + '.sprinklerState'), // "sprinklecontrol.0.sprinkle.???.sprinklerState"
1703
+ adapter.delObjectAsync(resID + '.runningTime'), // "sprinklecontrol.0.sprinkle.???.runningTime"
1704
+ delWhenExistObjectAsync(`${resID}.postponeByOneDay`, `boolean`), // "sprinklecontrol.0.sprinkle.???.postponeByOneDay" wenn vorhanden löschen
1705
+ adapter.delObjectAsync(resID + '.countdown'), // "sprinklecontrol.0.sprinkle.???.countdown"
1706
+ adapter.delObjectAsync(resID + '.autoOn'), // "sprinklecontrol.0.sprinkle.???.autoOn"
1707
+ adapter.delObjectAsync(resID + '.history.lastOn'), // "sprinklecontrol.0.sprinkle.???.history.lastOn"
1708
+ adapter.delObjectAsync(resID + '.history.lastConsumed'), // "sprinklecontrol.0.sprinkle.???.history.lastConsumed"
1709
+ adapter.delObjectAsync(resID + '.history.lastRunningTime'), // "sprinklecontrol.0.sprinkle.???.history.lastRunningTime"
1710
+ adapter.delObjectAsync(resID + '.history.curCalWeekConsumed'), // "sprinklecontrol.0.sprinkle.???.history.curCalWeekConsumed"
1711
+ adapter.delObjectAsync(resID + '.history.lastCalWeekConsumed'), // "sprinklecontrol.0.sprinkle.???.history.lastCalWeekConsumed"
1712
+ adapter.delObjectAsync(resID + '.history.curCalWeekRunningTime'), // "sprinklecontrol.0.sprinkle.???.history.curCalWeekRunningTime"
1713
+ adapter.delObjectAsync(resID + '.history.lastCalWeekRunningTime') // "sprinklecontrol.0.sprinkle.???.history.lastCalWeekRunningTime"
1714
+ ]
1715
+ ).then(async ()=>{
1436
1716
  // History - Objekt(Ordner.history) löschen
1437
- await adapter.delObjectAsync(resID + '.history'),
1717
+ await adapter.delObjectAsync(resID + '.history');
1718
+ }).then(async ()=>{
1438
1719
  // Objekt(Ordner) löschen
1439
- await adapter.delObjectAsync(resID)
1440
- ]).then((resultID)=>{
1441
- adapter.log.info(`sprinkleControl [${resultID}] was deleted`);
1442
- })
1720
+ await adapter.delObjectAsync(resID);
1721
+ }).then(()=>{
1722
+ adapter.log.info(`sprinkleControl [${resID}] was deleted`);
1723
+ });
1443
1724
  } catch (e) {
1444
1725
  adapter.log.warn(e);
1445
1726
  }
@@ -1448,17 +1729,20 @@ async function createSprinklers() {
1448
1729
  }
1449
1730
  }
1450
1731
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1732
+
1451
1733
  /**
1452
1734
  *
1453
1735
  * @param {number} ms => Waiting time in ms
1454
1736
  * @return {Promise<unknown>}
1455
1737
  */
1738
+ /*
1456
1739
  async function sleep(ms) {
1457
1740
  return new Promise(async (resolve) => {
1458
1741
  // @ts-ignore
1459
1742
  timerSleep = setTimeout(async () => resolve(), ms);
1460
1743
  });
1461
1744
  }
1745
+ */
1462
1746
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1463
1747
  /**
1464
1748
  *
@@ -1472,31 +1756,26 @@ function main(adapter) {
1472
1756
  adapter.config:
1473
1757
  */
1474
1758
  adapter.log.debug(`adapter.config.events: ${JSON.stringify(adapter.config.events)}`);
1475
-
1476
1759
  /**
1477
1760
  * The adapters' config (in the instance object everything under the attribute "native") is accessible via adapter.config:
1478
1761
  * => Auf die Adapterkonfiguration (im Instanz objekt alles unter dem Attribut "native") kann zugegriffen werden über adapter.config:
1479
1762
  * @param {any} err
1480
1763
  * @param {any} obj
1481
1764
  */
1482
- adapter.getForeignObject('system.config', (err) => {
1483
- if (!err) {
1484
- // init createConfig
1485
- myConfig.createConfig(adapter);
1765
+ adapter.getForeignObject('system.config', (err, obj) => {
1766
+ if (obj) {
1486
1767
  checkStates();
1487
1768
  }
1488
1769
  });
1489
-
1490
- GetSystemData().then();
1770
+ createSprinklers().catch((e) => adapter.log.warn(e));
1771
+ GetSystemData().catch((e) => adapter.log.warn(e));
1491
1772
  sendMessageText.initConfigMessage(adapter);
1492
-
1493
- timer = setTimeout(function() {
1494
- checkActualStates().then();
1495
- // init evaporation
1496
- evaporation.initEvaporation(adapter);
1497
- // Hauptpumpe zur Bewässerung setzen
1498
- valveControl.initValveControl(adapter);
1499
- sunPos();
1773
+ evaporation.initEvaporation(adapter); // init evaporation
1774
+ checkActualStates().catch((e) => adapter.log.warn(e));
1775
+ sunPos();
1776
+ timer = setTimeout(() => {
1777
+ startTimeSprinkle();
1778
+ addStartTimeSprinkle()
1500
1779
  }, 2000);
1501
1780
 
1502
1781
  /*
@@ -1518,11 +1797,17 @@ function main(adapter) {
1518
1797
  if (adapter.config.publicHolidays === true && (adapter.config.publicHolInstance + '.morgen.*')) {
1519
1798
  adapter.subscribeForeignStates(adapter.config.publicHolInstance + '.morgen.*');
1520
1799
  }
1521
- if ((adapter.config.weatherForecast === true) && (adapter.config.weatherForInstance + '.NextDaysDetailed.Location_1.Day_1.*')) {
1522
- adapter.subscribeForeignStates(adapter.config.weatherForInstance + '.NextDaysDetailed.Location_1.Day_1.rain_value');
1523
- }
1524
- if ((adapter.config.weatherForecast === true) && (adapter.config.weatherForInstance + '.NextDaysDetailed.Location_1.Day_2.*')) {
1525
- adapter.subscribeForeignStates(adapter.config.weatherForInstance + '.NextDaysDetailed.Location_1.Day_2.rain_value');
1800
+ if (adapter.config.weatherForecast === true) {
1801
+ if (adapter.config.weatherForecastService === 'ownDataPoint') {
1802
+ weatherForecastTodayPfadStr = adapter.config.pathRainForecast;
1803
+ adapter.subscribeForeignStates(weatherForecastTodayPfadStr);
1804
+ } else if (adapter.config.weatherForecastService === 'dasWetter' && adapter.config.weatherForInstance) {
1805
+ weatherForecastTodayPfadStr = adapter.config.weatherForInstance + '.NextDaysDetailed.Location_1.Day_1.rain_value';
1806
+ adapter.subscribeForeignStates(weatherForecastTodayPfadStr);
1807
+ adapter.subscribeForeignStates(adapter.config.weatherForInstance + '.NextDaysDetailed.Location_1.Day_2.rain_value');
1808
+ } else {
1809
+ adapter.log.warn('There is no valid data record stored in the weather forecast, please correct it!')
1810
+ }
1526
1811
  }
1527
1812
  if (adapter.config.actualValueLevel !== '') {
1528
1813
  adapter.subscribeForeignStates(adapter.config.actualValueLevel);