iobroker.poolcontrol 0.3.0 → 0.4.0-alpha
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 +32 -18
- package/admin/jsonConfig.json +4 -0
- package/io-package.json +28 -15
- package/lib/helpers/consumptionHelper.js +27 -32
- package/lib/helpers/frostHelper.js +11 -11
- package/lib/helpers/pumpHelper.js +22 -12
- package/lib/helpers/pumpHelper2.js +18 -16
- package/lib/helpers/pumpHelper3.js +52 -17
- package/lib/helpers/runtimeHelper.js +141 -43
- package/lib/helpers/statisticsHelper.js +448 -0
- package/lib/stateDefinitions/controlStates.js +0 -37
- package/lib/stateDefinitions/pumpStates3.js +63 -11
- package/lib/stateDefinitions/runtimeStates.js +20 -5
- package/lib/stateDefinitions/statisticsStates.js +138 -0
- package/main.js +10 -1
- package/package.json +5 -3
|
@@ -21,9 +21,24 @@ const runtimeHelper = {
|
|
|
21
21
|
resetTimer: null,
|
|
22
22
|
liveTimer: null, // Timer für Live-Updates
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Initialisiert den Runtime-Helper.
|
|
26
|
+
* Führt eine kurze Startverzögerung ein, um sicherzustellen,
|
|
27
|
+
* dass persistente States nach einer Überinstallation korrekt geladen werden.
|
|
28
|
+
*
|
|
29
|
+
* @param {ioBroker.Adapter} adapter - Aktive ioBroker-Adapterinstanz.
|
|
30
|
+
* @returns {Promise<void>}
|
|
31
|
+
*/
|
|
32
|
+
async init(adapter) {
|
|
25
33
|
this.adapter = adapter;
|
|
26
34
|
|
|
35
|
+
// ------------------------------------------------------
|
|
36
|
+
// NEU: Kurze Startverzögerung, damit ioBroker persistente States
|
|
37
|
+
// vollständig aus der Datenbank laden kann (Überinstallationsschutz)
|
|
38
|
+
// ------------------------------------------------------
|
|
39
|
+
this.adapter.log.debug('[runtimeHelper] Warte 3 Sekunden, um persistente States zu laden ...');
|
|
40
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
41
|
+
|
|
27
42
|
// Pumpenschalter überwachen
|
|
28
43
|
this.adapter.subscribeStates('pump.pump_switch');
|
|
29
44
|
|
|
@@ -52,6 +67,13 @@ const runtimeHelper = {
|
|
|
52
67
|
const seasonRaw = (await this.adapter.getStateAsync('runtime.season_total'))?.val;
|
|
53
68
|
const countRaw = (await this.adapter.getStateAsync('runtime.start_count_today'))?.val;
|
|
54
69
|
|
|
70
|
+
// FIX: Falls States leer oder neu angelegt sind, Warnhinweis ausgeben und Werte nicht überschreiben
|
|
71
|
+
if (!totalRaw && !seasonRaw) {
|
|
72
|
+
this.adapter.log.info(
|
|
73
|
+
'[runtimeHelper] Keine gespeicherten Laufzeiten gefunden – möglicherweise neue oder überinstallierte Instanz. Laufzeiten starten bei 0.',
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
55
77
|
// >>> NEU: Formatierten Text (z. B. "3h 12m 5s") in Sekunden umwandeln
|
|
56
78
|
this.runtimeTotal = this._parseFormattedTimeToSeconds(totalRaw);
|
|
57
79
|
this.runtimeToday = this._parseFormattedTimeToSeconds(todayRaw);
|
|
@@ -72,38 +94,72 @@ const runtimeHelper = {
|
|
|
72
94
|
return;
|
|
73
95
|
}
|
|
74
96
|
|
|
97
|
+
// FIX: Robuste Start-/Stop-Logik für pump.pump_switch
|
|
75
98
|
if (id.endsWith('pump.pump_switch')) {
|
|
76
|
-
if (state.val
|
|
77
|
-
// Pumpe
|
|
78
|
-
this.isRunning
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
this.
|
|
99
|
+
if (state.val) {
|
|
100
|
+
// FIX: Immer starten, wenn Pumpe an ist (egal welcher Helper)
|
|
101
|
+
if (!this.isRunning || !this.lastOn) {
|
|
102
|
+
this.isRunning = true;
|
|
103
|
+
this.lastOn = Date.now();
|
|
104
|
+
this.startCountToday += 1;
|
|
105
|
+
|
|
106
|
+
// Live-Timer starten (jede Minute)
|
|
107
|
+
this._startLiveTimer();
|
|
108
|
+
|
|
109
|
+
// Start sofort in State schreiben
|
|
110
|
+
await this.adapter.setStateAsync('runtime.start_count_today', {
|
|
111
|
+
val: this.startCountToday,
|
|
112
|
+
ack: true,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// ------------------------------------------------------
|
|
116
|
+
// Statuswerte bei Pumpenstart setzen
|
|
117
|
+
// ------------------------------------------------------
|
|
118
|
+
const nowStr = new Date().toLocaleString();
|
|
119
|
+
await this.adapter.setStateAsync('status.pump_last_start', { val: nowStr, ack: true });
|
|
120
|
+
await this.adapter.setStateAsync('status.pump_today_count', {
|
|
121
|
+
val: this.startCountToday,
|
|
122
|
+
ack: true,
|
|
123
|
+
});
|
|
124
|
+
await this.adapter.setStateAsync('status.pump_was_on_today', { val: true, ack: true });
|
|
125
|
+
// ------------------------------------------------------
|
|
126
|
+
this.adapter.log.debug('[runtimeHelper] Pumpenlaufzeit gestartet.');
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
// FIX: Immer sauber stoppen, wenn Pumpe aus ist
|
|
130
|
+
if (this.isRunning && this.lastOn) {
|
|
131
|
+
const delta = Math.floor((Date.now() - this.lastOn) / 1000);
|
|
132
|
+
this.runtimeToday += delta;
|
|
133
|
+
this.runtimeTotal += delta;
|
|
134
|
+
|
|
135
|
+
// Saisonlaufzeit nur zählen, wenn aktiv
|
|
136
|
+
const seasonActive = !!(await this.adapter.getStateAsync('control.season.active'))?.val;
|
|
137
|
+
if (seasonActive) {
|
|
138
|
+
this.runtimeSeason += delta;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
this.isRunning = false;
|
|
142
|
+
this.lastOn = null;
|
|
143
|
+
|
|
144
|
+
// Live-Timer stoppen
|
|
145
|
+
this._stopLiveTimer();
|
|
146
|
+
|
|
147
|
+
// States final aktualisieren
|
|
148
|
+
await this._updateStates();
|
|
149
|
+
|
|
150
|
+
// ------------------------------------------------------
|
|
151
|
+
// Statuswert bei Pumpenstopp setzen
|
|
152
|
+
// ------------------------------------------------------
|
|
153
|
+
const nowStr = new Date().toLocaleString();
|
|
154
|
+
await this.adapter.setStateAsync('status.pump_last_stop', { val: nowStr, ack: true });
|
|
155
|
+
// ------------------------------------------------------
|
|
156
|
+
this.adapter.log.debug('[runtimeHelper] Pumpenlaufzeit gestoppt.');
|
|
157
|
+
} else {
|
|
158
|
+
// FIX: Falls Pumpe aus, aber kein aktiver Lauf (z. B. Neustart) → nur Timer sicher stoppen
|
|
159
|
+
this._stopLiveTimer();
|
|
160
|
+
this.isRunning = false;
|
|
161
|
+
this.lastOn = null;
|
|
97
162
|
}
|
|
98
|
-
|
|
99
|
-
this.isRunning = false;
|
|
100
|
-
this.lastOn = null;
|
|
101
|
-
|
|
102
|
-
// Live-Timer stoppen
|
|
103
|
-
this._stopLiveTimer();
|
|
104
|
-
|
|
105
|
-
// States final aktualisieren
|
|
106
|
-
await this._updateStates();
|
|
107
163
|
}
|
|
108
164
|
}
|
|
109
165
|
},
|
|
@@ -134,6 +190,16 @@ const runtimeHelper = {
|
|
|
134
190
|
await this.adapter.setStateAsync('runtime.season_total', { val: formattedSeason, ack: true });
|
|
135
191
|
await this.adapter.setStateAsync('runtime.start_count_today', { val: this.startCountToday, ack: true });
|
|
136
192
|
|
|
193
|
+
// Poolparameter laden (vor Durchflussprüfung!)
|
|
194
|
+
const poolSize = (await this.adapter.getStateAsync('general.pool_size'))?.val || 0;
|
|
195
|
+
const minCirc = (await this.adapter.getStateAsync('general.min_circulation_per_day'))?.val || 1;
|
|
196
|
+
|
|
197
|
+
// daily_required immer direkt setzen – auch ohne Durchfluss
|
|
198
|
+
const dailyRequired = Math.round(poolSize * minCirc);
|
|
199
|
+
if (dailyRequired > 0) {
|
|
200
|
+
await this.adapter.setStateAsync('circulation.daily_required', { val: dailyRequired, ack: true });
|
|
201
|
+
}
|
|
202
|
+
|
|
137
203
|
// Umwälzmenge berechnen
|
|
138
204
|
// Reeller Durchflusswert aus pump.live.flow_current_lh
|
|
139
205
|
const liveFlowLh = (await this.adapter.getStateAsync('pump.live.flow_current_lh'))?.val || 0;
|
|
@@ -143,19 +209,26 @@ const runtimeHelper = {
|
|
|
143
209
|
return;
|
|
144
210
|
}
|
|
145
211
|
|
|
146
|
-
// Poolparameter laden
|
|
147
|
-
const poolSize = (await this.adapter.getStateAsync('general.pool_size'))?.val || 0;
|
|
148
|
-
const minCirc = (await this.adapter.getStateAsync('general.min_circulation_per_day'))?.val || 1;
|
|
149
|
-
|
|
150
212
|
// Berechnung der realen Tagesumwälzung (Liter)
|
|
151
213
|
const dailyTotal = Math.round((effectiveToday / 3600) * liveFlowLh);
|
|
152
|
-
const dailyRequired = Math.round(poolSize * minCirc);
|
|
153
214
|
const dailyRemaining = Math.max(dailyRequired - dailyTotal, 0);
|
|
154
215
|
|
|
155
|
-
// Werte
|
|
156
|
-
await this.adapter.
|
|
157
|
-
await this.adapter.
|
|
158
|
-
|
|
216
|
+
// Bestehende Werte für Total/Remaining laden
|
|
217
|
+
const oldTotal = (await this.adapter.getStateAsync('circulation.daily_total'))?.val || 0;
|
|
218
|
+
const oldRemaining = (await this.adapter.getStateAsync('circulation.daily_remaining'))?.val || 0;
|
|
219
|
+
|
|
220
|
+
// Nur schreiben, wenn tatsächlich sinnvolle Livewerte vorliegen
|
|
221
|
+
if (liveFlowLh > 0 && dailyTotal > 0) {
|
|
222
|
+
await this.adapter.setStateAsync('circulation.daily_total', { val: dailyTotal, ack: true });
|
|
223
|
+
await this.adapter.setStateAsync('circulation.daily_remaining', { val: dailyRemaining, ack: true });
|
|
224
|
+
this.adapter.log.debug(
|
|
225
|
+
`[runtimeHelper] Circulation-Werte aktualisiert (Total=${dailyTotal}, Required=${dailyRequired}, Remaining=${dailyRemaining})`,
|
|
226
|
+
);
|
|
227
|
+
} else {
|
|
228
|
+
this.adapter.log.debug(
|
|
229
|
+
`[runtimeHelper] Keine gültigen Live-Daten – bestehende Werte bleiben erhalten (Total=${oldTotal}, Required=${dailyRequired}, Remaining=${oldRemaining})`,
|
|
230
|
+
);
|
|
231
|
+
}
|
|
159
232
|
} catch (err) {
|
|
160
233
|
this.adapter.log.warn(`[runtimeHelper] Fehler beim Update der States: ${err.message}`);
|
|
161
234
|
}
|
|
@@ -204,12 +277,37 @@ const runtimeHelper = {
|
|
|
204
277
|
nextMidnight.setHours(24, 0, 0, 0);
|
|
205
278
|
const msUntilMidnight = nextMidnight - now;
|
|
206
279
|
|
|
207
|
-
this.resetTimer = setTimeout(() => {
|
|
280
|
+
this.resetTimer = setTimeout(async () => {
|
|
208
281
|
this.runtimeToday = 0;
|
|
209
282
|
this.startCountToday = 0;
|
|
210
283
|
this.lastOn = this.isRunning ? Date.now() : null;
|
|
284
|
+
|
|
285
|
+
// Laufzeiten zurücksetzen
|
|
211
286
|
this._updateStates();
|
|
287
|
+
|
|
288
|
+
// --- NEU: Circulation-Werte um Mitternacht zurücksetzen ---
|
|
289
|
+
await this.adapter.setStateAsync('circulation.daily_total', { val: 0, ack: true });
|
|
290
|
+
|
|
291
|
+
// daily_required neu berechnen (optional, falls sich Poolgröße geändert hat)
|
|
292
|
+
const poolSize = (await this.adapter.getStateAsync('general.pool_size'))?.val || 0;
|
|
293
|
+
const minCirc = (await this.adapter.getStateAsync('general.min_circulation_per_day'))?.val || 1;
|
|
294
|
+
const dailyRequired = Math.round(poolSize * minCirc);
|
|
295
|
+
await this.adapter.setStateAsync('circulation.daily_required', { val: dailyRequired, ack: true });
|
|
296
|
+
|
|
297
|
+
// 👉 daily_remaining neue berechnen auf Grundlage von daily_required
|
|
298
|
+
await this.adapter.setStateAsync('circulation.daily_remaining', { val: dailyRequired, ack: true });
|
|
299
|
+
|
|
300
|
+
// ------------------------------------------------------
|
|
301
|
+
// NEU: Pumpenstatuswerte um Mitternacht zurücksetzen
|
|
302
|
+
// ------------------------------------------------------
|
|
303
|
+
await this.adapter.setStateAsync('status.pump_today_count', { val: 0, ack: true });
|
|
304
|
+
await this.adapter.setStateAsync('status.pump_was_on_today', { val: false, ack: true });
|
|
305
|
+
// ------------------------------------------------------
|
|
306
|
+
|
|
307
|
+
// Nächsten Reset planen
|
|
212
308
|
this._scheduleDailyReset();
|
|
309
|
+
|
|
310
|
+
this.adapter.log.debug('[runtimeHelper] Tagesreset (Runtime + Circulation) ausgeführt.');
|
|
213
311
|
}, msUntilMidnight);
|
|
214
312
|
},
|
|
215
313
|
|
|
@@ -217,8 +315,8 @@ const runtimeHelper = {
|
|
|
217
315
|
if (this.liveTimer) {
|
|
218
316
|
clearInterval(this.liveTimer);
|
|
219
317
|
}
|
|
220
|
-
this.liveTimer = setInterval(() => this._updateStates(),
|
|
221
|
-
this.adapter.log.debug('[runtimeHelper] Live-Timer gestartet (Updates
|
|
318
|
+
this.liveTimer = setInterval(() => this._updateStates(), 10 * 1000);
|
|
319
|
+
this.adapter.log.debug('[runtimeHelper] Live-Timer gestartet (Updates alle 10 Sekunden)');
|
|
222
320
|
},
|
|
223
321
|
|
|
224
322
|
_stopLiveTimer() {
|