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 CHANGED
@@ -1,14 +1,18 @@
1
1
  # ioBroker.poolcontrol
2
2
 
3
- ![Test and Release](https://github.com/DasBo1975/iobroker.poolcontrol/actions/workflows/test-and-release.yml/badge.svg)
3
+ ![Test and Release](https://github.com/DasBo1975/ioBroker.poolcontrol/actions/workflows/test-and-release.yml/badge.svg)
4
4
  ![npm](https://img.shields.io/npm/v/iobroker.poolcontrol?color=blue)
5
5
  ![Downloads](https://img.shields.io/npm/dm/iobroker.poolcontrol)
6
6
  ![Installs](https://iobroker.live/badges/poolcontrol-installed.svg)
7
7
  ![Stable](https://iobroker.live/badges/poolcontrol-stable.svg)
8
8
  [![License](https://img.shields.io/github/license/DasBo1975/ioBroker.poolcontrol?cacheSeconds=3600)](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, Temperatur- und Solarsteuerung sowie Verbrauchsauswertung.
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
- - Optional Sprachausgabe bei Warnung
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
- **Hinweis:**
45
- 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).
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
- - **Systemcheck (Diagnosebereich)**
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, etc.
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, bitte regelmäßig den Changelog beachten.
112
+ Funktionen können sich ändern bitte regelmäßig den Changelog beachten.
98
113
 
99
114
  ---
100
115
 
101
116
  ## Dokumentation
102
- - [Help.md (ausführliche Beschreibung und Hinweise)](./help.md)
117
+ - [help.md (ausführliche Beschreibung und Hinweise)](./help.md)
103
118
 
104
119
  ---
105
120
 
106
121
  ## Changelog
107
- Auszug, vollständige Liste siehe `io-package.json`:
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.1.0
128
- - Sprachausgabe über **E-Mail** hinzugefügt (konfigurierbar: Instanz, Empfänger, Betreff).
129
- - Erweiterung der Instanz-Konfiguration im Tab „Sprachausgaben“.
130
- **Bugfixes**
131
- - Kleinere Korrekturen und Optimierungen in der Dokumentation (`help.md`).
132
- - Logging in `speechHelper` verbessert.
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
- ### 0.0.10
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.7
162
- - Help-Datei (`help.md`) und erste README-Version hinzugefügt
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
- ### 0.0.1
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.1",
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
- "0.1.0": {
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 pumpStatus = (await this.adapter.getStateAsync('pump.status'))?.val || '';
37
- if (pumpStatus.includes('controlHelper')) {
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 pumpStatus = (await this.adapter.getStateAsync('pump.status'))?.val || '';
37
- if (pumpStatus.includes('controlHelper')) {
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.1",
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",