iobroker.poolcontrol 0.2.1 → 0.2.2
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/README.md +42 -67
- package/io-package.json +16 -30
- package/lib/helpers/controlHelper.js +6 -0
- package/lib/helpers/controlHelper2.js +195 -0
- package/lib/helpers/frostHelper.js +2 -2
- package/lib/helpers/solarHelper.js +2 -2
- package/lib/stateDefinitions/controlStates.js +64 -0
- package/lib/stateDefinitions/pumpStates.js +19 -0
- package/main.js +8 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
# ioBroker.poolcontrol
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|

|
|
5
5
|

|
|
6
6
|

|
|
7
7
|

|
|
8
8
|
[](https://github.com/DasBo1975/ioBroker.poolcontrol/blob/main/LICENSE)
|
|
9
9
|
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Beschreibung
|
|
13
|
+
|
|
10
14
|
Der Adapter **ioBroker.poolcontrol** dient zur Steuerung und Überwachung von Poolanlagen.
|
|
11
|
-
Er ermöglicht die Automatisierung von Pumpen
|
|
15
|
+
Er ermöglicht die Automatisierung von Pumpen-, Temperatur- und Solarsteuerung sowie die Verbrauchsauswertung.
|
|
12
16
|
|
|
13
17
|
---
|
|
14
18
|
|
|
@@ -28,7 +32,7 @@ Er ermöglicht die Automatisierung von Pumpen, Temperatur- und Solarsteuerung so
|
|
|
28
32
|
- **Solarsteuerung**
|
|
29
33
|
- Ein-/Ausschaltgrenzen mit Hysterese
|
|
30
34
|
- Kollektor-Warnung (mit automatischer Rücksetzung bei 10 % unter der Schwelle)
|
|
31
|
-
-
|
|
35
|
+
- Optionale Sprachausgabe bei Warnung
|
|
32
36
|
|
|
33
37
|
- **Zeitsteuerung**
|
|
34
38
|
- Bis zu 3 frei konfigurierbare Zeitfenster pro Woche
|
|
@@ -41,14 +45,15 @@ Er ermöglicht die Automatisierung von Pumpen, Temperatur- und Solarsteuerung so
|
|
|
41
45
|
- Auswertung eines externen kWh-Zählers
|
|
42
46
|
- Tages-, Wochen-, Monats- und Jahresverbrauch
|
|
43
47
|
- Berechnung der Stromkosten anhand konfigurierbarem Preis
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
|
|
49
|
+
**Hinweis:**
|
|
50
|
+
Details zum Verhalten der Verbrauchs- und Kostenwerte (z. B. bei Neustarts oder beim Wechsel des Stromzählers) finden Sie in der Datei [help.md](./help.md).
|
|
46
51
|
|
|
47
52
|
- **Sprachausgaben**
|
|
48
53
|
- Ausgabe über Alexa oder Telegram
|
|
49
54
|
- Ansagen bei Pumpenstart/-stopp, Fehlern oder Temperaturschwellen
|
|
50
55
|
|
|
51
|
-
- **
|
|
56
|
+
- **SystemCheck (Diagnosebereich)**
|
|
52
57
|
Ab Version **0.2.0** enthält der Adapter einen neuen Diagnosebereich **SystemCheck**.
|
|
53
58
|
Er bietet interne Debug-Logs, mit denen bestimmte Teilbereiche (z. B. Pumpen-, Solar- oder Temperatursteuerung) gezielt überwacht werden können.
|
|
54
59
|
|
|
@@ -66,7 +71,7 @@ Er ermöglicht die Automatisierung von Pumpen, Temperatur- und Solarsteuerung so
|
|
|
66
71
|
|
|
67
72
|
1. Adapter über ioBroker Admin installieren.
|
|
68
73
|
2. Instanz anlegen.
|
|
69
|
-
3. Konfiguration im Admin-Tab vornehmen: Pumpenleistung, Sensoren, Solar, Sprachausgaben
|
|
74
|
+
3. Konfiguration im Admin-Tab vornehmen: Pumpenleistung, Sensoren, Solar, Sprachausgaben usw.
|
|
70
75
|
|
|
71
76
|
---
|
|
72
77
|
|
|
@@ -88,81 +93,52 @@ Die Konfiguration erfolgt über Tabs im Admin-Interface:
|
|
|
88
93
|
- Rückspülerinnerung (Intervall in Tagen, Erinnerung über State)
|
|
89
94
|
- Wartung Kesseldruck (maximaler Druck, Warnung bei Überschreitung)
|
|
90
95
|
- Weitere Komfortfunktionen nach Praxistests
|
|
96
|
+
- Kesseldruck-Wartung / Drucksensor-Warnung
|
|
97
|
+
- PV-Überschuss-Steuerung (für z.B. Pumpe oder Wärmepumpe)
|
|
98
|
+
- Zweite Pumpe (z.B. Wärmetauscher)
|
|
99
|
+
- Statistikbereich
|
|
100
|
+
- Eigene Widgets für VIS/VIS2
|
|
101
|
+
- Erweiterung Wärmepumpen-/Heizlogik
|
|
102
|
+
- Steuerung von Poolbeleuchtung
|
|
103
|
+
- Steuerung von Poolrobotern
|
|
104
|
+
- Steuerung von elektrischen Ventilen
|
|
105
|
+
- Steuerung von Gegenstromanlagen
|
|
91
106
|
|
|
92
107
|
---
|
|
93
108
|
|
|
94
109
|
## Hinweis
|
|
95
110
|
|
|
96
111
|
Der Adapter befindet sich aktuell in der Entwicklung.
|
|
97
|
-
Funktionen können sich ändern
|
|
112
|
+
Funktionen können sich ändern – bitte regelmäßig den Changelog beachten.
|
|
98
113
|
|
|
99
114
|
---
|
|
100
115
|
|
|
101
116
|
## Dokumentation
|
|
102
|
-
- [
|
|
117
|
+
- [help.md (ausführliche Beschreibung und Hinweise)](./help.md)
|
|
103
118
|
|
|
104
119
|
---
|
|
105
120
|
|
|
106
121
|
## Changelog
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
### 0.2.0 (2025-10-06)
|
|
110
|
-
- Neuer Diagnosebereich **SystemCheck** für interne Debug-Logs und Analysen.
|
|
111
|
-
- Möglichkeit, einzelne Adapterbereiche (z. B. Pumpe, Solar, Temperatur) gezielt zu überwachen.
|
|
112
|
-
- Fortlaufendes Textprotokoll mit manueller Löschfunktion.
|
|
113
|
-
- Alle bisherigen Debug-Funktionen aus `zz_debuglogs` in `SystemCheck.debug_logs` integriert.
|
|
114
|
-
- Vorbereitung für zukünftige Diagnose-Erweiterungen (Export, Systemprüfung, Plausibilitäts-Checks).
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
### 0.1.2
|
|
118
|
-
- Verbesserung: Beim Adapterstart werden nun die letzten bekannten Temperaturwerte aller aktiven Sensoren (z. B. Oberfläche, Kollektor, Außentemperatur usw.) automatisch übernommen.
|
|
119
|
-
- Dadurch werden auch Sensoren korrekt angezeigt, die ihren Messwert nur selten aktualisieren (z. B. Homematic oder stromsparende Funk-Sensoren).
|
|
120
|
-
- Keine Änderung am Verhalten der restlichen Logik, reine Komfort- und Stabilitätsverbesserung.
|
|
121
|
-
|
|
122
|
-
### 0.1.1
|
|
123
|
-
- Fehlerbehebung: Endlosschleife zwischen `pump_switch` und externer Steckdose (`deviceId`) behoben, die bei bestimmten Smart-Steckdosen (z. B. Shelly, Tasmota, FritzDECT) auftreten konnte.
|
|
124
|
-
- Verbesserte Stabilität im `pumpHelper` durch interne Rückkopplungsprüfung.
|
|
125
|
-
- Keine Änderungen an bestehenden Konfigurationen erforderlich.
|
|
122
|
+
### **WORK IN PROGRESS**
|
|
126
123
|
|
|
127
|
-
### 0.
|
|
128
|
-
-
|
|
129
|
-
-
|
|
130
|
-
|
|
131
|
-
-
|
|
132
|
-
-
|
|
124
|
+
### 0.2.2 (2025-10-08)
|
|
125
|
+
- Einführung einer **automatischen Rückspülerinnerung** (neuer Bereich im ControlHelper2)
|
|
126
|
+
- Erinnerung mit Intervall in Tagen und automatischer Rücksetzung nach erfolgter Rückspülung
|
|
127
|
+
- Log- und Sprachausgabe bei Fälligkeit oder Überfälligkeit
|
|
128
|
+
- Erweiterung des Control-Bereichs um zusätzliche States (backwash_reminder_active, interval_days, last_date, required)
|
|
129
|
+
- Anpassung der main.js und controlStates zur Integration
|
|
130
|
+
- Vorbereitung weiterer Wartungs- und Steuerungsfunktionen (Beleuchtung, Roboter, Ventile, Gegenstromanlage, Kesseldruck-Überwachung).
|
|
133
131
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
Statusübersicht
|
|
137
|
-
Ab Version 0.0.10 gibt es einen eigenen Bereich `status.*` mit folgenden Datenpunkten:
|
|
138
|
-
|
|
139
|
-
- **status.summary** → Textübersicht (Pumpe, Modus, Temperaturen, Laufzeit, Umwälzung)
|
|
140
|
-
- **status.overview_json** → Übersicht als JSON (maschinenlesbar)
|
|
141
|
-
- **status.last_summary_update** → Zeitpunkt der letzten Aktualisierung
|
|
142
|
-
- **status.pump_last_start** → Letzter Pumpenstart (Zeitstempel)
|
|
143
|
-
- **status.pump_last_stop** → Letztes Pumpenende (Zeitstempel)
|
|
144
|
-
- **status.pump_was_on_today** → Boolean, ob die Pumpe heute lief
|
|
145
|
-
- **status.pump_today_count** → Anzahl der Starts heute (Reset um Mitternacht)
|
|
146
|
-
- **status.system_ok** → Boolean, ob das System fehlerfrei läuft
|
|
147
|
-
- **status.system_warning** → Boolean, wenn eine Warnung aktiv ist
|
|
148
|
-
- **status.system_warning_text** → Beschreibung der aktiven Warnung
|
|
149
|
-
- **status.season_active** → Anzeige, ob die Poolsaison aktiv ist
|
|
150
|
-
|
|
151
|
-
Diese Datenpunkte sind besonders für **VIS/vis2, Alexa- oder Telegram-Ausgaben** gedacht, da sie eine schnelle Übersicht über den aktuellen Poolstatus bieten.
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
### 0.0.9
|
|
155
|
-
- Laufzeit-, Umwälz-, Verbrauch-/Kosten- und Temperatur-Min/Max-States sind jetzt persistent
|
|
156
|
-
(Werte bleiben nach Adapter-Neustart oder Stromausfall erhalten)
|
|
157
|
-
|
|
158
|
-
### 0.0.8
|
|
159
|
-
- Hilfetab in der Instanzkonfiguration hinzugefügt (mit Link zur GitHub-Dokumentation)
|
|
132
|
+
---
|
|
160
133
|
|
|
161
|
-
### 0.0
|
|
162
|
-
-
|
|
134
|
+
### 0.2.0 (2025-10-06)
|
|
135
|
+
- Neuer Diagnosebereich **SystemCheck** für interne Debug-Logs und Analysen.
|
|
136
|
+
- Möglichkeit, einzelne Adapterbereiche (z. B. Pumpe, Solar, Temperatur) gezielt zu überwachen.
|
|
137
|
+
- Fortlaufendes Textprotokoll mit manueller Löschfunktion.
|
|
138
|
+
- Alle bisherigen Debug-Funktionen aus `zz_debuglogs` in `SystemCheck.debug_logs` integriert.
|
|
139
|
+
- Vorbereitung für zukünftige Diagnose-Erweiterungen (Export, Systemprüfung, Plausibilitäts-Checks).
|
|
163
140
|
|
|
164
|
-
|
|
165
|
-
- initial release
|
|
141
|
+
*(ältere Versionen siehe [io-package.json](./io-package.json))*
|
|
166
142
|
|
|
167
143
|
---
|
|
168
144
|
|
|
@@ -174,7 +150,6 @@ Diese Datenpunkte sind besonders für **VIS/vis2, Alexa- oder Telegram-Ausgaben*
|
|
|
174
150
|
|
|
175
151
|
## Unterstützung der Adapterentwicklung
|
|
176
152
|
Wenn Ihnen **ioBroker.poolcontrol** gefällt, denken Sie bitte über eine Spende nach:
|
|
177
|
-
|
|
178
153
|
➡️ [Unterstützen via PayPal](https://www.paypal.com/donate?business=dirk.bertin@t-online.de)
|
|
179
154
|
|
|
180
155
|
---
|
|
@@ -188,6 +163,6 @@ Der Nutzer ist für die **sichere Installation und den Betrieb seiner Hardware**
|
|
|
188
163
|
---
|
|
189
164
|
|
|
190
165
|
## License
|
|
191
|
-
Copyright (c) 2025 DasBo1975 <dasbo1975@outlook.de>
|
|
166
|
+
Copyright (c) 2025 DasBo1975 <dasbo1975@outlook.de>
|
|
192
167
|
|
|
193
|
-
MIT License
|
|
168
|
+
MIT License
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "poolcontrol",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.2",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.2.2": {
|
|
7
|
+
"en": "Added automatic backwash reminder with speech and log notifications.",
|
|
8
|
+
"de": "Automatische Rückspülerinnerung mit Sprach- und Log-Benachrichtigung hinzugefügt.",
|
|
9
|
+
"ru": "Добавлено автоматическое напоминание о обратной промывке с голосовыми и журнальными уведомлениями.",
|
|
10
|
+
"pt": "Adicionado lembrete automático de retrolavagem com notificações de voz e registro.",
|
|
11
|
+
"nl": "Automatische terugspoelherinnering toegevoegd met spraak- en logmeldingen.",
|
|
12
|
+
"fr": "Ajout d’un rappel automatique de contre-lavage avec notifications vocales et journaux.",
|
|
13
|
+
"it": "Aggiunto promemoria automatico di controlavaggio con notifiche vocali e log.",
|
|
14
|
+
"es": "Recordatorio automático de contralavado añadido con notificaciones de voz y registro.",
|
|
15
|
+
"pl": "Dodano automatyczne przypomnienie o płukaniu wstecznym z powiadomieniami głosowymi i dziennikiem.",
|
|
16
|
+
"zh-cn": "添加了带语音和日志通知的自动反冲洗提醒。"
|
|
17
|
+
},
|
|
6
18
|
"0.2.1": {
|
|
7
19
|
"en": "Fixed the issue with invisible states for speech control and added proper internal variable handling.",
|
|
8
20
|
"de": "Behebung des Problems mit unsichtbaren States für die Sprachsteuerung und hinzugefügte korrekte Handhabung interner Variablen.",
|
|
@@ -54,34 +66,8 @@
|
|
|
54
66
|
"pl": "Naprawiono nieskończoną pętlę między pump_switch a deviceId dla niektórych inteligentnych gniazdek",
|
|
55
67
|
"uk": "Виправлено нескінченний цикл між pump_switch і deviceId для деяких розумних розеток",
|
|
56
68
|
"zh-cn": "修复了某些智能插座中 pump_switch 与 deviceId 之间的无限循环"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
"en": "Added speech output via E-Mail (configurable: instance, recipient, subject)",
|
|
60
|
-
"de": "Sprachausgabe per E-Mail hinzugefügt (konfigurierbar: Instanz, Empfänger, Betreff)",
|
|
61
|
-
"ru": "Добавлен вывод речи по электронной почте (настраивается: экземпляр, получатель, тема)",
|
|
62
|
-
"pt": "Adicionada saída de fala por e-mail (configurável: instância, destinatário, assunto)",
|
|
63
|
-
"nl": "Spraakuitvoer via e-mail toegevoegd (configureerbaar: instantie, ontvanger, onderwerp)",
|
|
64
|
-
"fr": "Ajout de la sortie vocale par e-mail (configurable : instance, destinataire, sujet)",
|
|
65
|
-
"it": "Aggiunta uscita vocale via e-mail (configurabile: istanza, destinatario, oggetto)",
|
|
66
|
-
"es": "Se agregó salida de voz por correo electrónico (configurable: instancia, destinatario, asunto)",
|
|
67
|
-
"pl": "Dodano wyjście głosowe przez e-mail (konfigurowalne: instancja, odbiorca, temat)",
|
|
68
|
-
"uk": "Додано озвучення електронною поштою (налаштовується: екземпляр, одержувач, тема)",
|
|
69
|
-
"zh-cn": "新增通过电子邮件的语音输出(可配置:实例、收件人、主题)"
|
|
70
|
-
},
|
|
71
|
-
"0.0.10": {
|
|
72
|
-
"en": "Added extended status overview with pump statistics, system flags and JSON summary",
|
|
73
|
-
"de": "Erweiterte Statusübersicht mit Pumpenstatistiken, Systemanzeigen und JSON-Zusammenfassung hinzugefügt",
|
|
74
|
-
"ru": "Добавлен расширенный обзор состояния с насосной статистикой, системными флагами и JSON-резюме",
|
|
75
|
-
"pt": "Adicionada visão geral de status estendida com estatísticas da bomba, sinalizadores do sistema e resumo em JSON",
|
|
76
|
-
"nl": "Uitgebreide statusoverzicht toegevoegd met pompstatistieken, systeemindicatoren en JSON-samenvatting",
|
|
77
|
-
"fr": "Aperçu du statut étendu ajouté avec statistiques de la pompe, indicateurs système et résumé JSON",
|
|
78
|
-
"it": "Aggiunta panoramica dello stato estesa con statistiche della pompa, indicatori di sistema e riepilogo JSON",
|
|
79
|
-
"es": "Añadida vista general de estado extendida con estadísticas de la bomba, indicadores del sistema y resumen en JSON",
|
|
80
|
-
"pl": "Dodano rozszerzony przegląd statusu ze statystykami pompy, flagami systemowymi i podsumowaniem JSON",
|
|
81
|
-
"uk": "Додано розширений огляд статусу зі статистикою насоса, системними прапорцями та зведенням JSON",
|
|
82
|
-
"zh-cn": "新增扩展状态概览,包括泵统计、系统标志和 JSON 摘要"
|
|
83
|
-
}
|
|
84
|
-
},
|
|
69
|
+
}
|
|
70
|
+
},
|
|
85
71
|
"titleLang": {
|
|
86
72
|
"en": "PoolControl",
|
|
87
73
|
"de": "PoolControl",
|
|
@@ -159,5 +145,5 @@
|
|
|
159
145
|
},
|
|
160
146
|
"objects": [],
|
|
161
147
|
"instanceObjects": []
|
|
162
|
-
|
|
148
|
+
}
|
|
163
149
|
|
|
@@ -141,6 +141,7 @@ async function _startAutoPumping(missingLiter) {
|
|
|
141
141
|
|
|
142
142
|
previousPumpMode = (await adapter.getStateAsync('pump.mode'))?.val || 'auto';
|
|
143
143
|
await adapter.setStateAsync('pump.mode', { val: 'controlHelper', ack: true });
|
|
144
|
+
await adapter.setStateAsync('pump.active_helper', { val: 'controlHelper', ack: true });
|
|
144
145
|
await adapter.setStateAsync('pump.reason', { val: 'nachpumpen', ack: true });
|
|
145
146
|
await adapter.setStateAsync('pump.pump_switch', { val: true, ack: false });
|
|
146
147
|
|
|
@@ -157,6 +158,7 @@ async function _startAutoPumping(missingLiter) {
|
|
|
157
158
|
clearInterval(interval);
|
|
158
159
|
await adapter.setStateAsync('pump.pump_switch', { val: false, ack: false });
|
|
159
160
|
await adapter.setStateAsync('pump.mode', { val: previousPumpMode, ack: true });
|
|
161
|
+
await adapter.setStateAsync('pump.active_helper', { val: '', ack: true });
|
|
160
162
|
await adapter.setStateAsync('pump.reason', { val: '', ack: true });
|
|
161
163
|
previousPumpMode = null;
|
|
162
164
|
|
|
@@ -199,6 +201,7 @@ async function handleStateChange(id, state) {
|
|
|
199
201
|
previousPumpMode = (await adapter.getStateAsync('pump.mode'))?.val || 'auto';
|
|
200
202
|
await adapter.setStateAsync('pump.mode', { val: 'controlHelper', ack: true });
|
|
201
203
|
await adapter.setStateAsync('pump.reason', { val: 'wartung', ack: true });
|
|
204
|
+
await adapter.setStateAsync('pump.active_helper', { val: 'controlHelper', ack: true });
|
|
202
205
|
await adapter.setStateAsync('pump.pump_switch', { val: false, ack: false });
|
|
203
206
|
adapter.log.info('[controlHelper] Wartungsmodus aktiviert. Automatik pausiert.');
|
|
204
207
|
|
|
@@ -207,6 +210,7 @@ async function handleStateChange(id, state) {
|
|
|
207
210
|
}
|
|
208
211
|
} else {
|
|
209
212
|
await adapter.setStateAsync('pump.mode', { val: previousPumpMode, ack: true });
|
|
213
|
+
await adapter.setStateAsync('pump.active_helper', { val: '', ack: true });
|
|
210
214
|
await adapter.setStateAsync('pump.reason', { val: '', ack: true });
|
|
211
215
|
previousPumpMode = null;
|
|
212
216
|
|
|
@@ -232,6 +236,7 @@ async function handleStateChange(id, state) {
|
|
|
232
236
|
await adapter.setStateAsync('control.pump.backwash_active', { val: true, ack: true });
|
|
233
237
|
await adapter.setStateAsync('control.pump.backwash_start', { val: false, ack: true });
|
|
234
238
|
await adapter.setStateAsync('pump.mode', { val: 'controlHelper', ack: true });
|
|
239
|
+
await adapter.setStateAsync('pump.active_helper', { val: 'controlHelper', ack: true });
|
|
235
240
|
await adapter.setStateAsync('pump.reason', { val: 'rückspülen', ack: true });
|
|
236
241
|
await adapter.setStateAsync('pump.pump_switch', { val: true, ack: false });
|
|
237
242
|
|
|
@@ -250,6 +255,7 @@ async function handleStateChange(id, state) {
|
|
|
250
255
|
try {
|
|
251
256
|
await adapter.setStateAsync('pump.pump_switch', { val: false, ack: false });
|
|
252
257
|
await adapter.setStateAsync('pump.mode', { val: prevMode, ack: true });
|
|
258
|
+
await adapter.setStateAsync('pump.active_helper', { val: '', ack: true });
|
|
253
259
|
await adapter.setStateAsync('pump.reason', { val: '', ack: true });
|
|
254
260
|
await adapter.setStateAsync('control.pump.backwash_active', { val: false, ack: true });
|
|
255
261
|
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* controlHelper2
|
|
5
|
+
* ----------------------------------------------
|
|
6
|
+
* Rückspülerinnerungs-Logik (eigenständig)
|
|
7
|
+
* ----------------------------------------------
|
|
8
|
+
* - täglicher Check um 12:00 Uhr (lokale Host-Zeit)
|
|
9
|
+
* - prüft Intervall und letzte Rückspülung
|
|
10
|
+
* - erzeugt Erinnerungen (Log + speech.queue)
|
|
11
|
+
* - setzt Erinnerung automatisch zurück, wenn Rückspülung startet
|
|
12
|
+
* ----------------------------------------------
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// NEU: Modulvariablen
|
|
16
|
+
let adapter;
|
|
17
|
+
let backwashReminderTimer = null;
|
|
18
|
+
let lastReminderDay = null; // verhindert doppelte tägliche Meldungen
|
|
19
|
+
|
|
20
|
+
// NEU: Initialisierung
|
|
21
|
+
/**
|
|
22
|
+
* Initialisiert den Rückspülerinnerungs-Helper
|
|
23
|
+
*
|
|
24
|
+
* @param {import('iobroker').Adapter} a – ioBroker-Adapterinstanz
|
|
25
|
+
*/
|
|
26
|
+
function init(a) {
|
|
27
|
+
adapter = a;
|
|
28
|
+
adapter.log.info('[controlHelper2] Rückspülerinnerung initialisiert (täglicher Check um 12:00 Uhr).');
|
|
29
|
+
|
|
30
|
+
// Rückspülstart abonnieren, um Erinnerung zurückzusetzen
|
|
31
|
+
adapter.subscribeStates('control.pump.backwash_start');
|
|
32
|
+
|
|
33
|
+
// Täglichen Check planen
|
|
34
|
+
_scheduleBackwashReminder().catch(err =>
|
|
35
|
+
adapter.log.error(`[controlHelper2] Fehler bei _scheduleBackwashReminder(): ${err.message}`),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// NEU: Plant täglichen Timer um 12:00 Uhr lokale Zeit
|
|
40
|
+
async function _scheduleBackwashReminder() {
|
|
41
|
+
try {
|
|
42
|
+
if (backwashReminderTimer) {
|
|
43
|
+
clearTimeout(backwashReminderTimer);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const now = new Date();
|
|
47
|
+
const next = new Date();
|
|
48
|
+
next.setHours(12, 0, 0, 0); // 12:00 Uhr lokale Zeit
|
|
49
|
+
|
|
50
|
+
// Wenn 12:00 Uhr heute schon vorbei ist → morgen
|
|
51
|
+
if (next <= now) {
|
|
52
|
+
next.setDate(next.getDate() + 1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const diffMs = next - now;
|
|
56
|
+
adapter.log.debug(`[controlHelper2] Nächster Rückspülerinnerungs-Check geplant für ${next.toLocaleString()}`);
|
|
57
|
+
|
|
58
|
+
backwashReminderTimer = setTimeout(async () => {
|
|
59
|
+
await _runBackwashReminderCheck();
|
|
60
|
+
await _scheduleBackwashReminder(); // neu planen
|
|
61
|
+
}, diffMs);
|
|
62
|
+
} catch (err) {
|
|
63
|
+
adapter.log.error(`[controlHelper2] Fehler bei _scheduleBackwashReminder(): ${err.message}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// NEU: Führt täglichen Erinnerungs-Check aus
|
|
68
|
+
async function _runBackwashReminderCheck() {
|
|
69
|
+
try {
|
|
70
|
+
adapter.log.debug('[controlHelper2] Starte Rückspülerinnerungs-Check ...');
|
|
71
|
+
|
|
72
|
+
const reminderActive = (await adapter.getStateAsync('control.pump.backwash_reminder_active'))?.val;
|
|
73
|
+
if (!reminderActive) {
|
|
74
|
+
adapter.log.debug('[controlHelper2] Rückspülerinnerung deaktiviert – Check übersprungen.');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const intervalDays = Number((await adapter.getStateAsync('control.pump.backwash_interval_days'))?.val || 7);
|
|
79
|
+
const lastDateStr = (await adapter.getStateAsync('control.pump.backwash_last_date'))?.val || '';
|
|
80
|
+
|
|
81
|
+
const now = new Date();
|
|
82
|
+
const todayKey = now.toISOString().split('T')[0]; // yyyy-mm-dd
|
|
83
|
+
|
|
84
|
+
// Verhindert doppelte Erinnerungen am selben Tag
|
|
85
|
+
if (lastReminderDay === todayKey) {
|
|
86
|
+
adapter.log.debug('[controlHelper2] Erinnerung für heute bereits gesendet.');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let daysSince = null;
|
|
91
|
+
if (lastDateStr) {
|
|
92
|
+
const lastDate = new Date(lastDateStr);
|
|
93
|
+
const diffMs = now - lastDate;
|
|
94
|
+
daysSince = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (daysSince === null) {
|
|
98
|
+
adapter.log.debug('[controlHelper2] Keine letzte Rückspülung bekannt – keine Erinnerung.');
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const notify = (await adapter.getStateAsync('control.pump.notifications_enabled'))?.val;
|
|
103
|
+
const speechEnabled = notify === true;
|
|
104
|
+
|
|
105
|
+
if (daysSince >= intervalDays) {
|
|
106
|
+
// Fällig oder überfällig
|
|
107
|
+
await adapter.setStateAsync('control.pump.backwash_required', { val: true, ack: true });
|
|
108
|
+
let text;
|
|
109
|
+
|
|
110
|
+
if (daysSince === intervalDays) {
|
|
111
|
+
text = 'Erinnerung: Rückspülung ist wieder fällig.';
|
|
112
|
+
} else {
|
|
113
|
+
const over = daysSince - intervalDays;
|
|
114
|
+
text = `Erinnerung: Rückspülung ist seit ${over} Tag${over === 1 ? '' : 'en'} überfällig.`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
adapter.log.info(`[controlHelper2] ${text}`);
|
|
118
|
+
if (speechEnabled) {
|
|
119
|
+
await _sendSpeech(text);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
lastReminderDay = todayKey;
|
|
123
|
+
} else {
|
|
124
|
+
adapter.log.debug(`[controlHelper2] Rückspülung noch nicht fällig (${daysSince}/${intervalDays} Tage).`);
|
|
125
|
+
}
|
|
126
|
+
} catch (err) {
|
|
127
|
+
adapter.log.warn(`[controlHelper2] Fehler beim Erinnerungs-Check: ${err.message}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// NEU: Rücksetzung nach Rückspülstart
|
|
132
|
+
/**
|
|
133
|
+
* Reagiert auf State-Änderungen (z. B. Rückspülstart).
|
|
134
|
+
*
|
|
135
|
+
* @param {string} id – Objekt-ID des geänderten States
|
|
136
|
+
* @param {ioBroker.State} state – Neuer State-Wert
|
|
137
|
+
*/
|
|
138
|
+
async function handleStateChange(id, state) {
|
|
139
|
+
try {
|
|
140
|
+
if (!state || state.ack) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (!id.endsWith('control.pump.backwash_start') || !state.val) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
adapter.log.debug('[controlHelper2] Rückspülstart erkannt – Erinnerung wird zurückgesetzt.');
|
|
148
|
+
|
|
149
|
+
await adapter.setStateAsync('control.pump.backwash_required', { val: false, ack: true });
|
|
150
|
+
await adapter.setStateAsync('control.pump.backwash_last_date', {
|
|
151
|
+
val: new Date().toISOString(),
|
|
152
|
+
ack: true,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const notify = (await adapter.getStateAsync('control.pump.notifications_enabled'))?.val;
|
|
156
|
+
if (notify) {
|
|
157
|
+
const text = 'Rückspülerinnerung wurde zurückgesetzt. Rückspülzyklus neu gestartet.';
|
|
158
|
+
adapter.log.info(`[controlHelper2] ${text}`);
|
|
159
|
+
await _sendSpeech(text);
|
|
160
|
+
}
|
|
161
|
+
} catch (err) {
|
|
162
|
+
adapter.log.warn(`[controlHelper2] Fehler bei handleStateChange(): ${err.message}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// NEU: Sprachausgabe
|
|
167
|
+
async function _sendSpeech(text) {
|
|
168
|
+
if (!text) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
await adapter.setStateAsync('speech.queue', { val: text, ack: false });
|
|
173
|
+
adapter.log.debug(`[controlHelper2] Nachricht an speech.queue: ${text}`);
|
|
174
|
+
} catch (err) {
|
|
175
|
+
adapter.log.warn(`[controlHelper2] Fehler beim Senden an speech.queue: ${err.message}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// NEU: Aufräumen
|
|
180
|
+
/**
|
|
181
|
+
* Stoppt den Rückspülerinnerungs-Timer und räumt Variablen auf.
|
|
182
|
+
*
|
|
183
|
+
* @returns {void}
|
|
184
|
+
*/
|
|
185
|
+
function cleanup() {
|
|
186
|
+
if (backwashReminderTimer) {
|
|
187
|
+
clearTimeout(backwashReminderTimer);
|
|
188
|
+
backwashReminderTimer = null;
|
|
189
|
+
}
|
|
190
|
+
lastReminderDay = null;
|
|
191
|
+
adapter.log.debug('[controlHelper2] Cleanup ausgeführt.');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// NEU: Exporte
|
|
195
|
+
module.exports = { init, handleStateChange, cleanup };
|
|
@@ -33,8 +33,8 @@ const frostHelper = {
|
|
|
33
33
|
async _checkFrost() {
|
|
34
34
|
try {
|
|
35
35
|
// --- NEU: Vorrangprüfung durch ControlHelper ---
|
|
36
|
-
const
|
|
37
|
-
if (
|
|
36
|
+
const activeHelper = (await this.adapter.getStateAsync('pump.active_helper'))?.val || '';
|
|
37
|
+
if (activeHelper === 'controlHelper') {
|
|
38
38
|
this.adapter.log.debug('[frostHelper] Vorrang durch ControlHelper aktiv – Frostschutz pausiert.');
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
@@ -33,8 +33,8 @@ const solarHelper = {
|
|
|
33
33
|
async _checkSolar() {
|
|
34
34
|
try {
|
|
35
35
|
// --- NEU: Vorrangprüfung durch ControlHelper ---
|
|
36
|
-
const
|
|
37
|
-
if (
|
|
36
|
+
const activeHelper = (await this.adapter.getStateAsync('pump.active_helper'))?.val || '';
|
|
37
|
+
if (activeHelper === 'controlHelper') {
|
|
38
38
|
this.adapter.log.debug('[solarHelper] Vorrang durch ControlHelper aktiv – Solarregelung pausiert.');
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
@@ -118,6 +118,70 @@ async function createControlStates(adapter) {
|
|
|
118
118
|
});
|
|
119
119
|
await adapter.setStateAsync('control.pump.backwash_duration', { val: 1, ack: true });
|
|
120
120
|
|
|
121
|
+
// >>> NEU: Rückspülerinnerung
|
|
122
|
+
await adapter.setObjectNotExistsAsync('control.pump.backwash_reminder_active', {
|
|
123
|
+
type: 'state',
|
|
124
|
+
common: {
|
|
125
|
+
name: 'Rückspülerinnerung aktiv',
|
|
126
|
+
desc: 'Wenn aktiviert, erinnert der Adapter automatisch nach Ablauf des eingestellten Intervalls an die Rückspülung',
|
|
127
|
+
type: 'boolean',
|
|
128
|
+
role: 'switch',
|
|
129
|
+
read: true,
|
|
130
|
+
write: true,
|
|
131
|
+
def: false,
|
|
132
|
+
},
|
|
133
|
+
native: {},
|
|
134
|
+
});
|
|
135
|
+
await adapter.setStateAsync('control.pump.backwash_reminder_active', { val: false, ack: true });
|
|
136
|
+
|
|
137
|
+
await adapter.setObjectNotExistsAsync('control.pump.backwash_interval_days', {
|
|
138
|
+
type: 'state',
|
|
139
|
+
common: {
|
|
140
|
+
name: 'Rückspülerinnerung: Intervall (Tage)',
|
|
141
|
+
desc: 'Anzahl Tage, nach denen eine Erinnerung für die Rückspülung erfolgt',
|
|
142
|
+
type: 'number',
|
|
143
|
+
role: 'value.interval',
|
|
144
|
+
unit: 'Tage',
|
|
145
|
+
read: true,
|
|
146
|
+
write: true,
|
|
147
|
+
def: 7,
|
|
148
|
+
min: 1,
|
|
149
|
+
max: 60,
|
|
150
|
+
},
|
|
151
|
+
native: {},
|
|
152
|
+
});
|
|
153
|
+
await adapter.setStateAsync('control.pump.backwash_interval_days', { val: 7, ack: true });
|
|
154
|
+
|
|
155
|
+
await adapter.setObjectNotExistsAsync('control.pump.backwash_last_date', {
|
|
156
|
+
type: 'state',
|
|
157
|
+
common: {
|
|
158
|
+
name: 'Letzte Rückspülung (Datum)',
|
|
159
|
+
desc: 'Zeitstempel der letzten ausgeführten Rückspülung, dient der Erinnerungsberechnung',
|
|
160
|
+
type: 'string',
|
|
161
|
+
role: 'date',
|
|
162
|
+
read: true,
|
|
163
|
+
write: false,
|
|
164
|
+
},
|
|
165
|
+
native: {},
|
|
166
|
+
});
|
|
167
|
+
await adapter.setStateAsync('control.pump.backwash_last_date', { val: '', ack: true });
|
|
168
|
+
|
|
169
|
+
await adapter.setObjectNotExistsAsync('control.pump.backwash_required', {
|
|
170
|
+
type: 'state',
|
|
171
|
+
common: {
|
|
172
|
+
name: 'Rückspülung erforderlich',
|
|
173
|
+
desc: 'Wird automatisch auf true gesetzt, wenn die eingestellte Rückspülzeit überschritten wurde',
|
|
174
|
+
type: 'boolean',
|
|
175
|
+
role: 'indicator.alarm',
|
|
176
|
+
read: true,
|
|
177
|
+
write: false,
|
|
178
|
+
def: false,
|
|
179
|
+
},
|
|
180
|
+
native: {},
|
|
181
|
+
});
|
|
182
|
+
await adapter.setStateAsync('control.pump.backwash_required', { val: false, ack: true });
|
|
183
|
+
|
|
184
|
+
// ---------------------------------------------------------------------
|
|
121
185
|
// Wartungsmodus aktiv
|
|
122
186
|
await adapter.setObjectNotExistsAsync('control.pump.maintenance_active', {
|
|
123
187
|
type: 'state',
|
|
@@ -149,6 +149,25 @@ async function createPumpStates(adapter) {
|
|
|
149
149
|
});
|
|
150
150
|
await adapter.setStateAsync('pump.status', { val: 'AUS', ack: true });
|
|
151
151
|
|
|
152
|
+
// Aktiver Helfer (Vorrangsteuerung)
|
|
153
|
+
await adapter.setObjectNotExistsAsync('pump.active_helper', {
|
|
154
|
+
type: 'state',
|
|
155
|
+
common: {
|
|
156
|
+
name: 'Aktiver Helfer (Vorrangsteuerung)',
|
|
157
|
+
desc: 'Zeigt an, welcher Helper aktuell die Vorrangsteuerung der Pumpe übernommen hat (z. B. Control, Solar, Frost, Zeit, Heizung …)',
|
|
158
|
+
type: 'string',
|
|
159
|
+
role: 'text',
|
|
160
|
+
read: true,
|
|
161
|
+
write: false, // Nur intern schreibbar
|
|
162
|
+
hidden: false, // Sichtbar, damit Nutzer den aktiven Helper sehen kann
|
|
163
|
+
},
|
|
164
|
+
native: {},
|
|
165
|
+
});
|
|
166
|
+
await adapter.setStateAsync('pump.active_helper', {
|
|
167
|
+
val: '',
|
|
168
|
+
ack: true,
|
|
169
|
+
});
|
|
170
|
+
|
|
152
171
|
// Pumpenfehler (bool)
|
|
153
172
|
await adapter.setObjectNotExistsAsync('pump.error', {
|
|
154
173
|
type: 'state',
|
package/main.js
CHANGED
|
@@ -15,6 +15,7 @@ const solarHelper = require('./lib/helpers/solarHelper');
|
|
|
15
15
|
const frostHelper = require('./lib/helpers/frostHelper');
|
|
16
16
|
const statusHelper = require('./lib/helpers/statusHelper');
|
|
17
17
|
const controlHelper = require('./lib/helpers/controlHelper');
|
|
18
|
+
const controlHelper2 = require('./lib/helpers/controlHelper2');
|
|
18
19
|
const debugLogHelper = require('./lib/helpers/debugLogHelper');
|
|
19
20
|
const speechTextHelper = require('./lib/helpers/speechTextHelper');
|
|
20
21
|
const { createTemperatureStates } = require('./lib/stateDefinitions/temperatureStates');
|
|
@@ -93,6 +94,7 @@ class Poolcontrol extends utils.Adapter {
|
|
|
93
94
|
frostHelper.init(this);
|
|
94
95
|
statusHelper.init(this);
|
|
95
96
|
controlHelper.init(this);
|
|
97
|
+
controlHelper2.init(this);
|
|
96
98
|
debugLogHelper.init(this);
|
|
97
99
|
speechTextHelper.init(this);
|
|
98
100
|
}
|
|
@@ -129,6 +131,9 @@ class Poolcontrol extends utils.Adapter {
|
|
|
129
131
|
if (controlHelper.cleanup) {
|
|
130
132
|
controlHelper.cleanup();
|
|
131
133
|
}
|
|
134
|
+
if (controlHelper2.cleanup) {
|
|
135
|
+
controlHelper2.cleanup();
|
|
136
|
+
}
|
|
132
137
|
if (speechTextHelper.cleanup) {
|
|
133
138
|
speechTextHelper.cleanup();
|
|
134
139
|
}
|
|
@@ -191,6 +196,9 @@ class Poolcontrol extends utils.Adapter {
|
|
|
191
196
|
if (id.includes('control.')) {
|
|
192
197
|
controlHelper.handleStateChange(id, state);
|
|
193
198
|
}
|
|
199
|
+
if (id.includes('control.')) {
|
|
200
|
+
controlHelper2.handleStateChange(id, state);
|
|
201
|
+
}
|
|
194
202
|
|
|
195
203
|
await debugLogHelper.handleStateChange(id, state);
|
|
196
204
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.poolcontrol",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Steuerung & Automatisierung für den Pool (Pumpe, Heizung, Ventile, Sensoren).",
|
|
5
5
|
"author": "DasBo1975 <dasbo1975@outlook.de>",
|
|
6
6
|
"homepage": "https://github.com/DasBo1975/ioBroker.poolcontrol",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"keywords": [
|
|
9
|
-
"ioBroker",
|
|
9
|
+
"ioBroker",
|
|
10
10
|
"pool",
|
|
11
11
|
"pumpe",
|
|
12
12
|
"solar",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"@iobroker/adapter-core": "^3.3.2"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
+
"@alcalzone/release-script": "^4.0.0",
|
|
27
28
|
"@iobroker/adapter-dev": "^1.5.0",
|
|
28
29
|
"@iobroker/eslint-config": "^2.2.0",
|
|
29
30
|
"@iobroker/testing": "^5.1.1",
|