iobroker.sprinklecontrol 0.2.18 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,456 +1,498 @@
1
- 'use strict';
2
- /*
3
- info: log aufbau evaporation.js: #3.*
4
- */
5
- const myConfig = require('./myConfig.js'); // myConfig → Speichern und abrufen von Konfigurationsdaten der Ventile
6
- const formatTime = require('./tools').formatTime; // tools => laden von Hilfsfunktionen
7
- const trend = require('./tools').trend; // tools => laden von Hilfsfunktionen
8
-
9
- let adapter;
10
-
11
- /* calcEvaporation */
12
- /**
13
- * akt. Temperatur °C
14
- * - -20 bis 55°C
15
- * - ts Zeitstempel, wann der Wert aktualisiert wurde (auch ohne Wertänderung)
16
- */
17
- const curTemperature = {
18
- val: 0,
19
- ts: undefined
20
- };
21
- /**
22
- * akt. LuftFeuchtigkeit in %
23
- * - 1 bis 99%
24
- * - lc: Zeitstempel, wann der Wert geändert wurde
25
- */
26
- const curHumidity = {
27
- val: 0,
28
- lc: undefined
29
- };
30
- /**
31
- * akt. Helligkeit (relativ)
32
- * - 0 bis 100000
33
- * - intern Begrenzung 100...7000
34
- * - lc: Zeitstempel, wann der Wert geändert wurde
35
- */
36
- const curIllumination = {
37
- val: 0,
38
- lc: undefined
39
- };
40
- /**
41
- * akt. WindGeschwindigkeit in km/h
42
- * - 0 bis 200 km/h
43
- * - lc: Zeitstempel, wann der Wert geändert wurde
44
- */
45
- const curWindSpeed = {
46
- val: 0,
47
- lc: undefined
48
- };
49
- /**
50
- * last rain container => letzter Regencontainer in mm
51
- */
52
- let lastRainCounter = 0;
53
- /**
54
- * letzte Aktualisierungszeit des Temperaturwertes
55
- */
56
- let lastChangeEvaPor = new Date();
57
- let ETpTodayNum = 0;
58
- /**
59
- * Extraterrestrische Tagesstrahlung in W/m²
60
- * - berechneter tabellarischer Tageswert
61
- */
62
- let toDayExtraTerStr;
63
- /**
64
- * kleinste extraterrestrische Tagesstrahlung im Jahr in W/m²
65
- * - berechneter tabellarischer Mindestwert
66
- */
67
- let minExtraTerStr;
68
- /**
69
- * größter extraterrestrische Tagesstrahlung im Jahr in W/m²
70
- * - berechneter tabellarischer Maximalwert
71
- */
72
- let maxExtraTerStr;
73
-
74
- /**
75
- * Extraterrestrische Strahlung (kurzwelliger Strahlungseinfluss von der Sonne an der Obergrenze der Erdatmosphäre) in W/m²
76
- * als Tagesmittel, Nordhalbkugel (IQBAL. 1983)
77
- *
78
- */
79
- const ExtraTerStrTab = {
80
- Tag:[ 21, 52, 80, 111, 141, 172, 202, 233, 264, 294, 325, 355],
81
- 46: [135, 198, 289, 382, 452, 483, 467, 409, 324, 230, 153, 117],
82
- 47: [128, 191, 283, 378, 450, 482, 466, 406, 319, 224, 146, 110],
83
- 48: [121, 184, 277, 375, 449, 482, 465, 403, 314, 217, 139, 103],
84
- 49: [114, 177, 271, 371, 447, 481, 464, 400, 309, 211, 132, 96],
85
- 50: [107, 170, 265, 367, 445, 481, 463, 398, 304, 204, 125, 89],
86
- 51: [100, 163, 259, 363, 443, 480, 462, 394, 298, 197, 118, 83],
87
- 52: [ 93, 156, 253, 358, 441, 480, 461, 391, 293, 191, 111, 76],
88
- 53: [ 86, 149, 247, 354, 439, 479, 459, 388, 287, 184, 104, 70],
89
- 54: [ 79, 142, 240, 350, 437, 478, 458, 384, 282, 177, 97, 63],
90
- 55: [ 73, 135, 234, 345, 435, 478, 457, 381, 276, 170, 90, 56]
91
- };
92
-
93
- /*----------------------------------------------------------- interne Funktionen -----------------------------------------------------------*/
94
-
95
- /**
96
- * Ermittlung der heutigen extraterrestrischen Strahlung
97
- * anhand der Tabelle "ExtraTerStrTab"
98
- */
99
- function extraTerStr () { // latitude Breitengrad
100
- const dayNr = formatTime(adapter,'','dayNr');
101
- // - unterer Tabellenwert der Latitude
102
- const lowerLatitude = ((parseInt(adapter.config.latitude, 10) < 46 ) ? 46 : ((parseInt(adapter.config.latitude, 10) > 55) ? 55 : (parseInt(adapter.config.latitude, 10)))) || 52,
103
- // - oberer Tabellenwert der Latitude
104
- upperLatitude = ((lowerLatitude + 1) > 55) ? 55 : (lowerLatitude + 1);
105
- let currentMonth,
106
- followMonth;
107
-
108
- for(let i = 0; i < 12; i++) {
109
- if (ExtraTerStrTab.Tag[i] > dayNr) {
110
- followMonth = i;
111
- currentMonth = (i === 0) ? 11 : (i - 1);
112
- break;
113
- } else if (i === 11) {
114
- followMonth = 0;
115
- currentMonth = 11;
116
- break;
117
- }
118
- }
119
-
120
- toDayExtraTerStr = trend(
121
- lowerLatitude,
122
- upperLatitude,
123
- trend(ExtraTerStrTab.Tag[currentMonth], ExtraTerStrTab.Tag[followMonth], ExtraTerStrTab[lowerLatitude.toString()][currentMonth], ExtraTerStrTab[lowerLatitude.toString()][followMonth], dayNr),
124
- trend(ExtraTerStrTab.Tag[currentMonth], ExtraTerStrTab.Tag[followMonth], ExtraTerStrTab[upperLatitude.toString()][currentMonth], ExtraTerStrTab[upperLatitude.toString()][followMonth], dayNr),
125
- +adapter.config.latitude
126
- );
127
-
128
- minExtraTerStr = trend(
129
- lowerLatitude,
130
- upperLatitude,
131
- ExtraTerStrTab[lowerLatitude.toString()][11],
132
- ExtraTerStrTab[upperLatitude.toString()][11],
133
- +adapter.config.latitude
134
- );
135
-
136
- maxExtraTerStr = trend(
137
- lowerLatitude,
138
- upperLatitude,
139
- ExtraTerStrTab[lowerLatitude.toString()][5],
140
- ExtraTerStrTab[upperLatitude.toString()][5],
141
- +adapter.config.latitude
142
- );
143
- }
144
-
145
- /**
146
- * evaporation calculation
147
- * => Berechnung der Verdunstung
148
- *
149
- * @param timeDifference
150
- */
151
- function calcEvaporation (timeDifference) {
152
- adapter.log.debug(`calcEvaporation => gestartet TimeDifferenz: ${timeDifference}`);
153
- // Sonnenscheindauer in %
154
- const curSunshineDuration = (curIllumination.val < 100) ? (0) : (curIllumination.val > 7000) ? (1) : ((curIllumination.val - 100) / (6900));
155
-
156
- /**
157
- * Sättigungsdampfdruck 'Es' in hPa
158
- *
159
- */
160
- const m1 = 6.11 * ( 10 ** (( 7.48 * curTemperature.val ) / ( 237 + curTemperature.val )));
161
- /**
162
- * Dampfdruck Ea
163
- *
164
- */
165
- const m2 = m1 * curHumidity.val / 100;
166
- /**
167
- * Globalstrahlung RG
168
- *
169
- */
170
- const m3 = (0.19 + 0.55 * curSunshineDuration) * toDayExtraTerStr;
171
- /**
172
- * Abstrahlung I in W/m²
173
- *
174
- */
175
- const m4 = 5.67E-8 * (( curSunshineDuration + 273 ) ** 4 ) * ( 0.56 - 0.08 * ( m2 ** 0.5 )) * ( 0.1 + ( 0.9 * curSunshineDuration));
176
- /**
177
- * Strahlungsäquivalent EH in mm/d
178
- *
179
- */
180
- const m5 = ( m3 * ( 1 - 0.2 ) - m4 ) / 28.3;
181
- /**
182
- * Steigung der Sättigungsdampfdruckkurve Delta in hPa/K
183
- *
184
- */
185
- const m6 = ( m1 * 4032 ) / (( 237 + curTemperature.val ) ** 2 );
186
- /**
187
- * Windfunktion f(v) in mm/d hPa
188
- *
189
- */
190
- const m7 = 0.13 + 0.14 * curWindSpeed.val / 3.6;
191
- /**
192
- * pot. Evapotranspiration nach Penman ETp in mm/d
193
- *
194
- */
195
- const eTp = (( m6 * m5 + 0.65 * m7 * ( m1 - m2 )) / ( m6 + 0.65 )) - 0.5;
196
-
197
- adapter.setState('evaporation.ETpCurrent', {
198
- val: Math.round(eTp * 10000) / 10000,
199
- ack: true
200
- });
201
-
202
- addEvaporation(eTp * timeDifference);
203
- }
204
-
205
- function addEvaporation (value) {
206
- if (value < 2) { // um Fehler in der Auswertung beim Neustart zu löschen
207
- ETpTodayNum += value;
208
- }
209
- adapter.setState('evaporation.ETpToday', {
210
- val: Math.round(ETpTodayNum * 10000) / 10000,
211
- ack: true
212
- });
213
-
214
- myConfig.applyEvaporation (value);
215
- }
216
-
217
- /*
218
- ----------------------------------------------------------- externe Funktionen -----------------------------------------------------------
219
- */
220
-
221
- /**
222
- * externe Funktionen
223
- *
224
- */
225
- const evaporation = {
226
- /**
227
- * Initialisierung von evaporation
228
- * - Bereitstellen von Umweltdaten
229
- *
230
- * @param myAdapter
231
- */
232
- initEvaporation (myAdapter) {
233
- adapter = myAdapter;
234
- /**
235
- * - Sensors to calculate the evaporation are required
236
- * - Sensoren zur Berechnung der Evaporation werden benötigt
237
- *
238
- * @returns
239
- */
240
- function fCalculationOn () {
241
- const found = myConfig.config.find(d => d.methodControlSM === 'calculation');
242
- return (!(typeof found === 'undefined'));
243
- }
244
- const calculationOn = fCalculationOn();
245
- extraTerStr();
246
- if (adapter.config.sensorOutsideTemperature !== '') {
247
- adapter.subscribeForeignStates(adapter.config.sensorOutsideTemperature);
248
- adapter.getForeignState(adapter.config.sensorOutsideTemperature, (err, state) => {
249
- if (typeof state !== undefined && state != null) {
250
- if (!Number.isNaN(Number.parseFloat(state.val))) {
251
- curTemperature.val = (parseFloat(state.val));
252
- curTemperature.ts = state.ts;
253
- } else {
254
- adapter.log.warn(`sensorOutsideTemperature => Wrong value: ${state.val}, Type: ${typeof state.val}`);
255
- }
256
- }
257
- });
258
- } else if (calculationOn) {
259
- adapter.log.warn('The sensor "sensorOutsideTemperature" is not saved in the configuration! The adapter cannot work like this!');
260
- }
261
-
262
- if (adapter.config.sensorOutsideHumidity !== '') {
263
- adapter.subscribeForeignStates(adapter.config.sensorOutsideHumidity);
264
- adapter.getForeignState(adapter.config.sensorOutsideHumidity, (err, state) => {
265
- if (typeof state !== undefined && state != null) {
266
- if (!Number.isNaN(Number.parseFloat(state.val))) {
267
- curHumidity.val = (parseFloat(state.val));
268
- curHumidity.lc = state.lc;
269
- } else {
270
- adapter.log.warn(`sensorOutsideHumidity => Wrong value: ${state.val}, Type: ${typeof state.val}`);
271
- }
272
- }
273
- });
274
- } else if (calculationOn) {
275
- adapter.log.warn('The sensor "sensorOutsideHumidity" is not saved in the configuration! The adapter cannot work like this!');
276
- }
277
-
278
- if (adapter.config.sensorBrightness !== '') {
279
- adapter.subscribeForeignStates(adapter.config.sensorBrightness);
280
- adapter.getForeignState(adapter.config.sensorBrightness, (err, state) => {
281
- if (typeof state !== undefined && state != null) {
282
- if (!Number.isNaN(Number.parseFloat(state.val))) {
283
- curIllumination.val = (parseFloat(state.val));
284
- curIllumination.lc = state.lc;
285
- } else {
286
- adapter.log.warn(`sensorBrightness => Wrong value: ${ state.val }, Type: ${ typeof state.val}`);
287
- }
288
- }
289
- });
290
- } else if (calculationOn) {
291
- adapter.log.warn('The sensor "sensorBrightness" is not saved in the configuration! The adapter cannot work like this!');
292
- }
293
-
294
- if (adapter.config.sensorWindSpeed !== '') {
295
- adapter.subscribeForeignStates(adapter.config.sensorWindSpeed);
296
- adapter.getForeignState(adapter.config.sensorWindSpeed, (err, state) => {
297
- if (typeof state !== undefined && state != null) {
298
- if (!Number.isNaN(Number.parseFloat(state.val))) {
299
- curWindSpeed.val = (parseFloat(state.val));
300
- curWindSpeed.lc = state.lc;
301
- } else {
302
- adapter.log.warn(`sensorWindSpeed => Wrong value: ${state.val}, Type: ${typeof state.val}`);
303
- }
304
- }
305
- });
306
- } else if (calculationOn) {
307
- adapter.log.warn('The sensor "sensorWindSpeed" is not saved in the configuration! The adapter cannot work like this!');
308
- }
309
-
310
- if (adapter.config.sensorRainfall !== '') {
311
- adapter.subscribeForeignStates(adapter.config.sensorRainfall);
312
- adapter.getForeignState(adapter.config.sensorRainfall, (err, state) => {
313
- if (typeof state !== undefined && state != null) {
314
- if (!Number.isNaN(Number.parseFloat(state.val))) {
315
- lastRainCounter = (parseFloat(state.val));
316
- } else {
317
- adapter.log.warn(`sensorRainfall => Wrong value: ${state.val}, Type: ${typeof state.val}`);
318
- }
319
- }
320
- });
321
- }
322
- },
323
- /**
324
- * aktuelle Temperatur
325
- *
326
- * @param value - aktuelle Temperatur
327
- * @param curTime - aktuelle Zeit der Temperaturerfassung
328
- */
329
- setCurTemperature (value, curTime) {
330
- curTemperature.val = value;
331
- curTemperature.ts = curTime;
332
-
333
- /**
334
- * Abbruch bei inkorrekten Umweltdaten
335
- *
336
- */
337
- let abbruch = false;
338
- if((curTemperature.val < -20) && (curTemperature.val > 55)){
339
- adapter.log.warn('Temperature outside the range of -20 ... 55 [°C]'); abbruch = true;
340
- }
341
- if((curHumidity.val < 1) && (curHumidity.val > 99)) {
342
- adapter.log.warn('Humidity outside the range of 1 ... 99 [%]'); abbruch = true;
343
- }
344
- if((curIllumination.val < 0) && (curIllumination.val > 100000)) {
345
- adapter.log.warn('Brightness out of range von 0 ... 100.000'); abbruch = true;
346
- }
347
- if((curWindSpeed.val < 0) && (curWindSpeed.val > 200)) {
348
- adapter.log.warn('Wind speed outside the range of 0 ... 200 km/h'); abbruch = true;
349
- }
350
- if (abbruch) {
351
- return;
352
- }
353
-
354
- /**
355
- * Zeitdifferenz in ms
356
- */
357
- // @ts-ignore
358
- const timeDifference = (curTime - lastChangeEvaPor) / 86400000; // 1Tag === 24/h * 60/min * 60/s * 1000/ms === 86400000 ms
359
- adapter.log.debug(`ts: ${curTime} - lastChangeEvaPor: ${lastChangeEvaPor} = timeDifference: ${timeDifference}`);
360
-
361
- if (timeDifference) {
362
- setTimeout(() => {
363
- calcEvaporation(timeDifference);
364
- }, 100);
365
- }
366
- lastChangeEvaPor = curTime;
367
- },
368
- /**
369
- * akt. LuftFeuchtigkeit in %
370
- *
371
- * @param value
372
- * @param lc
373
- */
374
- setCurHumidity (value, lc) {
375
- curHumidity.val = value;
376
- curHumidity.lc =lc;
377
- },
378
- /**
379
- * akt. Helligkeit wird auf 0 bis 7000 begrenzt
380
- *
381
- * @param value
382
- * @param lc
383
- */
384
- setCurIllumination (value, lc) {
385
- curIllumination.val = value;
386
- curIllumination.lc = lc;
387
- },
388
- /**
389
- * akt. Windgeschwindigkeit
390
- *
391
- * @param value Windgeschwindigkeit in km/h
392
- * @param lc
393
- */
394
- setCurWindSpeed (value, lc) {
395
- curWindSpeed.val = value;
396
- curWindSpeed.lc = lc;
397
- },
398
- /**
399
- * akt. Regenmengenzähler
400
- * Bei einer Änderung über 20 mm wird der Wert nur intern gespeichert,
401
- * es findet aber keine Anwendung statt!
402
- *
403
- * @param value current rain counter → aktueller Regencontainer in mm
404
- */
405
- setCurAmountOfRain (value) {
406
- if ((value > lastRainCounter) // es regnet
407
- && ((value - lastRainCounter) < 20) // && Plausibilitätskontrolle (Regenmenge unter 10mm)
408
- ) {
409
- addEvaporation(lastRainCounter - value);
410
- }
411
- lastRainCounter = value;
412
- adapter.log.debug(`lastRainCounter: ${lastRainCounter} curAmountOfRain: ${(lastRainCounter - value)} state.val: ${value}`);
413
- },
414
- /**
415
- * Summe der heutigen Verdunstung
416
- *
417
- * @param value
418
- */
419
- setETpTodayNum (value) {
420
- ETpTodayNum = value;
421
- },
422
- /**
423
- * ETpToday und ETpYesterday in evaporation aktualisieren da ein neuer Tag beginnt
424
- */
425
- setNewDay () {
426
- extraTerStr();
427
- setTimeout(() => {
428
- adapter.setState('evaporation.ETpYesterday', {
429
- val: Math.round(ETpTodayNum * 10000) / 10000,
430
- ack: true
431
- });
432
- ETpTodayNum = 0;
433
- adapter.setState('evaporation.ETpToday', {
434
- val: 0,
435
- ack: true
436
- });
437
- }, 100);
438
- },
439
- /**
440
- *
441
- * @param maxExtension - Wert aus der Konfiguration (wateringAdd 100...300%) des Bewässerungskreises
442
- * @returns - Erweiterung/Multiplikator (1...3) der Bewässerungszeit
443
- */
444
- timeExtension (maxExtension) {
445
- return trend(minExtraTerStr, maxExtraTerStr,1, maxExtension / 100, toDayExtraTerStr);
446
- },
447
- /**Output of the current evaporation =>
448
- * Ausgabe der aktuellen Verdunstung
449
- * @returns {number}
450
- */
451
- getETpTodayNum () {
452
- return ETpTodayNum;
453
- }
454
- };
455
-
1
+ 'use strict';
2
+ /*
3
+ info: log aufbau evaporation.js: #3.*
4
+ */
5
+ const myConfig = require('./myConfig.js'); // myConfig → Speichern und abrufen von Konfigurationsdaten der Ventile
6
+ const formatTime = require('./tools').formatTime; // tools => laden von Hilfsfunktionen
7
+ const trend = require('./tools').trend; // tools => laden von Hilfsfunktionen
8
+
9
+ let adapter;
10
+
11
+ /* calcEvaporation */
12
+ /**
13
+ * akt. Temperatur °C
14
+ * - -20 bis 55°C
15
+ * - ts Zeitstempel, wann der Wert aktualisiert wurde (auch ohne Wertänderung)
16
+ */
17
+ const curTemperature = {val: undefined, ts: undefined},
18
+ /**
19
+ * akt. LuftFeuchtigkeit in %
20
+ * - 1 bis 99%
21
+ * - lc: Zeitstempel, wann der Wert geändert wurde
22
+ */
23
+ curHumidity = {val: undefined, lc: undefined},
24
+ /**
25
+ * akt. Helligkeit (relativ)
26
+ * - 0 bis 100000
27
+ * - intern Begrenzung 100...7000
28
+ * - lc: Zeitstempel, wann der Wert geändert wurde
29
+ */
30
+ curIllumination = {val: undefined, lc: undefined},
31
+ /**
32
+ * akt. WindGeschwindigkeit in km/h
33
+ * - 0 bis 200 km/h
34
+ * - lc: Zeitstempel, wann der Wert geändert wurde
35
+ */
36
+ curWindSpeed = {val: undefined, lc: undefined};
37
+ /**
38
+ * max. Temperatur des Tages (für Auswertung der zusätzlichen Bewässerung
39
+ */
40
+ let curTemperatureMax = 0,
41
+ /**
42
+ * last rain container => letzter Regencontainer in mm
43
+ */
44
+ lastRainCounter = 0,
45
+ /**
46
+ * letzte Aktualisierungszeit des Temperaturwertes
47
+ */
48
+ lastChangeEvaPor = new Date();
49
+
50
+ let ETpTodayNum = 0,
51
+
52
+ /**
53
+ * Extraterrestrische Tagesstrahlung in W/m²
54
+ * - berechneter tabellarischer Tageswert
55
+ */
56
+ toDayExtraTerStr,
57
+ /**
58
+ * kleinste extraterrestrische Tagesstrahlung im Jahr in W/m²
59
+ * - berechneter tabellarischer Mindestwert
60
+ */
61
+ minExtraTerStr,
62
+ /**
63
+ * größter extraterrestrische Tagesstrahlung im Jahr in W/m²
64
+ * - berechneter tabellarischer Maximalwert
65
+ */
66
+ maxExtraTerStr;
67
+
68
+ /**
69
+ * Extraterrestrische Strahlung (kurzwelliger Strahlungseinfluss von der Sonne an der Obergrenze der Erdatmosphäre) in W/m²
70
+ * als Tagesmittel, Nordhalbkugel (IQBAL. 1983)
71
+ */
72
+ const ExtraTerStrTab = {
73
+ Tag:[ 21, 52, 80, 111, 141, 172, 202, 233, 264, 294, 325, 355],
74
+ 46: [135, 198, 289, 382, 452, 483, 467, 409, 324, 230, 153, 117],
75
+ 47: [128, 191, 283, 378, 450, 482, 466, 406, 319, 224, 146, 110],
76
+ 48: [121, 184, 277, 375, 449, 482, 465, 403, 314, 217, 139, 103],
77
+ 49: [114, 177, 271, 371, 447, 481, 464, 400, 309, 211, 132, 96],
78
+ 50: [107, 170, 265, 367, 445, 481, 463, 398, 304, 204, 125, 89],
79
+ 51: [100, 163, 259, 363, 443, 480, 462, 394, 298, 197, 118, 83],
80
+ 52: [ 93, 156, 253, 358, 441, 480, 461, 391, 293, 191, 111, 76],
81
+ 53: [ 86, 149, 247, 354, 439, 479, 459, 388, 287, 184, 104, 70],
82
+ 54: [ 79, 142, 240, 350, 437, 478, 458, 384, 282, 177, 97, 63],
83
+ 55: [ 73, 135, 234, 345, 435, 478, 457, 381, 276, 170, 90, 56]
84
+ };
85
+
86
+ /*----------------------------------------------------------- interne Funktionen -----------------------------------------------------------*/
87
+
88
+ /**
89
+ * Ermittlung der heutigen extraterrestrischen Strahlung
90
+ * anhand der Tabelle "ExtraTerStrTab"
91
+ */
92
+ function extraTerStr () { // latitude Breitengrad
93
+ const dayNr = formatTime().dayNr;
94
+ /**
95
+ * - unterer Tabellenwert der Latitude
96
+ */
97
+ const lowerLatitude = ((parseInt(adapter.config.latitude, 10) < 46 ) ? 46 : ((parseInt(adapter.config.latitude, 10) > 55) ? 55 : (parseInt(adapter.config.latitude, 10)))) || 52,
98
+ /**
99
+ * - oberer Tabellenwert der Latitude
100
+ */
101
+ upperLatitude = ((lowerLatitude + 1) > 55) ? 55 : (lowerLatitude + 1);
102
+
103
+ let currentMonth = 0,
104
+ followMonth = 0;
105
+
106
+ for(let i = 0; i < 12; i++) {
107
+ if (ExtraTerStrTab.Tag[i] > dayNr) {
108
+ followMonth = i;
109
+ currentMonth = (i === 0) ? 11 : (i - 1);
110
+ break;
111
+ } else if (i === 11) {
112
+ followMonth = 0;
113
+ currentMonth = 11;
114
+ break;
115
+ }
116
+ }
117
+
118
+ toDayExtraTerStr = trend(
119
+ lowerLatitude,
120
+ upperLatitude,
121
+ trend(ExtraTerStrTab.Tag[currentMonth], ExtraTerStrTab.Tag[followMonth], ExtraTerStrTab[lowerLatitude.toString()][currentMonth], ExtraTerStrTab[lowerLatitude.toString()][followMonth], dayNr),
122
+ trend(ExtraTerStrTab.Tag[currentMonth], ExtraTerStrTab.Tag[followMonth], ExtraTerStrTab[upperLatitude.toString()][currentMonth], ExtraTerStrTab[upperLatitude.toString()][followMonth], dayNr),
123
+ +adapter.config.latitude
124
+ );
125
+
126
+ minExtraTerStr = trend(
127
+ lowerLatitude,
128
+ upperLatitude,
129
+ ExtraTerStrTab[lowerLatitude.toString()][11], //alter Wert 11
130
+ ExtraTerStrTab[upperLatitude.toString()][11], //alter Wert 11
131
+ +adapter.config.latitude
132
+ );
133
+
134
+ maxExtraTerStr = trend(
135
+ lowerLatitude,
136
+ upperLatitude,
137
+ ExtraTerStrTab[lowerLatitude.toString()][5],
138
+ ExtraTerStrTab[upperLatitude.toString()][5],
139
+ +adapter.config.latitude
140
+ );
141
+ }
142
+
143
+ /**
144
+ * evaporation calculation
145
+ * => Berechnung der Verdunstung
146
+ *
147
+ * @param {number} timeDifference
148
+ */
149
+ function calcEvaporation (timeDifference) {
150
+ if (!Number.isFinite(curIllumination.val) || !Number.isFinite(curTemperature.val) || !Number.isFinite(curHumidity.val) || !Number.isFinite(curWindSpeed.val)) {
151
+ adapter.log.warn(`calcEvaporation => berechnung nicht möglich! Es fehlen Werte. ( ${curTemperature.val} °C | ${curIllumination.val} | ${curHumidity.val} % | ${curWindSpeed.val} km/h )`);
152
+ return;
153
+ }
154
+ adapter.log.debug(`calcEvaporation => gestartet TimeDifferenz: ${timeDifference}`);
155
+ // Sonnenscheindauer in %
156
+ const curSunshineDuration = (curIllumination.val < 100) ? (0) : (curIllumination.val > 7000) ? (1) : ((curIllumination.val - 100) / (6900));
157
+
158
+ /**
159
+ * Sättigungsdampfdruck 'Es' in hPa
160
+ * m1
161
+ */
162
+ const m1 = 6.11 * ( 10 ** (( 7.48 * curTemperature.val ) / ( 237 + curTemperature.val )));
163
+ /**
164
+ * Dampfdruck Ea
165
+ * m2
166
+ */
167
+ const m2 = m1 * curHumidity.val / 100;
168
+ /**
169
+ * Globalstrahlung RG
170
+ * m3
171
+ */
172
+ const m3 = (0.19 + 0.55 * curSunshineDuration) * toDayExtraTerStr;
173
+ /**
174
+ * Abstrahlung I in W/m²
175
+ * m4
176
+ */
177
+ const m4 = 5.67E-8 * (( curSunshineDuration + 273 ) ** 4 ) * ( 0.56 - 0.08 * ( m2 ** 0.5 )) * ( 0.1 + ( 0.9 * curSunshineDuration));
178
+ /**
179
+ * Strahlungsäquivalent EH in mm/d
180
+ * m5
181
+ */
182
+ const m5 = ( m3 * ( 1 - 0.2 ) - m4 ) / 28.3;
183
+ /**
184
+ * Steigung der Sättigungsdampfdruckkurve Delta in hPa/K
185
+ * m6
186
+ */
187
+ const m6 = ( m1 * 4032 ) / (( 237 + curTemperature.val ) ** 2 );
188
+ /**
189
+ * Windfunktion f(v) in mm/d hPa
190
+ * m7
191
+ */
192
+ const m7 = 0.13 + 0.14 * curWindSpeed.val / 3.6;
193
+ /**
194
+ * pot. Evapotranspiration nach Penman ETp in mm/d
195
+ * eTp
196
+ */
197
+ const eTp = (( m6 * m5 + 0.65 * m7 * ( m1 - m2 )) / ( m6 + 0.65 )) - 0.5;
198
+
199
+ adapter.setState('evaporation.ETpCurrent', { val: Math.round(eTp * 10000) / 10000, ack: true });
200
+
201
+ addEvaporation(eTp * timeDifference);
202
+ }
203
+
204
+ function addEvaporation (value) {
205
+ if (value < 2) { // um Fehler in der Auswertung beim Neustart zu löschen
206
+ ETpTodayNum += value;
207
+ }
208
+ adapter.setState('evaporation.ETpToday', { val: Math.round(ETpTodayNum * 10000) / 10000, ack: true });
209
+
210
+ myConfig.applyEvaporation (value);
211
+ }
212
+
213
+ /*
214
+ ----------------------------------------------------------- externe Funktionen -----------------------------------------------------------
215
+ */
216
+
217
+ const evaporation = {
218
+ /**
219
+ * Initialisierung von evaporation
220
+ * - Bereitstellen von Umweltdaten
221
+ *
222
+ * @param {ioBroker.Adapter} myAdapter
223
+ */
224
+ initEvaporation (myAdapter) {
225
+ adapter = myAdapter;
226
+ /**
227
+ * - Sensors to calculate the evaporation are required
228
+ * - Sensoren zur Berechnung der Evaporation werden benötigt
229
+ *
230
+ * @returns {boolean}
231
+ */
232
+ function fCalculationOn () {
233
+ const found = myConfig.config.find(d => d.methodControlSM === 'calculation');
234
+ return (!(typeof found === 'undefined'));
235
+ }
236
+ const calculationOn = fCalculationOn();
237
+ extraTerStr();
238
+ if (adapter.config.sensorOutsideTemperature !== '') {
239
+ adapter.subscribeForeignStates(adapter.config.sensorOutsideTemperature);
240
+ adapter.getForeignState(adapter.config.sensorOutsideTemperature, (err, state) => {
241
+ if (state && state.val) {
242
+ // @ts-ignore
243
+ if (!Number.isNaN(Number.parseFloat(state.val))) {
244
+ // @ts-ignore
245
+ curTemperature.val = (parseFloat(state.val));
246
+ // @ts-ignore
247
+ curTemperature.ts = state.ts;
248
+ } else {
249
+ adapter.log.warn(`sensorOutsideTemperature => Wrong value: ${state.val}, Type: ${typeof state.val}`);
250
+ }
251
+ }
252
+ });
253
+ } else if (calculationOn) {
254
+ adapter.log.warn('The sensor "sensorOutsideTemperature" is not saved in the configuration! The adapter cannot work like this!');
255
+ }
256
+
257
+ if (adapter.config.sensorOutsideHumidity !== '') {
258
+ adapter.subscribeForeignStates(adapter.config.sensorOutsideHumidity);
259
+ adapter.getForeignState(adapter.config.sensorOutsideHumidity, (err, state) => {
260
+ if (state && state.val) {
261
+ // @ts-ignore
262
+ if (!Number.isNaN(Number.parseFloat(state.val))) {
263
+ // @ts-ignore
264
+ curHumidity.val = (parseFloat(state.val));
265
+ // @ts-ignore
266
+ curHumidity.lc = state.lc;
267
+ } else {
268
+ adapter.log.warn(`sensorOutsideHumidity => Wrong value: ${state.val}, Type: ${typeof state.val}`);
269
+ }
270
+ }
271
+ });
272
+ } else if (calculationOn) {
273
+ adapter.log.warn('The sensor "sensorOutsideHumidity" is not saved in the configuration! The adapter cannot work like this!');
274
+ }
275
+
276
+ if (adapter.config.sensorBrightness !== '') {
277
+ adapter.subscribeForeignStates(adapter.config.sensorBrightness);
278
+ adapter.getForeignState(adapter.config.sensorBrightness, (err, state) => {
279
+ if (state && state.val) {
280
+ // @ts-ignore
281
+ if (!Number.isNaN(Number.parseFloat(state.val))) {
282
+ // @ts-ignore
283
+ curIllumination.val = (parseFloat(state.val));
284
+ // @ts-ignore
285
+ curIllumination.lc = state.lc;
286
+ } else {
287
+ adapter.log.warn(`sensorBrightness => Wrong value: ${ state.val }, Type: ${ typeof state.val }`);
288
+ }
289
+ }
290
+ });
291
+ } else if (calculationOn) {
292
+ adapter.log.warn('The sensor "sensorBrightness" is not saved in the configuration! The adapter cannot work like this!');
293
+ }
294
+
295
+ if (adapter.config.sensorWindSpeed !== '') {
296
+ adapter.subscribeForeignStates(adapter.config.sensorWindSpeed);
297
+ adapter.getForeignState(adapter.config.sensorWindSpeed, (err, state) => {
298
+ if (state && state.val) {
299
+ // @ts-ignore
300
+ if (!Number.isNaN(Number.parseFloat(state.val))) {
301
+ // @ts-ignore
302
+ curWindSpeed.val = (parseFloat(state.val));
303
+ // @ts-ignore
304
+ curWindSpeed.lc = state.lc;
305
+ } else {
306
+ adapter.log.warn(`sensorWindSpeed => Wrong value: ${state.val}, Type: ${typeof state.val}`);
307
+ }
308
+ }
309
+ });
310
+ } else if (calculationOn) {
311
+ adapter.log.warn('The sensor "sensorWindSpeed" is not saved in the configuration! The adapter cannot work like this!');
312
+ }
313
+
314
+ if (adapter.config.sensorRainfall !== '') {
315
+ adapter.subscribeForeignStates(adapter.config.sensorRainfall);
316
+ adapter.getForeignState(adapter.config.sensorRainfall, (err, state) => {
317
+ if (state && state.val) {
318
+ // @ts-ignore
319
+ if (!Number.isNaN(Number.parseFloat(state.val))) {
320
+ // @ts-ignore
321
+ lastRainCounter = (parseFloat(state.val));
322
+ } else {
323
+ adapter.log.warn(`sensorRainfall => Wrong value: ${state.val}, Type: ${typeof state.val}`);
324
+ }
325
+ }
326
+ });
327
+ }
328
+ },
329
+
330
+ /**
331
+ * akt. Temperatur
332
+ *
333
+ * @param {number} value curTemperature
334
+ * @param {Date} curTime ts (akt. Zeit)
335
+ */
336
+ setCurTemperature (value, curTime) {
337
+ curTemperature.val = value;
338
+ curTemperature.ts = curTime;
339
+ if (curTemperature.val > curTemperatureMax) {
340
+ curTemperatureMax = curTemperature.val;
341
+ adapter.setState('evaporation.dailyHighTemp', {
342
+ val: curTemperatureMax,
343
+ ack: true
344
+ });
345
+ }
346
+
347
+ /**
348
+ * Abbruch bei inkorrekten Umweltdaten
349
+ */
350
+ let abbruch = false;
351
+ if((curTemperature.val < -20) || (curTemperature.val > 55)){
352
+ adapter.log.warn('Temperature outside the range of -20 ... 55 [°C]');
353
+ abbruch = true;
354
+ }
355
+ if(curHumidity.val && (curHumidity.val < 1) || (curHumidity.val > 99)) {
356
+ adapter.log.warn('Humidity outside the range of 1 ... 99 [%]');
357
+ abbruch = true;
358
+ }
359
+ if(curIllumination.val && (curIllumination.val < 0) || (curIllumination.val > 100000)) {
360
+ adapter.log.warn('Brightness out of range von 0 ... 100.000');
361
+ abbruch = true;
362
+ }
363
+ if(curWindSpeed.val && (curWindSpeed.val < 0) || (+curWindSpeed > 200)) {
364
+ adapter.log.warn('Wind speed outside the range of 0 ... 200 km/h');
365
+ abbruch = true;
366
+ }
367
+ if (abbruch) {
368
+ return;
369
+ }
370
+
371
+ /**
372
+ * Zeitdifferenz in ms
373
+ */
374
+ const timeDifference = (+curTime - +lastChangeEvaPor) / 86400000; // 1Tag === 24/h * 60/min * 60/s * 1000/ms === 86400000 ms
375
+ adapter.log.debug(`${curTemperature.val}°C | ${curHumidity.val}% | ${curIllumination.val} | ${curWindSpeed.val}km/h | ts: ${curTime} - lastChangeEvaPor: ${lastChangeEvaPor} = timeDifference: ${timeDifference}`);
376
+
377
+ if (timeDifference) {
378
+ setTimeout(() => {
379
+ calcEvaporation(timeDifference);
380
+ }, 100);
381
+ }
382
+ lastChangeEvaPor = curTime;
383
+ },
384
+ /**
385
+ * akt. LuftFeuchtigkeit in %
386
+ *
387
+ * @param {number} value
388
+ * @param {any} lc
389
+ */
390
+ setCurHumidity (value, lc) {
391
+ curHumidity.val = value;
392
+ curHumidity.lc =lc;
393
+ },
394
+ /**
395
+ * akt. Helligkeit wird auf 0 bis 7000 begrenzt
396
+ *
397
+ * @param {number} value
398
+ * @param {any} lc
399
+ */
400
+ setCurIllumination (value, lc) {
401
+ curIllumination.val = value;
402
+ curIllumination.lc = lc;
403
+ },
404
+ /**
405
+ * akt. Windgeschwindigkeit
406
+ *
407
+ * @param {number} value Windgeschwindigkeit in km/h
408
+ * @param {any} lc
409
+ */
410
+ setCurWindSpeed (value, lc) {
411
+ curWindSpeed.val = value;
412
+ curWindSpeed.lc = lc;
413
+ },
414
+ /**
415
+ * akt. Regenmengenzähler
416
+ * → Bei einer Änderung über 20 mm wird der Wert nur intern gespeichert,
417
+ * es findet aber keine Anwendung statt!
418
+ *
419
+ * @param {number} value current rain counter → aktueller Regencontainer in mm
420
+ */
421
+ setCurAmountOfRain (value) {
422
+ if ((value > lastRainCounter) // es regnet
423
+ && ((value - lastRainCounter) < 20) // && Plausibilitätskontrolle (Regenmenge unter 10mm)
424
+ ) {
425
+ addEvaporation(lastRainCounter - value);
426
+ }
427
+ lastRainCounter = value;
428
+ adapter.log.debug(`lastRainCounter: ${lastRainCounter} curAmountOfRain: ${(lastRainCounter - value)} state.val: ${value}`);
429
+ },
430
+ /**
431
+ * Summe der heutigen Verdunstung
432
+ *
433
+ * @param {number} value
434
+ */
435
+ setETpTodayNum (value) {
436
+ ETpTodayNum = value;
437
+ },
438
+ /**
439
+ * Tageshöchstwert der Temperatur (für Auswertung der zusätzlichen Bewässerung)
440
+ *
441
+ * @param {number} value
442
+ */
443
+ setCurTemperatureMax (value) {
444
+ curTemperatureMax = value;
445
+ },
446
+ /**
447
+ * ETpToday und ETpYesterday in evaporation aktualisieren da ein neuer Tag beginnt
448
+ */
449
+ setNewDay () {
450
+ extraTerStr();
451
+ setTimeout(() => {
452
+ adapter.setState('evaporation.ETpYesterday', {
453
+ val: Math.round(ETpTodayNum * 10000) / 10000,
454
+ ack: true
455
+ });
456
+ ETpTodayNum = 0;
457
+ adapter.setState('evaporation.ETpToday', {
458
+ val: ETpTodayNum,
459
+ ack: true
460
+ });
461
+ curTemperatureMax = 0;
462
+ adapter.setState('evaporation.dailyHighTemp', {
463
+ val: curTemperatureMax,
464
+ ack: true
465
+ });
466
+ }, 100);
467
+ },
468
+ /**
469
+ *
470
+ * @param {number} maxExtension - Wert aus der Konfiguration (wateringAdd 100...300%) des Bewässerungskreises
471
+ * @returns {number} - Erweiterung/Multiplikator (1...3) der Bewässerungszeit
472
+ */
473
+ timeExtension (maxExtension) {
474
+ if (ETpTodayNum < 136) { // 16. Mai
475
+ return 1;
476
+ }else if (ETpTodayNum < 171) { // 20. Juni
477
+ return trend(136, 170,1, maxExtension / 100, ETpTodayNum);
478
+ } else if (ETpTodayNum < 186) { // 5. Juli
479
+ return maxExtension / 100;
480
+ }else if (ETpTodayNum < 241) { // 29. August
481
+ return trend(186, 240,maxExtension / 100, 1, ETpTodayNum);
482
+ }else {
483
+ return 1;
484
+ }
485
+ },
486
+ /**Output of the current evaporation =>
487
+ * Ausgabe der aktuellen Verdunstung
488
+ * @returns {number}
489
+ */
490
+ getETpTodayNum () {
491
+ return ETpTodayNum;
492
+ },
493
+ getCurTemperatureMax () {
494
+ return curTemperatureMax;
495
+ }
496
+ };
497
+
456
498
  module.exports = evaporation;