iobroker.sprinklecontrol 0.2.12 → 0.2.14

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