iobroker.sprinklecontrol 0.2.19 → 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.
- package/LICENSE +1 -1
- package/README.md +8 -6
- package/admin/i18n/de/translations.json +13 -4
- package/admin/i18n/en/translations.json +12 -3
- package/admin/i18n/es/translations.json +13 -4
- package/admin/i18n/fr/translations.json +13 -4
- package/admin/i18n/it/translations.json +13 -4
- package/admin/i18n/nl/translations.json +13 -4
- package/admin/i18n/pl/translations.json +13 -4
- package/admin/i18n/pt/translations.json +13 -4
- package/admin/i18n/ru/translations.json +13 -4
- package/admin/i18n/uk/translations.json +13 -4
- package/admin/i18n/zh-cn/translations.json +13 -4
- package/admin/index_m.html +941 -919
- package/admin/index_m.js +807 -779
- package/admin/words.js +12 -3
- package/io-package.json +218 -174
- package/lib/evaporation.js +497 -455
- package/lib/myConfig.js +190 -266
- package/lib/sendMessageText.js +196 -162
- package/lib/tools.js +211 -148
- package/lib/valveControl.js +1414 -978
- package/main.js +1416 -1245
- package/package.json +9 -14
package/lib/valveControl.js
CHANGED
|
@@ -1,978 +1,1414 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
*
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
let
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* @param
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
&& (
|
|
294
|
-
||
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
entry.
|
|
320
|
-
entry.
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
)
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
});
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
if (
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1
|
+
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const asyncTime = require('timers/promises');
|
|
5
|
+
// import {setTimeout} from 'timers/promises';
|
|
6
|
+
|
|
7
|
+
const myConfig = require('./myConfig.js');
|
|
8
|
+
//const sleep = require('./tools.js').sleep;
|
|
9
|
+
const addTime = require('./tools.js').addTime;
|
|
10
|
+
const formatTime = require('./tools').formatTime;
|
|
11
|
+
const findAsync = require('./tools.js').findAsync;
|
|
12
|
+
const sendMessageText = require('./sendMessageText.js'); // sendMessageText
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The adapter instance
|
|
16
|
+
*/
|
|
17
|
+
let adapter;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Thread-list
|
|
21
|
+
* → Auflistung aller aktiver Sprenger-Kreise
|
|
22
|
+
*/
|
|
23
|
+
const threadList = [];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* - bereit zum Boost (true: kein Boostventil aktive; false: BoostVentil aktive)
|
|
27
|
+
*/
|
|
28
|
+
let boostReady = true,
|
|
29
|
+
/**
|
|
30
|
+
* - Boost aktive
|
|
31
|
+
*/
|
|
32
|
+
boostOn = false,
|
|
33
|
+
/**
|
|
34
|
+
* maximal zulässige Anzahl der eingeschalteten Ventile
|
|
35
|
+
*/
|
|
36
|
+
maxParallel = 0,
|
|
37
|
+
/* Control of the cistern pump */
|
|
38
|
+
/**
|
|
39
|
+
* Füllstand der Zisterne
|
|
40
|
+
*/
|
|
41
|
+
fillLevelCistern = 0;
|
|
42
|
+
const updateListMarker = {funcActive: false, newStart: false, switchingDistance: 5000, cancelSwitchingDistance: {}};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* aktive Pumpendaten
|
|
46
|
+
* - enable: Pumpe ein/ausgeschaltet
|
|
47
|
+
* - name: Bezeichnung der Pumpe
|
|
48
|
+
* - idState: Objektname des State
|
|
49
|
+
* - id: ID des States unter Objecte im ioBroker info.cisternPump || info.mainPump
|
|
50
|
+
* - intBreak: Pause (Zisterne leer)
|
|
51
|
+
* - pumpCistern: ZisternenPumpe aktiv bei Verwendung zweier Pumpen
|
|
52
|
+
* - leadTime: Vorlaufzeit
|
|
53
|
+
* - cancelLeadTime: Vorlaufzeit abbrechen
|
|
54
|
+
* - pumpPower: Maximalleistung der Pumpe
|
|
55
|
+
* - restFlow: aktuelle LeistungsReserve der Pumpe
|
|
56
|
+
* - controller: Rückmeldung ack
|
|
57
|
+
* - ac: AbortController
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
const currentPumpUse = {enable: false, name: '', idState: '', id: '', pumpCistern: false, intBreak: false, leadTime: 0, cancelLeadTime: {}, pumpPower: 0, restFlow: 0,ac: {},controller: {}};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Steuerspannung 24V
|
|
64
|
+
* - enable: 24V ein/ausgeschaltet
|
|
65
|
+
* - name: Bezeichnung 24V
|
|
66
|
+
* - idState: Aktorerkennung "hm-rpc.0.MEQ1810129.1.STATE"
|
|
67
|
+
* - controller: controlle von Zeiten und Abbruchsignalen
|
|
68
|
+
*/
|
|
69
|
+
const controlVoltage ={enable: false, name: '24V', idState: undefined, ac: {}, controller: {}};
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Schaltabstand in ms
|
|
73
|
+
* - Schaltabstand zwischen den Ventilen
|
|
74
|
+
* - 250 ms - 240 000 ms (4 min)
|
|
75
|
+
*/
|
|
76
|
+
let switchingDistanceMS = 250;
|
|
77
|
+
/*==============================================================================================================================================*/
|
|
78
|
+
/* interne Funktionen */
|
|
79
|
+
/*----------------------------------------------------------------------------------------------------------------------------------------------*/
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Schalten der Ventile
|
|
83
|
+
*
|
|
84
|
+
* @param {object} thread -Objekt des Ventils
|
|
85
|
+
* @param {boolean} val - neuer Zustand des Ventils
|
|
86
|
+
* @returns {Promise<string|undefined>}
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
const setValve = async (thread, val) => {
|
|
90
|
+
|
|
91
|
+
const startTime = new Date();
|
|
92
|
+
let result = undefined;
|
|
93
|
+
|
|
94
|
+
thread.ac.acSetValveCancelTimeout = new AbortController;
|
|
95
|
+
/**
|
|
96
|
+
* Sprinkle geschaltet
|
|
97
|
+
*
|
|
98
|
+
* @param {{val:boolean,ack:boolean}} state
|
|
99
|
+
*/
|
|
100
|
+
thread.controller.ackTrue = (state) => {
|
|
101
|
+
if (typeof state.val === 'boolean'
|
|
102
|
+
&& state.val === val
|
|
103
|
+
&& state.ack === true
|
|
104
|
+
) {
|
|
105
|
+
adapter.log.debug(`setValve ${thread.name} => ackTrue`);
|
|
106
|
+
result = thread.idState;
|
|
107
|
+
thread.enable = val;
|
|
108
|
+
thread.ac.acSetValveCancelTimeout.abort();
|
|
109
|
+
} else {
|
|
110
|
+
adapter.log.warn(`setValve ${thread.name} => ackTrue val = ${val} state: ${JSON.stringify(state)}`);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
//adapter.log.info(`Set Valve (async () => {...}`);
|
|
115
|
+
try {
|
|
116
|
+
// Ventil ansteuern
|
|
117
|
+
const _setValve = await adapter.setForeignStateAsync(thread.idState, {
|
|
118
|
+
val: val,
|
|
119
|
+
ack: false
|
|
120
|
+
});
|
|
121
|
+
if (_setValve === thread.idState) { // Auftrag ausgeführt
|
|
122
|
+
await asyncTime.setTimeout(10000, undefined, { signal: thread.ac.acSetValveCancelTimeout.signal });
|
|
123
|
+
const _getValve = await adapter.getForeignStateAsync(thread.idState);
|
|
124
|
+
if (_getValve && typeof _getValve.val === 'boolean'
|
|
125
|
+
&& _getValve.val === val
|
|
126
|
+
&& _getValve.ack === true
|
|
127
|
+
) {
|
|
128
|
+
thread.enable = val;
|
|
129
|
+
return thread.idState;
|
|
130
|
+
} else {
|
|
131
|
+
adapter.log.debug(`setValve ${thread.name} _getValve: ${_getValve}`);
|
|
132
|
+
throw new Error(`setForeignState not responding (ack === false)`);
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
throw new Error(`set Valve was not switched`);
|
|
136
|
+
}
|
|
137
|
+
} catch (error) {
|
|
138
|
+
// thread.controller.ackTrue wurde ausgelöst
|
|
139
|
+
if (error.name !== `AbortError`) {
|
|
140
|
+
await adapter.setForeignStateAsync(thread.idState, {
|
|
141
|
+
val: false,
|
|
142
|
+
ack: false
|
|
143
|
+
});
|
|
144
|
+
thread.enable = false;
|
|
145
|
+
if (adapter.config.notificationEnabled) {
|
|
146
|
+
sendMessageText.sendMessage(`setValve ${thread.name} (${thread.idState}) ${error}`);
|
|
147
|
+
}
|
|
148
|
+
throw new Error(`set Valve (${thread.idState}) ${error}`);
|
|
149
|
+
}
|
|
150
|
+
} finally {
|
|
151
|
+
if (thread.ac.acSetValveCancelTimeout.aborted === false) thread.ac.acSetValveCancelTimeout.abort();
|
|
152
|
+
adapter.log.info(`setValve ${thread.name}: ${val}, ${thread.wateringTime > 0 && val === true ? `${ addTime(thread.wateringTime,'') }, ` : ''}processing time: ${(+new Date()) - +startTime}ms`);
|
|
153
|
+
}
|
|
154
|
+
adapter.setStateAsync(`sprinkle.${thread.name}.sprinklerState`, {
|
|
155
|
+
val: thread.state,
|
|
156
|
+
ack: true
|
|
157
|
+
});
|
|
158
|
+
if (thread.name !== 'Cistern pump' && thread.name !== 'Main pump' && thread.name !== '24V' && thread.name !== 'no Pump') {
|
|
159
|
+
adapter.setStateAsync(`sprinkle.${thread.name}.valveOn`, {
|
|
160
|
+
val: thread.enable,
|
|
161
|
+
ack: true
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
return result;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Sprinkle (name) delete
|
|
169
|
+
* → Ventil (name) löschen
|
|
170
|
+
*
|
|
171
|
+
* @param {Array.<{name: string}>} killList
|
|
172
|
+
* @returns {Promise}
|
|
173
|
+
*/
|
|
174
|
+
const delList = async (killList) => {
|
|
175
|
+
new Promise((resolve, reject) => {
|
|
176
|
+
const badList = [];
|
|
177
|
+
for (const name of killList) {
|
|
178
|
+
let bValveFound = false; // Ventil gefunden
|
|
179
|
+
for (let counter = 0, // Loop über das Array
|
|
180
|
+
lastArray = (threadList.length - 1); // entsprechend der Anzahl der Eintragungen
|
|
181
|
+
counter <= lastArray;
|
|
182
|
+
counter++) {
|
|
183
|
+
const entry = threadList[counter].name;
|
|
184
|
+
if ((name === entry) || bValveFound) {
|
|
185
|
+
if (name === entry) bValveFound = true;
|
|
186
|
+
if (counter !== lastArray) threadList[counter] = threadList[counter + 1];
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/* If a valve is found, delete the last array (entry). Wenn Ventil gefunden letzten Array (Auftrag) löschen */
|
|
190
|
+
if (bValveFound) {
|
|
191
|
+
threadList.pop();
|
|
192
|
+
adapter.log.debug(`delList => order deleted ID: ${name} ( rest orders: ${threadList.length} )`);
|
|
193
|
+
}else{
|
|
194
|
+
badList.push(name);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (badList.length > 0) {
|
|
198
|
+
reject(`delList: could not find ${JSON.stringify(badList)}`);
|
|
199
|
+
} else {
|
|
200
|
+
resolve;
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}; // End delList
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* currentConsumption aktueller Verbrauch ermitteln
|
|
207
|
+
*
|
|
208
|
+
* @param {boolean} write
|
|
209
|
+
* @returns {Promise<{curFlow:number, parallel:number, pumpRequired:boolean}>}
|
|
210
|
+
*/
|
|
211
|
+
const currentConsumption = async (write) => {
|
|
212
|
+
try {
|
|
213
|
+
let curFlow = currentPumpUse.intBreak ? 0 : currentPumpUse.pumpPower, /* adapter.config.triggerMainPumpPower; */
|
|
214
|
+
/** aktuelle Anzahl der eingeschalteten Ventile */
|
|
215
|
+
parallel = 0,
|
|
216
|
+
pumpRequired = false;
|
|
217
|
+
adapter.log.debug(`currentConsumption curFlow: ${curFlow}, ${currentPumpUse.intBreak} => ${currentPumpUse.intBreak ? 0 : currentPumpUse.pumpPower}`);
|
|
218
|
+
if (!currentPumpUse.intBreak) {
|
|
219
|
+
// ermitteln von curPipe und der Anzahl der parallelen Stränge
|
|
220
|
+
for (const entry of threadList){
|
|
221
|
+
if (entry.state === 'wait') pumpRequired = true; // state => wait
|
|
222
|
+
if (entry.enable === true
|
|
223
|
+
&& entry.extBreak === false
|
|
224
|
+
) {
|
|
225
|
+
curFlow -= entry.pipeFlow; // // ermitteln der RestFörderkapazität
|
|
226
|
+
parallel ++; // Anzahl der Bewässerungsstellen um 1 erhöhen
|
|
227
|
+
pumpRequired = true;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (write || currentPumpUse.intBreak) {
|
|
233
|
+
adapter.setStateAsync('control.parallelOfMax', {
|
|
234
|
+
val: `${parallel} : ${maxParallel}`,
|
|
235
|
+
ack: true
|
|
236
|
+
});
|
|
237
|
+
adapter.setStateAsync('control.restFlow', {
|
|
238
|
+
val: `${curFlow} (${currentPumpUse.pumpPower} | ${currentPumpUse.name})`,
|
|
239
|
+
ack: true
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
curFlow: curFlow,
|
|
245
|
+
parallel: parallel,
|
|
246
|
+
pumpRequired: pumpRequired
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
} catch (error) {
|
|
250
|
+
adapter.log.error(`currentConsumption Error: ${error}`);
|
|
251
|
+
return {
|
|
252
|
+
curFlow: 0,
|
|
253
|
+
parallel: 99,
|
|
254
|
+
pumpRequired: false
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
/** Interval-Beregnung aus */
|
|
260
|
+
|
|
261
|
+
const onOffTimeoutOff = async (entry) => {
|
|
262
|
+
entry.ac.acOnOffTimeoutOff = new AbortController;
|
|
263
|
+
try {
|
|
264
|
+
const res = await asyncTime.setTimeout(1000 * (entry.onOffTimeOff < 600 ? 600 : entry.onOffTimeOff),`time expired`, { signal: entry.ac.acOnOffTimeoutOff.signal }); // mindestens 600 sek Pause (10 min)
|
|
265
|
+
if (res === `time expired`) { // Zeit abgelaufen
|
|
266
|
+
entry.myBreak = false;
|
|
267
|
+
// Zustand des Ventils im Thread < 0 > off, <<< 1 >>> wait, < 2 > on, < 3 > break, < 4 > Boost(on), < 5 > off(Boost)
|
|
268
|
+
entry.state = 'wait';
|
|
269
|
+
adapter.setStateAsync(`sprinkle.${entry.name}.sprinklerState`, {
|
|
270
|
+
val: entry.state, // <<< 1 >>> wait
|
|
271
|
+
ack: true
|
|
272
|
+
});
|
|
273
|
+
updateList();
|
|
274
|
+
}
|
|
275
|
+
} catch (error) {
|
|
276
|
+
adapter.log.error(`onOffTimeoutOff error: ${error}`);
|
|
277
|
+
} finally {
|
|
278
|
+
if (entry.ac.acOnOffTimeoutOff.aborted === false) entry.ac.acOnOffTimeoutOff.abort();
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
/*----------------------------------------------------------------------------------------------------------------------------------------------*/
|
|
282
|
+
|
|
283
|
+
/*----------------------------------------------------------------------------------------------------------------------------------------------*/
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Handling von Ventilen, Zeiten, Verbrauchsmengen im 1s Takt
|
|
287
|
+
*
|
|
288
|
+
* @param {object} entry
|
|
289
|
+
*/
|
|
290
|
+
const countSprinkleTime = async (entry) => {
|
|
291
|
+
try {
|
|
292
|
+
/* --- function beenden wenn ---*/
|
|
293
|
+
if ((boostOn && !(myConfig.config[entry.sprinkleID].booster) // boost-On && kein aktuelles Boost-Ventil
|
|
294
|
+
|| entry.extBreak) // extBreak aktive
|
|
295
|
+
) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
entry.count ++;
|
|
300
|
+
|
|
301
|
+
if ((entry.count < entry.wateringTime) // Zeit noch nicht abgelaufen?
|
|
302
|
+
&& (!entry.calcOn // Vergleich nur bei Berechnung der Verdunstung
|
|
303
|
+
|| !entry.autoOn // Vergleich nur bei Automatik
|
|
304
|
+
|| (myConfig.config[entry.sprinkleID].calculation.val < myConfig.config[entry.sprinkleID].calculation.maxIrrigation)) // Bodenfeuchte noch nicht erreicht? (z.B. beim Regen)
|
|
305
|
+
) { /* Zeit läuft */
|
|
306
|
+
adapter.setStateAsync(`sprinkle.${entry.name}.countdown`, {
|
|
307
|
+
val: addTime(entry.wateringTime - entry.count, ''),
|
|
308
|
+
ack: true
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
/* Alle 15s die Bodenfeuchte anpassen */
|
|
312
|
+
if (entry.calcOn // Vergleich nur bei Berechnung der Verdunstung
|
|
313
|
+
&& !(entry.count % 15) // alle 15s ausführen
|
|
314
|
+
) {
|
|
315
|
+
myConfig.addSoilMoistVal(entry.sprinkleID, entry.soilMoisture15s);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/* Intervall-Beregnung wenn angegeben (onOffTimeOff > 0) */
|
|
319
|
+
if ((entry.onOffTimeOff > 0) && !(entry.count % entry.onOffTimeOn)) {
|
|
320
|
+
adapter.log.info(`Intervall-Beregnung, timeOn: ${entry.onOffTimeOn}s, count: ${entry.count}s, timeOff: ${entry.onOffTimeOff}s, count % onOffTime: ${entry.count % entry.onOffTimeOn}`);
|
|
321
|
+
const _setValveOnOff = await setValve(entry, false);
|
|
322
|
+
if (_setValveOnOff === entry.idState) {
|
|
323
|
+
entry.myBreak = true;
|
|
324
|
+
/* Zustand des Ventils im Thread <<< 3 = Pause >>> (0:off; 1:wait; 2:on; 3:break; 4:Boost(on); 5:off(Boost); 6:Cistern empty; 7:extBreak) */
|
|
325
|
+
entry.state = 'break';
|
|
326
|
+
adapter.setStateAsync(`sprinkle.${entry.name}.sprinklerState`, {
|
|
327
|
+
val: entry.state,
|
|
328
|
+
ack: true
|
|
329
|
+
});
|
|
330
|
+
clearInterval(entry.countdown);
|
|
331
|
+
entry.countdown = null;
|
|
332
|
+
currentConsumption(true);
|
|
333
|
+
onOffTimeoutOff(entry);
|
|
334
|
+
updateList();
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
} else { /* zeit abgelaufen => Ventil ausschalten */
|
|
338
|
+
/* Wenn in der Konfiguration Bodenfeuchte = 100% gesetzt ist und Auto-Bewässerung aktive, dann Bodenfeuchte = 100% setzen*/
|
|
339
|
+
if (entry.autoOn && entry.calcOn && myConfig.config[entry.sprinkleID].calculation.endIrrigation) {
|
|
340
|
+
myConfig.setSoilMoistPct100(entry.sprinkleID);
|
|
341
|
+
}
|
|
342
|
+
/* Verbrauchswerte in der Historie aktualisieren */
|
|
343
|
+
addConsumedAndTime(entry);
|
|
344
|
+
/* Booster zurücksetzen */
|
|
345
|
+
if (myConfig.config[entry.sprinkleID].booster) {
|
|
346
|
+
//if (boostOn) {boostKill(entry.sprinkleID);}
|
|
347
|
+
boostReady = true;
|
|
348
|
+
boostOn = false;
|
|
349
|
+
adapter.log.debug(`ID: ${entry.name} UpdateList Sprinkle Off: boostReady = ${boostReady}`);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const _setValve = await setValve(entry, false);
|
|
353
|
+
|
|
354
|
+
/* Zustand des Ventils im Thread <<< 0 >>> off, < 1 > wait, < 2 > on, < 3 > break, < 4 > Boost(on), < 5 > off(Boost) */
|
|
355
|
+
entry.state = 'off';
|
|
356
|
+
const _sprinklerState = await adapter.setStateAsync(`sprinkle.${entry.name}.sprinklerState`, {
|
|
357
|
+
val: entry.state,
|
|
358
|
+
ack: true
|
|
359
|
+
});
|
|
360
|
+
const _runningTime = adapter.setStateAsync(`sprinkle.${entry.name}.runningTime`, {
|
|
361
|
+
val: '00:00',
|
|
362
|
+
ack: true
|
|
363
|
+
});
|
|
364
|
+
const _countdown = adapter.setStateAsync(`sprinkle.${entry.name}.countdown`, {
|
|
365
|
+
val: '0',
|
|
366
|
+
ack: true
|
|
367
|
+
});
|
|
368
|
+
currentConsumption(true);
|
|
369
|
+
// currentConsumption(entry.pipeFlow, false);
|
|
370
|
+
Promise.all([
|
|
371
|
+
_setValve,
|
|
372
|
+
_sprinklerState,
|
|
373
|
+
_runningTime,
|
|
374
|
+
_countdown
|
|
375
|
+
]).then(async () => {
|
|
376
|
+
entry.killSprinkle = true;
|
|
377
|
+
/* Zeiten löschen */
|
|
378
|
+
clearInterval(entry.countdown);
|
|
379
|
+
entry.countdown = null;
|
|
380
|
+
// entry.ac.acOnOffTimeoutOff.abort(); /// ???
|
|
381
|
+
|
|
382
|
+
}).then(()=>{
|
|
383
|
+
updateList();
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
}
|
|
387
|
+
} catch (error) {
|
|
388
|
+
adapter.log.error(`countSprinkleTime(${entry.name}): ${error}`);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Timer zum ausschalten des Boost
|
|
395
|
+
*
|
|
396
|
+
* @param {*} entry
|
|
397
|
+
*/
|
|
398
|
+
const boostOnTimer = async (entry) => {
|
|
399
|
+
entry.ac.acBoostOnTimer = new AbortController;
|
|
400
|
+
const combinedSignal = AbortSignal.any([
|
|
401
|
+
entry.ac.acBoostOnTimer.signal
|
|
402
|
+
]);
|
|
403
|
+
try {
|
|
404
|
+
adapter.log.debug(`ID: ${entry.name} boostOnTimer time start`);
|
|
405
|
+
await asyncTime.setTimeout(30000, undefined, { signal: combinedSignal });
|
|
406
|
+
boostOn = false;
|
|
407
|
+
// Zustand des Ventils im Thread < 0 > off, < 1 > wait, <<< 2 >>> on, < 3 > break, < 4 > Boost(on), < 5 > off(Boost)
|
|
408
|
+
entry.state = 'on';
|
|
409
|
+
adapter.setStateAsync(`sprinkle.${entry.name}.sprinklerState`, {
|
|
410
|
+
val: entry.state,
|
|
411
|
+
ack: true
|
|
412
|
+
});
|
|
413
|
+
adapter.log.debug(`ID: ${entry.name} boostOnTimer time out: boostOn = ${boostOn}`);
|
|
414
|
+
updateList();
|
|
415
|
+
} catch (error) {
|
|
416
|
+
boostOn = false;
|
|
417
|
+
adapter.log.debug(`ID: ${entry.name} boostOnTimer time out: ERROR: ${error}`);
|
|
418
|
+
updateList();
|
|
419
|
+
}finally{
|
|
420
|
+
if (entry.ac.acBoostOnTimer.aborted === false) entry.ac.acBoostOnTimer.abort();
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Control of the active irrigation circuits so that the maximum pump capacity (l / h) is achieved and the maximum number of irrigation circuits is not exceeded.
|
|
426
|
+
* => Steuerung der aktiven Bewässerungskreise, damit die maximale Pumpenkapazität (l / h) erreicht wird und die maximale Anzahl der Bewässerungskreise nicht überschritten wird.
|
|
427
|
+
*/
|
|
428
|
+
const updateList = async () => {
|
|
429
|
+
/* während des Boost eines Kreises ist ein Zuschalten von Sprengern nicht möglich */
|
|
430
|
+
if (boostOn) return;
|
|
431
|
+
if (updateListMarker.funcActive === true) {
|
|
432
|
+
updateListMarker.newStart = true;
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
const killList = [];
|
|
436
|
+
let consumption = {};
|
|
437
|
+
/* (timerOn = true) => Schaltabstand zwischen den Ventilen ein */
|
|
438
|
+
let timerOn = true;
|
|
439
|
+
// let switchingDistanceOn = false;
|
|
440
|
+
updateListMarker.funcActive = true;
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Sortierfunktion mySortDescending absteigende Sortierung
|
|
444
|
+
*
|
|
445
|
+
* @param a
|
|
446
|
+
* @param b
|
|
447
|
+
* @returns {number}
|
|
448
|
+
*/
|
|
449
|
+
function mySortDescending(a, b) {
|
|
450
|
+
return a.pipeFlow > b.pipeFlow ? -1 :
|
|
451
|
+
a.pipeFlow < b.pipeFlow ? 1 :
|
|
452
|
+
0;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Sortierfunktion mySortAscending aufsteigende Sortierung
|
|
456
|
+
*
|
|
457
|
+
* @param a
|
|
458
|
+
* @param b
|
|
459
|
+
* @returns {number}
|
|
460
|
+
*/
|
|
461
|
+
function mySortAscending(a, b) {
|
|
462
|
+
return a.pipeFlow < b.pipeFlow ? -1 :
|
|
463
|
+
a.pipeFlow > b.pipeFlow ? 1 :
|
|
464
|
+
0;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// ermitteln von curPipe und der Anzahl der parallelen Stränge
|
|
468
|
+
consumption = await currentConsumption(true);
|
|
469
|
+
if (consumption.pumpRequired === true) { // Pumpe erforderlich
|
|
470
|
+
|
|
471
|
+
// Spannungsversorgung einschalten bei Leistungsanforderung
|
|
472
|
+
try {
|
|
473
|
+
if (adapter.config.triggerControlVoltage
|
|
474
|
+
&& controlVoltage.enable === false) {
|
|
475
|
+
const _controlVoltage = await setValve(controlVoltage, true);
|
|
476
|
+
if (_controlVoltage === controlVoltage.idState) {
|
|
477
|
+
adapter.setStateAsync(`info.supplyVoltage`, {
|
|
478
|
+
val: controlVoltage.enable,
|
|
479
|
+
ack: true
|
|
480
|
+
});
|
|
481
|
+
await asyncTime.setTimeout(switchingDistanceMS, undefined, undefined);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
} catch (error) {
|
|
485
|
+
adapter.log.error(`Error trigger Control Voltage [${controlVoltage.idState}]: ${error}`);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Pumpe einschalten bei Leistungsanforderung
|
|
489
|
+
try {
|
|
490
|
+
if (adapter.config.pumpSelection !== 'noPump'
|
|
491
|
+
&& currentPumpUse.enable === false) {
|
|
492
|
+
const _currentPumpUse = await setValve(currentPumpUse, true);
|
|
493
|
+
if (_currentPumpUse && _currentPumpUse === currentPumpUse.idState) {
|
|
494
|
+
timerOn = false;
|
|
495
|
+
adapter.setStateAsync(currentPumpUse.id, {
|
|
496
|
+
val: currentPumpUse.enable,
|
|
497
|
+
ack: true
|
|
498
|
+
});
|
|
499
|
+
await asyncTime.setTimeout(currentPumpUse.leadTime, undefined, undefined);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
} catch (error) {
|
|
503
|
+
adapter.log.error(`Error trigger current Pump [${currentPumpUse.idState}]: ${error}`);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/* - wenn beim Umschalten der Pumpen die Förderleistung zu gering → Ventile deaktivieren - */
|
|
508
|
+
if (consumption.curFlow < 0) {
|
|
509
|
+
// aufsteigend sortieren nach der Verbrauchsmenge
|
|
510
|
+
threadList.sort(mySortAscending);
|
|
511
|
+
|
|
512
|
+
for await(const entry of threadList) {
|
|
513
|
+
entry.ac.acUpdateListPuOff = new AbortController; // acPumpeOff
|
|
514
|
+
try {
|
|
515
|
+
if (entry.enable // eingeschaltet
|
|
516
|
+
&& !entry.killSprinkle // && Aufgabe noch nicht erledigt
|
|
517
|
+
&& (consumption.curFlow < 0) // && Förderleistung der Pumpe zu gering
|
|
518
|
+
) {
|
|
519
|
+
entry.state = 'wait'; //1
|
|
520
|
+
const _setValve2 = await setValve(entry, false);
|
|
521
|
+
if (_setValve2 === entry.idState) {
|
|
522
|
+
consumption = await currentConsumption(true);
|
|
523
|
+
clearInterval(entry.countdown); // Zähler für Countdown, Verbrauchsmengen, usw. löschen
|
|
524
|
+
entry.countdown = null;
|
|
525
|
+
adapter.log.info(`Set Valve ID: ${entry.name} Pump delivery rate too low, wait! curFlow ${consumption.curFlow} parallel: ${consumption.parallel}`);
|
|
526
|
+
await asyncTime.setTimeout(300, undefined, {signal: entry.ac.acUpdateListPuOff.signal});
|
|
527
|
+
}
|
|
528
|
+
}else{
|
|
529
|
+
entry.ac.acUpdateListPuOff.abort();
|
|
530
|
+
}
|
|
531
|
+
} catch (error) { // Fehler beim Reduzieren der Verbrauchsmenge
|
|
532
|
+
adapter.log.error(`Error reducing consumption amount: ${error}`);
|
|
533
|
+
} finally {
|
|
534
|
+
if (entry.ac.acUpdateListPuOff.aborted === false) entry.ac.acUpdateListPuOff.abort();
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
adapter.log.info(`curFlow: ${consumption.curFlow}, parallel: ${consumption.parallel}`);
|
|
540
|
+
// absteigend sortieren nach der Verbrauchsmenge
|
|
541
|
+
threadList.sort(mySortDescending);
|
|
542
|
+
|
|
543
|
+
// einschalten der Bewässerungsventile nach Verbrauchsmenge und maximaler Anzahl
|
|
544
|
+
for await(const entry of threadList) {
|
|
545
|
+
try {
|
|
546
|
+
if (!entry.enable // ausgeschaltet
|
|
547
|
+
&& !entry.killSprinkle // && Aufgabe noch nicht erledigt
|
|
548
|
+
&& !entry.myBreak // && nicht in der Pause Interval-Beregnung
|
|
549
|
+
&& !entry.extBreak // && nicht in der externen Pause (extBreak)
|
|
550
|
+
&& (consumption.curFlow >= entry.pipeFlow) // && noch genügend Förderleistung der Pumpe
|
|
551
|
+
&& (consumption.parallel < maxParallel) // && maxParallel noch nicht erreicht
|
|
552
|
+
&& !boostOn // && Ventile nur einschalten, wenn kein Boost aktive
|
|
553
|
+
&& (boostReady || !(myConfig.config[entry.sprinkleID].booster)) // && wenn kein Boostventil aktive ist => alle Ventile ein ansonsten nur Ventile ohne Boostfunktion
|
|
554
|
+
){
|
|
555
|
+
entry.ac.acUpdateListOn = new AbortController;
|
|
556
|
+
|
|
557
|
+
timerOn === true ? await asyncTime.setTimeout(switchingDistanceMS, undefined, {signal: entry.ac.acUpdateListOn.signal}) : timerOn = true;
|
|
558
|
+
entry.state = myConfig.config[entry.sprinkleID].booster ? 'boost(on)' : 'on'; // state 4 => boost(on) : 2 => on
|
|
559
|
+
const _setValve3 = await setValve(entry, true);
|
|
560
|
+
if (_setValve3 === entry.idState) {
|
|
561
|
+
consumption = await currentConsumption(true);
|
|
562
|
+
if (myConfig.config[entry.sprinkleID].booster) {
|
|
563
|
+
boostReady = false;
|
|
564
|
+
boostOn = true;
|
|
565
|
+
boostOnTimer(entry);
|
|
566
|
+
adapter.log.debug(`ID: ${entry.name} UpdateList sprinkle On: boostReady = ${boostReady}`);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/* countdown starten */
|
|
570
|
+
if (!entry.startTime) {
|
|
571
|
+
entry.startTime = new Date();
|
|
572
|
+
}
|
|
573
|
+
adapter.log.debug(`!entry.countdown: ${!entry.countdown}, type: ${typeof(entry.countdown)}`);
|
|
574
|
+
if(!entry.countdown){
|
|
575
|
+
entry.countdown = setInterval(countSprinkleTime, 1000, entry); // 1000 = 1s
|
|
576
|
+
//entry.countdown = asyncTime.setInterval();
|
|
577
|
+
}
|
|
578
|
+
} else {
|
|
579
|
+
entry.ac.acUpdateListOn.abort();
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
} catch (error) { //Fehler beim Einschalten der Bewässerungsventile
|
|
583
|
+
adapter.log.error(`Error turning on irrigation valves [${entry.name}]: ${error}`);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Ausschalten der Ventile bei boostReady
|
|
588
|
+
if (boostOn) {
|
|
589
|
+
for await(const entry of threadList){
|
|
590
|
+
entry.ac.acUpdateListBoostOn = new AbortController;
|
|
591
|
+
try {
|
|
592
|
+
if(entry.enable // eingeschaltet
|
|
593
|
+
&& !entry.killSprinkle
|
|
594
|
+
&& !myConfig.config[entry.sprinkleID].booster
|
|
595
|
+
){
|
|
596
|
+
entry.state = 'off(Boost)'; //state => 5/off(boost)
|
|
597
|
+
const _setValve4 = await setValve(entry, false);
|
|
598
|
+
if (_setValve4 === entry.idState){
|
|
599
|
+
consumption = await currentConsumption(true);
|
|
600
|
+
clearInterval(entry.countdown);
|
|
601
|
+
entry.countdown = null;
|
|
602
|
+
await asyncTime.setTimeout(300, undefined, {signal: entry.ac.acUpdateListBoostOn.signal});
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
} catch (error) {
|
|
606
|
+
entry.ac.acUpdateListBoostOn.abort();
|
|
607
|
+
adapter.log.error(`Error when switching off the valves with boostReady [${entry.name}]: ${error}`);
|
|
608
|
+
} finally {
|
|
609
|
+
if (entry.ac.acUpdateListBoostOn.aborted === false) entry.ac.acUpdateListBoostOn.abort();
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
if (consumption.parallel === 0) { // Pumpe nicht mehr erforderlich | 0 Ventile an
|
|
615
|
+
|
|
616
|
+
// Pumpe ausschalten
|
|
617
|
+
if (currentPumpUse.enable === true) {
|
|
618
|
+
try {
|
|
619
|
+
const _currentPumpUse = await setValve(currentPumpUse, false);
|
|
620
|
+
if (_currentPumpUse === currentPumpUse.idState) {
|
|
621
|
+
adapter.setStateAsync(currentPumpUse.id,{
|
|
622
|
+
val: currentPumpUse.enable,
|
|
623
|
+
ack: true
|
|
624
|
+
});
|
|
625
|
+
await asyncTime.setTimeout(switchingDistanceMS, undefined, undefined);
|
|
626
|
+
}
|
|
627
|
+
} catch (error) {
|
|
628
|
+
adapter.log.error(`Error trigger current Pump [${currentPumpUse.idState}]: ${error}`);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// Spannungsversorgung (24V) ausschalten
|
|
633
|
+
if(controlVoltage.enable === true) {
|
|
634
|
+
try {
|
|
635
|
+
const _controlVoltage = await setValve(controlVoltage, false);
|
|
636
|
+
if (_controlVoltage === controlVoltage.idState) {
|
|
637
|
+
adapter.setStateAsync(`info.supplyVoltage`, {
|
|
638
|
+
val: controlVoltage.enable,
|
|
639
|
+
ack: true
|
|
640
|
+
});
|
|
641
|
+
// await asyncTime.setTimeout(switchingDistanceMS, undefined, undefined);
|
|
642
|
+
|
|
643
|
+
}
|
|
644
|
+
} catch (error) {
|
|
645
|
+
adapter.log.error(`Error trigger Control Voltage [${controlVoltage.idState}]: ${error}`);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
for await(const entry of threadList){
|
|
651
|
+
if(entry.killSprinkle
|
|
652
|
+
&& !entry.enable
|
|
653
|
+
){
|
|
654
|
+
killList.push(entry.name);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
if (killList.length > 0) {
|
|
659
|
+
await delList(killList); // erledigte Bewässerungsaufgaben aus der threadList löschen
|
|
660
|
+
await asyncTime.setTimeout(50,undefined,undefined);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
updateListMarker.funcActive = false;
|
|
664
|
+
if (updateListMarker.newStart === true) {
|
|
665
|
+
updateListMarker.newStart = false;
|
|
666
|
+
await asyncTime.setTimeout(50,undefined,undefined);
|
|
667
|
+
updateList();
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
}; // End updateList
|
|
671
|
+
|
|
672
|
+
/* --------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* +++++ Set the current pump for irrigation +++++
|
|
676
|
+
* → Festlegen der aktuellen Pumpe zur Bewässerung
|
|
677
|
+
*/
|
|
678
|
+
const setActualPump = async () => {
|
|
679
|
+
try {
|
|
680
|
+
switch(adapter.config.pumpSelection) {
|
|
681
|
+
case 'noPump':
|
|
682
|
+
case 'mainPump': {
|
|
683
|
+
/* Pumpe AUS => Zisternen-Bewässerung nicht aktiviert */
|
|
684
|
+
if (adapter.config.triggerCisternPump) {
|
|
685
|
+
adapter.setState('info.cisternState', {
|
|
686
|
+
val: `Cistern settings are not active! ${(fillLevelCistern > 0) ? (`level sensor: ${fillLevelCistern}% ${(adapter.config.triggerMinCisternLevel !== '') ? (` ${adapter.config.triggerMinCisternLevel}%`) : ('')}`):('')}`,
|
|
687
|
+
ack: true
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
break;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
case 'cistern': {
|
|
694
|
+
if (fillLevelCistern < parseFloat(adapter.config.triggerMinCisternLevel)) { // (Zisterne unter Minimum)
|
|
695
|
+
if (!currentPumpUse.intBreak) {
|
|
696
|
+
currentPumpUse.intBreak = true;
|
|
697
|
+
adapter.log.warn('Cistern empty => irrigation no longer possible');
|
|
698
|
+
if(!sendMessageText.onlySendError()){
|
|
699
|
+
sendMessageText.sendMessage('Cistern empty => irrigation no longer possible'); // Zisterne leer => Bewässerung nicht mehr möglich
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
adapter.setState('info.cisternState', {
|
|
703
|
+
val: `Cistern empty: ${fillLevelCistern} % (${adapter.config.triggerMinCisternLevel} %)`,
|
|
704
|
+
ack: true
|
|
705
|
+
});
|
|
706
|
+
// Pumpe ist eingeschaltet => ausschalten
|
|
707
|
+
if (currentPumpUse.enable) {
|
|
708
|
+
await setValve(currentPumpUse, false);
|
|
709
|
+
updateList(); // Wasserverbrauch an Pumpenleistung anpassen
|
|
710
|
+
}
|
|
711
|
+
} else if (fillLevelCistern > parseFloat(adapter.config.triggerOnCisternLevel)) {
|
|
712
|
+
if (currentPumpUse.intBreak) {
|
|
713
|
+
currentPumpUse.intBreak = false;
|
|
714
|
+
adapter.log.warn('Cistern filled => irrigation can begin again'); // Zisterne gefüllt => Bewässerung kann wieder beginnen
|
|
715
|
+
if(!sendMessageText.onlySendError()){
|
|
716
|
+
sendMessageText.sendMessage('Cistern filled => irrigation can begin again');
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
currentPumpUse.intBreak = false;
|
|
720
|
+
adapter.setState('info.cisternState', {
|
|
721
|
+
val: `Cistern filled: ${fillLevelCistern} % (${adapter.config.triggerMinCisternLevel} %)`,
|
|
722
|
+
ack: true
|
|
723
|
+
});
|
|
724
|
+
updateList(); // Wasserverbrauch an Pumpenleistung anpassen
|
|
725
|
+
} else if (currentPumpUse.intBreak === true) {
|
|
726
|
+
adapter.setState('info.cisternState', {
|
|
727
|
+
val: `Cistern empty: ${fillLevelCistern} % (${adapter.config.triggerMinCisternLevel} %)`,
|
|
728
|
+
ack: true
|
|
729
|
+
});
|
|
730
|
+
} else {
|
|
731
|
+
adapter.setState('info.cisternState', {
|
|
732
|
+
val: `Cistern filled: ${fillLevelCistern} % (${adapter.config.triggerMinCisternLevel} %)`,
|
|
733
|
+
ack: true
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
break;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
case 'pumpAndCistern': {
|
|
740
|
+
if (currentPumpUse.enable) {
|
|
741
|
+
/* Bewässerungspumpen aktiv */
|
|
742
|
+
if ((fillLevelCistern < parseFloat(adapter.config.triggerMinCisternLevel)) && (currentPumpUse.pumpCistern === true)) {
|
|
743
|
+
/* (Zisterne unter Minimum) && (ZisternenPumpe läuft) */
|
|
744
|
+
const _setValveCisternPumpOff = await setValve(currentPumpUse, false); // Pumpe Zisterne Aus
|
|
745
|
+
if (_setValveCisternPumpOff === currentPumpUse.idState) {
|
|
746
|
+
await adapter.setStateAsync(currentPumpUse.id, { // set State cisternPump === false
|
|
747
|
+
val: currentPumpUse.enable,
|
|
748
|
+
ack: true
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
currentPumpUse.pumpCistern = false;
|
|
752
|
+
currentPumpUse.name = 'Main pump';
|
|
753
|
+
currentPumpUse.idState = adapter.config.triggerMainPump || '';
|
|
754
|
+
currentPumpUse.id = 'info.mainPump';
|
|
755
|
+
currentPumpUse.pumpPower = parseInt(adapter.config.triggerMainPumpPower);
|
|
756
|
+
/* Hauptpumpe Ein */
|
|
757
|
+
const _setValveMainPumpOn = await setValve(currentPumpUse, true);
|
|
758
|
+
if (_setValveMainPumpOn === currentPumpUse.idState) {
|
|
759
|
+
await adapter.setStateAsync(currentPumpUse.id, { // set State cisternPump === false
|
|
760
|
+
val: currentPumpUse.enable,
|
|
761
|
+
ack: true
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
adapter.log.info('Pump change (cistern empty) Cistern pump off => main pump on');
|
|
765
|
+
if(!sendMessageText.onlySendError()){
|
|
766
|
+
sendMessageText.sendMessage('Pump change (cistern empty) Cistern pump off => main pump on');
|
|
767
|
+
}
|
|
768
|
+
updateList(); // Wasserverbrauch an Pumpenleistung anpassen
|
|
769
|
+
}
|
|
770
|
+
} else {
|
|
771
|
+
/* Bewässerungspumpen inaktiv */
|
|
772
|
+
if ((fillLevelCistern > parseFloat(adapter.config.triggerOnCisternLevel)) && (adapter.config.triggerCisternPump) && (adapter.config.triggerCisternPumpPower)) {
|
|
773
|
+
/* Zisterne voll && triggerCisternPump && triggerCisternPumpPower vorhanden*/
|
|
774
|
+
adapter.setState('info.cisternState', {
|
|
775
|
+
val: `Cistern filled: ${fillLevelCistern} % (${adapter.config.triggerMinCisternLevel} %)`,
|
|
776
|
+
ack: true
|
|
777
|
+
});
|
|
778
|
+
currentPumpUse.pumpCistern = true;
|
|
779
|
+
currentPumpUse.name = 'Cistern pump';
|
|
780
|
+
currentPumpUse.id = 'info.cisternPump';
|
|
781
|
+
currentPumpUse.idState = adapter.config.triggerCisternPump || '';
|
|
782
|
+
currentPumpUse.pumpPower = parseInt(adapter.config.triggerCisternPumpPower);
|
|
783
|
+
|
|
784
|
+
} else {
|
|
785
|
+
adapter.setState('info.cisternState', {
|
|
786
|
+
val: `Cistern empty: ${fillLevelCistern} % (adapter.config.triggerMinCisternLevel %)`,
|
|
787
|
+
ack: true
|
|
788
|
+
});
|
|
789
|
+
currentPumpUse.pumpCistern = false;
|
|
790
|
+
currentPumpUse.name = 'Main pump';
|
|
791
|
+
currentPumpUse.id = 'info.mainPump';
|
|
792
|
+
currentPumpUse.idState = adapter.config.triggerMainPump || '';
|
|
793
|
+
currentPumpUse.pumpPower = parseInt(adapter.config.triggerMainPumpPower);
|
|
794
|
+
}
|
|
795
|
+
adapter.setState('control.restFlow', {
|
|
796
|
+
val: `${currentPumpUse.pumpPower} (${currentPumpUse.pumpPower} | ${currentPumpUse.name})`,
|
|
797
|
+
ack: true
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
if (currentPumpUse.pumpCistern) {
|
|
801
|
+
adapter.setState('info.cisternState', {
|
|
802
|
+
val: `Cistern filled: ${fillLevelCistern} % (${adapter.config.triggerMinCisternLevel} %)`,
|
|
803
|
+
ack: true
|
|
804
|
+
});
|
|
805
|
+
} else {
|
|
806
|
+
adapter.setState('info.cisternState', {
|
|
807
|
+
val: `Cistern empty: ${fillLevelCistern} % (${adapter.config.triggerMinCisternLevel} %)`,
|
|
808
|
+
ack: true
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
break;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
} catch (error) {
|
|
815
|
+
adapter.log.error(`setActualPump ${error}`);
|
|
816
|
+
}
|
|
817
|
+
}; // End setActualPump
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Adding the consumption data to the history
|
|
822
|
+
* => Hinzufügen der Verbrauchsdaten zur History
|
|
823
|
+
*
|
|
824
|
+
* @param entry - array mit den Daten des aktiven Ventils
|
|
825
|
+
*/
|
|
826
|
+
function addConsumedAndTime(entry) {
|
|
827
|
+
adapter.setState(`sprinkle.${entry.name}.history.lastConsumed`, {
|
|
828
|
+
val: Math.round(entry.litersPerSecond * entry.count),
|
|
829
|
+
ack: true
|
|
830
|
+
});
|
|
831
|
+
adapter.setState(`sprinkle.${entry.name}.history.lastRunningTime`, {
|
|
832
|
+
val: addTime(entry.count, ''),
|
|
833
|
+
ack: true
|
|
834
|
+
});
|
|
835
|
+
const _formatTime = formatTime(entry.startTime);
|
|
836
|
+
adapter.setState(`sprinkle.${entry.name}.history.lastOn`, {
|
|
837
|
+
val: _formatTime.dayTime,
|
|
838
|
+
ack: true
|
|
839
|
+
});
|
|
840
|
+
adapter.getState(`sprinkle.${entry.name}.history.curCalWeekConsumed`, (err, state) => {
|
|
841
|
+
if (state && state.val) {
|
|
842
|
+
adapter.setState(`sprinkle.${entry.name}.history.curCalWeekConsumed`, {
|
|
843
|
+
val: (+state.val) + Math.round(entry.litersPerSecond * entry.count),
|
|
844
|
+
ack: true
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
});
|
|
848
|
+
adapter.getState(`sprinkle.${entry.name}.history.curCalWeekRunningTime`, (err, state) => {
|
|
849
|
+
if (state && state.val) {
|
|
850
|
+
adapter.setState(`sprinkle.${entry.name}.history.curCalWeekRunningTime`, {
|
|
851
|
+
val: addTime(+state.val, entry.count),
|
|
852
|
+
ack: true
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
});
|
|
856
|
+
} // End addConsumedAndTime
|
|
857
|
+
|
|
858
|
+
|
|
859
|
+
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
|
860
|
+
/* externe Funktionen */
|
|
861
|
+
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
|
862
|
+
|
|
863
|
+
/**
|
|
864
|
+
* -- externe Funktionen -> initValveControl - addList - extBreak - clearEntireList - setFillLevelCistern --
|
|
865
|
+
*/
|
|
866
|
+
const valveControl = {
|
|
867
|
+
/**
|
|
868
|
+
* Initialize the start configuration of ventilControl
|
|
869
|
+
* => Initialisieren Sie die Startkonfiguration von ventilControl
|
|
870
|
+
*
|
|
871
|
+
* @param {ioBroker.Adapter} myAdapter
|
|
872
|
+
*/
|
|
873
|
+
initValveControl: async function (myAdapter) {
|
|
874
|
+
adapter = adapter || myAdapter;
|
|
875
|
+
|
|
876
|
+
try {
|
|
877
|
+
switchingDistanceMS = (
|
|
878
|
+
(+adapter.config.switchingDistance || 0) < 200)
|
|
879
|
+
? 200
|
|
880
|
+
: (
|
|
881
|
+
(+adapter.config.switchingDistance > 240000)
|
|
882
|
+
? 240000
|
|
883
|
+
: (+adapter.config.switchingDistance)
|
|
884
|
+
);
|
|
885
|
+
adapter.log.info(`switchingDistanceMS: ${switchingDistanceMS}ms`);
|
|
886
|
+
/* Object supplyVoltage (VersorgungsSpannung) anlegen */
|
|
887
|
+
if (adapter.config.triggerControlVoltage.length > 5) {
|
|
888
|
+
controlVoltage.idState = adapter.config.triggerControlVoltage; // Schaltaktor zuweisen
|
|
889
|
+
await adapter.setObjectNotExistsAsync(`info.supplyVoltage`, {
|
|
890
|
+
type: 'state',
|
|
891
|
+
common: {
|
|
892
|
+
role: 'switch',
|
|
893
|
+
name: 'Supply voltage',
|
|
894
|
+
desc: {
|
|
895
|
+
en: 'power supply',
|
|
896
|
+
de: 'Stromversorgung',
|
|
897
|
+
ru: 'источник питания',
|
|
898
|
+
pt: 'fonte de energia',
|
|
899
|
+
nl: 'voeding',
|
|
900
|
+
fr: 'alimentation électrique',
|
|
901
|
+
it: 'Alimentazione elettrica',
|
|
902
|
+
es: 'fuente de alimentación',
|
|
903
|
+
pl: 'zasilacz',
|
|
904
|
+
uk: 'джерело живлення',
|
|
905
|
+
'zh-cn': '电源'
|
|
906
|
+
},
|
|
907
|
+
type: 'boolean',
|
|
908
|
+
read: true,
|
|
909
|
+
write: false,
|
|
910
|
+
def: false
|
|
911
|
+
},
|
|
912
|
+
native: {},
|
|
913
|
+
});
|
|
914
|
+
} else {
|
|
915
|
+
const _supplyVoltage = await adapter.getObjectAsync(`info.supplyVoltage`);
|
|
916
|
+
if (_supplyVoltage) await adapter.delObjectAsync(`info.supplyVoltage`);
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
|
|
920
|
+
/* Objekt control.parallelOfMax befüllen */
|
|
921
|
+
maxParallel = parseInt(adapter.config.maximumParallelValves);
|
|
922
|
+
adapter.setStateAsync('control.parallelOfMax', {
|
|
923
|
+
val: `0 : ${adapter.config.maximumParallelValves}`,
|
|
924
|
+
ack: true
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
/* Object mainPump und Cistern anlegen, wenn benötigt */
|
|
928
|
+
const objMainPump = {
|
|
929
|
+
type: 'state',
|
|
930
|
+
common: {
|
|
931
|
+
role: 'indicator',
|
|
932
|
+
name: 'Main pump',
|
|
933
|
+
desc: {
|
|
934
|
+
en: 'Main pump',
|
|
935
|
+
de: 'Hauptpumpe',
|
|
936
|
+
ru: 'Главный насос',
|
|
937
|
+
pt: 'Bomba principal',
|
|
938
|
+
nl: 'Hoofdpomp',
|
|
939
|
+
fr: 'Pompe principale',
|
|
940
|
+
it: 'Pompa principale',
|
|
941
|
+
es: 'Bomba principal',
|
|
942
|
+
pl: 'Główna pompa',
|
|
943
|
+
uk: 'Головний насос',
|
|
944
|
+
'zh-cn': '主泵'
|
|
945
|
+
},
|
|
946
|
+
type: 'boolean',
|
|
947
|
+
read: true,
|
|
948
|
+
write: false,
|
|
949
|
+
def: false
|
|
950
|
+
},
|
|
951
|
+
native: {},
|
|
952
|
+
};
|
|
953
|
+
const objCisternPump = {
|
|
954
|
+
type: 'state',
|
|
955
|
+
common: {
|
|
956
|
+
role: 'indicator',
|
|
957
|
+
name: 'Cistern pump',
|
|
958
|
+
desc: {
|
|
959
|
+
en: 'Cistern pump',
|
|
960
|
+
de: 'Zisternenpumpe',
|
|
961
|
+
ru: 'Насос для цистерны',
|
|
962
|
+
pt: 'Bomba da cisterna',
|
|
963
|
+
nl: 'Cisternpomp',
|
|
964
|
+
fr: 'Pompe de citerne',
|
|
965
|
+
it: 'Pompa cisterna',
|
|
966
|
+
es: 'Bomba de cisterna',
|
|
967
|
+
pl: 'Pompa zbiornika',
|
|
968
|
+
uk: 'Насос цистерни',
|
|
969
|
+
'zh-cn': '水箱泵'
|
|
970
|
+
},
|
|
971
|
+
type: 'boolean',
|
|
972
|
+
read: true,
|
|
973
|
+
write: false,
|
|
974
|
+
def: false
|
|
975
|
+
},
|
|
976
|
+
native: {},
|
|
977
|
+
};
|
|
978
|
+
|
|
979
|
+
switch (adapter.config.pumpSelection) {
|
|
980
|
+
case 'noPump': {
|
|
981
|
+
currentPumpUse.pumpCistern = false;
|
|
982
|
+
currentPumpUse.name = 'no pump';
|
|
983
|
+
currentPumpUse.intBreak = false;
|
|
984
|
+
currentPumpUse.idState = '';
|
|
985
|
+
currentPumpUse.id = '';
|
|
986
|
+
currentPumpUse.leadTime = 0;
|
|
987
|
+
currentPumpUse.pumpPower = parseInt(adapter.config.triggerMainPumpPower) || 0;
|
|
988
|
+
currentPumpUse.restFlow = parseInt(adapter.config.triggerMainPumpPower) || 0;
|
|
989
|
+
const _mainPump = await adapter.getObjectAsync(`info.mainPump`);
|
|
990
|
+
if (_mainPump) await adapter.delObjectAsync(`info.mainPump`);
|
|
991
|
+
const _cisternPump = await adapter.getObjectAsync(`info.cisternPump`);
|
|
992
|
+
if (_cisternPump) await adapter.delObjectAsync(`info.cisternPump`);
|
|
993
|
+
break;
|
|
994
|
+
}
|
|
995
|
+
case 'mainPump': {
|
|
996
|
+
currentPumpUse.pumpCistern = false;
|
|
997
|
+
currentPumpUse.name = 'Main pump';
|
|
998
|
+
currentPumpUse.intBreak = false;
|
|
999
|
+
currentPumpUse.idState = adapter.config.triggerMainPump || '';
|
|
1000
|
+
currentPumpUse.id = 'info.mainPump';
|
|
1001
|
+
currentPumpUse.leadTime = (parseInt(adapter.config.mainPumpLeadTime) || 5) * 1000;
|
|
1002
|
+
currentPumpUse.pumpPower = parseInt(adapter.config.triggerMainPumpPower) || 0;
|
|
1003
|
+
currentPumpUse.restFlow = parseInt(adapter.config.triggerMainPumpPower) || 0;
|
|
1004
|
+
// @ts-ignore
|
|
1005
|
+
await adapter.setObjectNotExistsAsync(`info.mainPump`, objMainPump);
|
|
1006
|
+
const _cisternPump = await adapter.getObjectAsync(`info.cisternPump`);
|
|
1007
|
+
if (_cisternPump) await adapter.delObjectAsync(`info.cisternPump`);
|
|
1008
|
+
break;
|
|
1009
|
+
}
|
|
1010
|
+
case 'cistern': {
|
|
1011
|
+
/* Füllstand der Zisterne in % holen */
|
|
1012
|
+
const _actualValueLevel = await adapter.getForeignStateAsync(adapter.config.actualValueLevel);
|
|
1013
|
+
if (_actualValueLevel && _actualValueLevel.val) {
|
|
1014
|
+
if (typeof _actualValueLevel.val === 'number') {
|
|
1015
|
+
fillLevelCistern = _actualValueLevel.val;
|
|
1016
|
+
(_actualValueLevel.val > parseInt(adapter.config.triggerMinCisternLevel)) ? currentPumpUse.intBreak = false : currentPumpUse.intBreak = true;
|
|
1017
|
+
} else if (typeof _actualValueLevel.val === 'boolean') {
|
|
1018
|
+
if (_actualValueLevel.val) {
|
|
1019
|
+
currentPumpUse.intBreak = false;
|
|
1020
|
+
fillLevelCistern = 100;
|
|
1021
|
+
} else {
|
|
1022
|
+
currentPumpUse.intBreak = true;
|
|
1023
|
+
fillLevelCistern = 0;
|
|
1024
|
+
}
|
|
1025
|
+
} else {
|
|
1026
|
+
adapter.log.warn(`level sensor in the cistern => Wrong value: ${_actualValueLevel.val}, Type: ${typeof _actualValueLevel.val}`);
|
|
1027
|
+
}
|
|
1028
|
+
} else {
|
|
1029
|
+
adapter.log.warn(`level sensor in the cistern => Wrong value: ${JSON.stringify(_actualValueLevel)}`);
|
|
1030
|
+
fillLevelCistern = 0;
|
|
1031
|
+
currentPumpUse.intBreak = true;
|
|
1032
|
+
}
|
|
1033
|
+
currentPumpUse.pumpCistern = false;
|
|
1034
|
+
currentPumpUse.name = 'Cistern pump';
|
|
1035
|
+
currentPumpUse.idState = adapter.config.triggerCisternPump || '';
|
|
1036
|
+
currentPumpUse.id = 'info.cisternPump';
|
|
1037
|
+
currentPumpUse.leadTime = (parseInt(adapter.config.cisternPumpLeadTime) || 5) * 1000;
|
|
1038
|
+
currentPumpUse.pumpPower = parseInt(adapter.config.triggerCisternPumpPower) || 0;
|
|
1039
|
+
currentPumpUse.restFlow = parseInt(adapter.config.triggerCisternPumpPower) || 0;
|
|
1040
|
+
// @ts-ignore
|
|
1041
|
+
await adapter.setObjectNotExistsAsync(`info.cisternPump`, objCisternPump);
|
|
1042
|
+
const _mainPump = await adapter.getObjectAsync(`info.mainPump`);
|
|
1043
|
+
if (_mainPump) await adapter.delObjectAsync(`info.mainPump`);
|
|
1044
|
+
break;
|
|
1045
|
+
}
|
|
1046
|
+
case 'pumpAndCistern': {
|
|
1047
|
+
currentPumpUse.enable = false;
|
|
1048
|
+
if (adapter.config.actualValueLevel) {
|
|
1049
|
+
/* Füllstand der Zisterne in % holen */
|
|
1050
|
+
const _actualValueLevel = await adapter.getForeignStateAsync(adapter.config.actualValueLevel);
|
|
1051
|
+
if (_actualValueLevel && _actualValueLevel.val) {
|
|
1052
|
+
if (typeof _actualValueLevel.val === 'number') {
|
|
1053
|
+
fillLevelCistern = _actualValueLevel.val;
|
|
1054
|
+
} else if (typeof _actualValueLevel.val === 'boolean') {
|
|
1055
|
+
_actualValueLevel.val ? fillLevelCistern = 100 : fillLevelCistern = 0;
|
|
1056
|
+
} else {
|
|
1057
|
+
fillLevelCistern = 0;
|
|
1058
|
+
adapter.log.warn(`level sensor in the cistern => Wrong value: ${_actualValueLevel.val}, Type: ${typeof _actualValueLevel.val}`);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
if (fillLevelCistern > parseInt(adapter.config.triggerMinCisternLevel)) {
|
|
1063
|
+
currentPumpUse.pumpCistern = true;
|
|
1064
|
+
currentPumpUse.name = 'Cistern pump';
|
|
1065
|
+
currentPumpUse.idState = adapter.config.triggerCisternPump || '';
|
|
1066
|
+
currentPumpUse.id = 'info.cisternPump';
|
|
1067
|
+
currentPumpUse.leadTime = (parseInt(adapter.config.cisternPumpLeadTime) || 5) * 1000;
|
|
1068
|
+
currentPumpUse.pumpPower = parseInt(adapter.config.triggerCisternPumpPower) || 0;
|
|
1069
|
+
currentPumpUse.restFlow = parseInt(adapter.config.triggerCisternPumpPower) || 0;
|
|
1070
|
+
} else {
|
|
1071
|
+
currentPumpUse.pumpCistern = false;
|
|
1072
|
+
currentPumpUse.name = 'Main pump';
|
|
1073
|
+
currentPumpUse.idState = adapter.config.triggerMainPump || '';
|
|
1074
|
+
currentPumpUse.id = 'info.mainPump';
|
|
1075
|
+
currentPumpUse.leadTime = (parseInt(adapter.config.mainPumpLeadTime) || 5) * 1000;
|
|
1076
|
+
currentPumpUse.pumpPower = parseInt(adapter.config.triggerMainPumpPower) || 0;
|
|
1077
|
+
currentPumpUse.restFlow = parseInt(adapter.config.triggerMainPumpPower) || 0;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
currentPumpUse.intBreak = false;
|
|
1081
|
+
}
|
|
1082
|
+
// @ts-ignore
|
|
1083
|
+
await adapter.setObjectNotExistsAsync(`info.mainPump`, objMainPump);
|
|
1084
|
+
// @ts-ignore
|
|
1085
|
+
await adapter.setObjectNotExistsAsync(`info.cisternPump`, objCisternPump);
|
|
1086
|
+
break;
|
|
1087
|
+
}
|
|
1088
|
+
default: {
|
|
1089
|
+
currentPumpUse.intBreak = true;
|
|
1090
|
+
adapter.log.error(`In the configuration, under Pump settings, select the Pump selection field.`);
|
|
1091
|
+
const _mainPump = await adapter.getObjectAsync(`info.mainPump`);
|
|
1092
|
+
if (_mainPump) await adapter.delObjectAsync(`info.mainPump`);
|
|
1093
|
+
const _cisternPump = await adapter.getObjectAsync(`info.cisternPump`);
|
|
1094
|
+
if (_cisternPump) await adapter.delObjectAsync(`info.cisternPump`);
|
|
1095
|
+
break;
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
/* Objekt control.restFlow befüllen */
|
|
1099
|
+
adapter.setStateAsync('control.restFlow', {
|
|
1100
|
+
val: `${currentPumpUse.pumpPower} (${currentPumpUse.pumpPower} | ${currentPumpUse.name})`,
|
|
1101
|
+
ack: true
|
|
1102
|
+
});
|
|
1103
|
+
|
|
1104
|
+
/*Pumpe ausschalten*/
|
|
1105
|
+
currentPumpUse.enable = false;
|
|
1106
|
+
/* Pumpe ausschalter, wenn vorhanden */
|
|
1107
|
+
if (adapter.config.triggerMainPump !== '') {
|
|
1108
|
+
const _triggerMainPump = await adapter.getStateAsync('adapter.config.triggerMainPump');
|
|
1109
|
+
if (_triggerMainPump && _triggerMainPump.val && _triggerMainPump.val === true) {
|
|
1110
|
+
adapter.setStateAsync(adapter.config.triggerMainPump, {
|
|
1111
|
+
val: false,
|
|
1112
|
+
ack: false
|
|
1113
|
+
});
|
|
1114
|
+
adapter.setStateAsync('info.mainPump', {
|
|
1115
|
+
val:false,
|
|
1116
|
+
ack:false
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
/* Pumpe (Zisterne) ausschalter, wenn vorhanden */
|
|
1121
|
+
if (adapter.config.triggerCisternPump !== '') {
|
|
1122
|
+
const _triggerCisternPump = await adapter.getStateAsync('adapter.config.triggerCisternPump');
|
|
1123
|
+
if (_triggerCisternPump && _triggerCisternPump.val && _triggerCisternPump.val === true) {
|
|
1124
|
+
adapter.setState(adapter.config.triggerCisternPump, {
|
|
1125
|
+
val: false,
|
|
1126
|
+
ack: false
|
|
1127
|
+
});
|
|
1128
|
+
adapter.setStateAsync('info.cisternPump', {
|
|
1129
|
+
val:false,
|
|
1130
|
+
ack:false
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
/* alle Ventile (.name = "hm-rpc.0.MEQ1234567.3.STATE") in einem definierten Zustand (false) versetzen*/
|
|
1135
|
+
const result = adapter.config.events;
|
|
1136
|
+
let testMaxFlow;
|
|
1137
|
+
if (adapter.config.pumpSelection === 'pumpAndCistern') {
|
|
1138
|
+
testMaxFlow = (parseFloat(adapter.config.triggerCisternPumpPower) > parseFloat(adapter.config.triggerMainPumpPower)) ? parseFloat(adapter.config.triggerCisternPumpPower) : parseFloat(adapter.config.triggerMainPumpPower);
|
|
1139
|
+
} else {
|
|
1140
|
+
testMaxFlow = currentPumpUse.pumpPower;
|
|
1141
|
+
}
|
|
1142
|
+
if (result) {
|
|
1143
|
+
for (const res of result) {
|
|
1144
|
+
const objectName = (res.name !== '') ? res.name.replace(/[.;, ]/g, '_') : res.name.replace(/[.;, ]/g, '_');
|
|
1145
|
+
const _valve = await adapter.getStateAsync(res.name);
|
|
1146
|
+
if (_valve?.val === true) {
|
|
1147
|
+
await adapter.setStateAsync(res.name, {
|
|
1148
|
+
val: false,
|
|
1149
|
+
ack: false
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
1152
|
+
/*Kontrolle Flow Pumpe > Flow Ventil*/
|
|
1153
|
+
if (testMaxFlow < parseInt(res.pipeFlow)) {
|
|
1154
|
+
adapter.log.warn(`The irrigation circuit ${objectName} cannot start! pipeFlow ${res.pipeFlow} > maxFlow ${testMaxFlow}! logicError in the configuration`);
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
} catch (error) {
|
|
1159
|
+
adapter.log.error(`initValveControl ERROR: ${error}`);
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
}, // End initValveControl
|
|
1163
|
+
|
|
1164
|
+
/**
|
|
1165
|
+
* Add Sprinkle
|
|
1166
|
+
* → Sprinkle hinzufügen
|
|
1167
|
+
* - auto → Automatik == (true), Handbetrieb == (false)
|
|
1168
|
+
* - sprinkleID → zugriff auf myConfig.config[sprinkleID]. xyz
|
|
1169
|
+
* - wateringTime → Bewässerungszeit in min
|
|
1170
|
+
*
|
|
1171
|
+
* @param {Array.<{auto: boolean, sprinkleID: number, wateringTime: number}>} sprinkleList
|
|
1172
|
+
*/
|
|
1173
|
+
addList: async function (sprinkleList) {
|
|
1174
|
+
try {
|
|
1175
|
+
if (adapter.config.pumpSelection === 'pumpAndCistern'
|
|
1176
|
+
&& currentPumpUse.enable === false
|
|
1177
|
+
&& fillLevelCistern > parseFloat(adapter.config.triggerMinCisternLevel)
|
|
1178
|
+
){
|
|
1179
|
+
await setActualPump();
|
|
1180
|
+
}
|
|
1181
|
+
for await (const res of sprinkleList) {
|
|
1182
|
+
const name = myConfig.config[res.sprinkleID].objectName;
|
|
1183
|
+
/**
|
|
1184
|
+
* add done
|
|
1185
|
+
* → hinzufügen erledigt (Sprenger bereits aktive)
|
|
1186
|
+
*
|
|
1187
|
+
*/
|
|
1188
|
+
let addDone = false;
|
|
1189
|
+
// schauen ob der Sprenger schon in der threadList ist
|
|
1190
|
+
if (threadList) {
|
|
1191
|
+
for await (const entry of threadList) {
|
|
1192
|
+
if (entry.sprinkleID === res.sprinkleID) {
|
|
1193
|
+
if (entry.wateringTime === res.wateringTime) {
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
entry.wateringTime = res.wateringTime;
|
|
1197
|
+
entry.autoOn = res.auto; // auto: = true autostart; = false Handbetrieb
|
|
1198
|
+
await adapter.setStateAsync(`sprinkle.${name}.runningTime`, {
|
|
1199
|
+
val: addTime(res.wateringTime, ''),
|
|
1200
|
+
ack: true
|
|
1201
|
+
});
|
|
1202
|
+
addDone = true; // Sprinkle found
|
|
1203
|
+
adapter.log.debug(`update ID: ${entry.name} new time: ${addTime(res.wateringTime, '')}`);
|
|
1204
|
+
break;
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
if (!addDone) {
|
|
1210
|
+
if (res.wateringTime <= 0) {
|
|
1211
|
+
adapter.setState(`sprinkle.${name}.runningTime`, {
|
|
1212
|
+
val: '00:00',
|
|
1213
|
+
ack: true
|
|
1214
|
+
});
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
const newThread = {};
|
|
1218
|
+
newThread.sprinkleID = res.sprinkleID; // Array[0...]
|
|
1219
|
+
newThread.name = name; // z.B "Blumenbeet"
|
|
1220
|
+
newThread.idState = myConfig.config[res.sprinkleID].idState; // z.B. "hm-rpc.0.MEQ1810129.1.STATE"
|
|
1221
|
+
newThread.wateringTime = res.wateringTime; // Bewässerungszeit
|
|
1222
|
+
newThread.pipeFlow = myConfig.config[res.sprinkleID].pipeFlow; // Wasserverbrauch
|
|
1223
|
+
newThread.count = 0; // Zähler im Sekundentakt
|
|
1224
|
+
newThread.calcOn = (myConfig.config[res.sprinkleID].methodControlSM === 'calculation'); // Anpassung der Bodenfeuchte true/false
|
|
1225
|
+
if (newThread.calcOn) {
|
|
1226
|
+
newThread.soilMoisture15s = 15 * (myConfig.config[res.sprinkleID].calculation.maxIrrigation - myConfig.config[res.sprinkleID].calculation.triggersIrrigation)
|
|
1227
|
+
/ (60 * myConfig.config[res.sprinkleID].wateringTime);
|
|
1228
|
+
}
|
|
1229
|
+
/** 0:"off", 1:"wait", 2:"on", 3:"break", 4:"Boost(on)", 5:"off(Boost)", 6:"Cistern empty", 7:"extBreak" */
|
|
1230
|
+
newThread.state = 'wait'; // zustand des Ventils Softwaremäßig
|
|
1231
|
+
newThread.enable = false; // zustand des Ventil softwaremäßig
|
|
1232
|
+
newThread.myBreak = false; // meine Pause
|
|
1233
|
+
newThread.extBreak = myConfig.config[res.sprinkleID].extBreak; // extBreak wird über .sprinkle.*.extBreak geschaltet
|
|
1234
|
+
newThread.killSprinkle = false; // Löschauftrag ausführen am Ende in threadList
|
|
1235
|
+
newThread.litersPerSecond = myConfig.config[res.sprinkleID].pipeFlow / 3600; // Wasserverbrauchsmenge pro Sekunde
|
|
1236
|
+
newThread.onOffTimeOff = myConfig.config[res.sprinkleID].wateringIntervalOff;
|
|
1237
|
+
newThread.onOffTimeOn = myConfig.config[res.sprinkleID].wateringIntervalOn;
|
|
1238
|
+
newThread.autoOn = res.auto;
|
|
1239
|
+
newThread.controller = {}; // controlle von Zeiten und Abbruchsignalen
|
|
1240
|
+
newThread.ac = {}; // object zum speichern des abortController
|
|
1241
|
+
newThread.id = threadList.length || 0;
|
|
1242
|
+
threadList.push(newThread);
|
|
1243
|
+
/* Zustand des Ventils im Thread < 0 > off, <<< 1 >>> wait, < 2 > on, < 3 > break, < 4 > Boost(on), < 5 > off(Boost), < 6 > Cistern empty, < 7 > extBreak */
|
|
1244
|
+
newThread.extBreak ? (newThread.state = 'extBreak') : (newThread.state = 'wait');
|
|
1245
|
+
adapter.setState(`sprinkle.${name}.sprinklerState`, {
|
|
1246
|
+
val: newThread.state,
|
|
1247
|
+
ack: true
|
|
1248
|
+
});
|
|
1249
|
+
adapter.setState(`sprinkle.${name}.runningTime`, {
|
|
1250
|
+
val: addTime(res.wateringTime, ''),
|
|
1251
|
+
ack: true
|
|
1252
|
+
});
|
|
1253
|
+
adapter.log.debug(`ID: ${name} new order created: ${JSON.stringify(threadList[newThread.id])}`);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
updateList();
|
|
1257
|
+
} catch (error) {
|
|
1258
|
+
adapter.log.warn(`valveControl.addList: ${JSON.stringify(sprinkleList)} => ${error}`);
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
}, // End addList
|
|
1262
|
+
|
|
1263
|
+
/**
|
|
1264
|
+
* extBreak => Spränger unterbrechen bei extBreak
|
|
1265
|
+
*
|
|
1266
|
+
* @param {number} sprinkleID
|
|
1267
|
+
* @param {boolean} extBreak
|
|
1268
|
+
* @returns {Promise<{val: boolean}>} val: true/false = Ventil gefunden / nicht gefunden
|
|
1269
|
+
*/
|
|
1270
|
+
extBreak: async function (sprinkleID, extBreak) {
|
|
1271
|
+
try {
|
|
1272
|
+
const _found = await findAsync(threadList, async (d) => {
|
|
1273
|
+
return Promise.resolve (d.sprinkleID === sprinkleID);
|
|
1274
|
+
});
|
|
1275
|
+
|
|
1276
|
+
if (_found?.sprinkleID === sprinkleID) {
|
|
1277
|
+
_found.extBreak = extBreak;
|
|
1278
|
+
if (extBreak === true) { // extBreak aktiv
|
|
1279
|
+
if (_found.enable === true) { // Ventil ist eingeschaltet
|
|
1280
|
+
const _setValve = await setValve(_found, false);
|
|
1281
|
+
if (_setValve === _found.idState) {
|
|
1282
|
+
_found.state = 'extBreak'; // <<< 7 >>> extBreak
|
|
1283
|
+
clearInterval(_found.countdown); // Timer Countdown löschen
|
|
1284
|
+
_found.countdown = null;
|
|
1285
|
+
/* Booster zurücksetzen */
|
|
1286
|
+
if (myConfig.config[_found.sprinkleID].booster) {
|
|
1287
|
+
_found.ac.acBoostOnTimer.abort(extBreak);
|
|
1288
|
+
boostReady = true;
|
|
1289
|
+
boostOn = false;
|
|
1290
|
+
adapter.log.debug(`ID: ${_found.name} UpdateList Sprinkle Off: boostReady = ${boostReady}`);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
} else { // Ventil ist in bereitschaft, aber extBreak wird aktiviert
|
|
1294
|
+
_found.state = 'extBreak'; // <<< 7 >>> extBreak
|
|
1295
|
+
}
|
|
1296
|
+
} else {
|
|
1297
|
+
// extBreak beendet und Zeit noch nicht abgelaufen?
|
|
1298
|
+
(_found.count < _found.wateringTime) ? (_found.state = 'wait') : (_found.state = 'off'); // (Bewässerung noch nicht erledigt) ? (< 0 > off) : (< 1 > wait)
|
|
1299
|
+
}
|
|
1300
|
+
/* Zustand des Ventils im Thread < 0 > off, < 1 > wait, < 2 > on, < 3 > break, < 4 > Boost(on), < 5 > off(Boost), < 6 > Cistern empty, <<< 7 >>> extBreak */
|
|
1301
|
+
await adapter.setStateAsync(`sprinkle.${_found.name}.sprinklerState`, {
|
|
1302
|
+
val: _found.state,
|
|
1303
|
+
ack: true
|
|
1304
|
+
});
|
|
1305
|
+
adapter.log.debug(`valveControl.extBreak: ${extBreak}, Name: ${_found.name}, ID: ${_found.sprinkleID}`); // löschen
|
|
1306
|
+
updateList();
|
|
1307
|
+
return {val: true};
|
|
1308
|
+
} else {
|
|
1309
|
+
return {val: false};
|
|
1310
|
+
}
|
|
1311
|
+
} catch (error) {
|
|
1312
|
+
adapter.log.warn(`valveControl.extBreak(${sprinkleID}, ${extBreak}) => ${error}`);
|
|
1313
|
+
return {val: false};
|
|
1314
|
+
}
|
|
1315
|
+
},
|
|
1316
|
+
|
|
1317
|
+
/**
|
|
1318
|
+
* switch off all devices, when close the adapter
|
|
1319
|
+
* => Beim Beenden des adapters alles ausschalten
|
|
1320
|
+
*/
|
|
1321
|
+
clearEntireList: async function () {
|
|
1322
|
+
try {
|
|
1323
|
+
await setValve(controlVoltage, false);
|
|
1324
|
+
await setValve(currentPumpUse, false);
|
|
1325
|
+
// let bValveFound = false; // Ventil gefunden
|
|
1326
|
+
for (let counter = threadList.length - 1; // Loop über das Array
|
|
1327
|
+
counter >= 0;
|
|
1328
|
+
counter--) {
|
|
1329
|
+
const entry = threadList[counter];
|
|
1330
|
+
/* Zustand des Ventils im Thread <<< 0 >>> off, < 1 > wait, < 2 > on, < 3 > break, < 4 > Boost(on), < 5 > off(Boost) */
|
|
1331
|
+
entry.state = 'off'; //0
|
|
1332
|
+
if (entry.enable) {
|
|
1333
|
+
await setValve(entry, false);
|
|
1334
|
+
adapter.log.info(`Set Valve (SprinkleControl: off) ID: ${entry.name}, value: false`);
|
|
1335
|
+
} else {
|
|
1336
|
+
adapter.setStateAsync(`sprinkle.${entry.name}.sprinklerState`, {
|
|
1337
|
+
val: entry.state,
|
|
1338
|
+
ack: true
|
|
1339
|
+
});
|
|
1340
|
+
}
|
|
1341
|
+
adapter.setStateAsync(`sprinkle.${entry.name}.runningTime`, {
|
|
1342
|
+
val: '00:00',
|
|
1343
|
+
ack: true
|
|
1344
|
+
});
|
|
1345
|
+
adapter.setStateAsync(`sprinkle.${entry.name}.countdown`, {
|
|
1346
|
+
val: '0',
|
|
1347
|
+
ack: true
|
|
1348
|
+
});
|
|
1349
|
+
/* Verbrauchswerte in der Historie aktualisieren */
|
|
1350
|
+
addConsumedAndTime(entry);
|
|
1351
|
+
/* del timer countdown */
|
|
1352
|
+
clearInterval(entry.countdown);
|
|
1353
|
+
entry.countdown = null;
|
|
1354
|
+
/* Timer abbrechen */
|
|
1355
|
+
if (entry.ac.acSetValveCancelTimeout.aborted === false) entry.ac.acSetValveCancelTimeout.abort(); // setValve
|
|
1356
|
+
if (entry.ac.acBoostOnTimer.aborted === false) entry.ac.acBoostOnTimer.abort(); // BoostOnTimer
|
|
1357
|
+
if (entry.ac.acUpdateListPuOff.aborted === false) entry.ac.acUpdateListPuOff.abort(); // UpdateList Pumpe aus (Leistung zu gering beim Pumpenwechsel)
|
|
1358
|
+
if (entry.ac.acUpdateListOn.aborted === false) entry.ac.acUpdateListOn.abort(); // UpdateList Ventile ein
|
|
1359
|
+
if (entry.ac.acUpdateListBoostOn.aborted === false) entry.ac.acUpdateListBoostOn.abort(); // UpdateList Ausschalten der Ventile bei BoostOn
|
|
1360
|
+
if (entry.ac.acOnOffTimeoutOff.aborted === false) entry.ac.acOnOffTimeoutOff.abort(); // OnOffTimeoutOff Ausschaltdauer bei on-off-Betrieb
|
|
1361
|
+
|
|
1362
|
+
adapter.log.debug(`order deleted Stop all ID: ${entry.name} ( rest orders: ${threadList.length} )`);
|
|
1363
|
+
threadList.pop(); // del last array
|
|
1364
|
+
}
|
|
1365
|
+
boostReady = true;
|
|
1366
|
+
boostOn = false;
|
|
1367
|
+
const _currentConsumption = await currentConsumption(true);
|
|
1368
|
+
if (_currentConsumption.parallel > 0) throw new Error(`clearEntireList: Not all valves in the list have been deleted`); // Nicht alle Ventile in der Liste wurden gelöscht
|
|
1369
|
+
return true;
|
|
1370
|
+
} catch (error) {
|
|
1371
|
+
if (error) {
|
|
1372
|
+
adapter.log.warn(`valveControl.clearEntireList() => ${error}`);
|
|
1373
|
+
}
|
|
1374
|
+
return false;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
}, // End clearEntireList
|
|
1378
|
+
|
|
1379
|
+
/**
|
|
1380
|
+
* Änderungen des Füllstands setzen + Vorrang der Pumpe setzen
|
|
1381
|
+
*
|
|
1382
|
+
* @param {number|string|boolean} levelCistern
|
|
1383
|
+
*/
|
|
1384
|
+
setFillLevelCistern: function (levelCistern) {
|
|
1385
|
+
adapter.log.debug(`setFillLevelCistern: ${levelCistern}`);
|
|
1386
|
+
if(typeof levelCistern === 'number') {
|
|
1387
|
+
fillLevelCistern = levelCistern;
|
|
1388
|
+
}else if(typeof levelCistern === 'string') {
|
|
1389
|
+
fillLevelCistern = parseFloat(levelCistern);
|
|
1390
|
+
}else if(typeof levelCistern === 'boolean') {
|
|
1391
|
+
(levelCistern === true) ? fillLevelCistern = 100 : fillLevelCistern = 0;
|
|
1392
|
+
}
|
|
1393
|
+
setActualPump();
|
|
1394
|
+
}, // End setFillLevelCistern
|
|
1395
|
+
|
|
1396
|
+
/**
|
|
1397
|
+
* Abfrage von intBreak der Zisternenpumpe
|
|
1398
|
+
*
|
|
1399
|
+
* @returns {boolean} intBreak
|
|
1400
|
+
*/
|
|
1401
|
+
getIntBreakCisternPump: function () {
|
|
1402
|
+
return (adapter.config.pumpSelection === 'cistern') ? currentPumpUse.intBreak : false;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
}; // End valveControl
|
|
1406
|
+
|
|
1407
|
+
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
|
1408
|
+
|
|
1409
|
+
module.exports = {
|
|
1410
|
+
valveControl,
|
|
1411
|
+
controlVoltage,
|
|
1412
|
+
currentPumpUse,
|
|
1413
|
+
threadList
|
|
1414
|
+
};
|