iobroker.poolcontrol 1.3.13 → 1.3.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -11
- package/io-package.json +14 -14
- package/lib/helpers/runtimeHelper.js +90 -22
- package/lib/stateDefinitions/runtimeStates.js +108 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -188,6 +188,14 @@ New features are added regularly – please refer to the changelog.
|
|
|
188
188
|
---
|
|
189
189
|
|
|
190
190
|
## Changelog
|
|
191
|
+
### 1.3.14 (2026-05-08)
|
|
192
|
+
|
|
193
|
+
- Improved runtime handling and persistence
|
|
194
|
+
- Fixed season runtime calculation using the correct season state
|
|
195
|
+
- Unified live runtime calculations for total, today and season values
|
|
196
|
+
- Added numeric runtime second states for robust persistence and recovery
|
|
197
|
+
- Converted runtime timers to adapter-managed timers for improved ioBroker compatibility
|
|
198
|
+
|
|
191
199
|
### 1.3.13 (2026-05-08)
|
|
192
200
|
- (copilot) Adapter requires node.js >= 22 now
|
|
193
201
|
- Fixed invalid `common.installedFrom` entry in `io-package.json`
|
|
@@ -293,17 +301,6 @@ Fix: PV Circulation Logic
|
|
|
293
301
|
- Fixed issue where pump stopped despite `photovoltaic.ignore_on_circulation = false`
|
|
294
302
|
- Circulation check is now only applied when explicitly enabled
|
|
295
303
|
|
|
296
|
-
### 1.3.9 (2026-04-24)
|
|
297
|
-
|
|
298
|
-
- Fix: solarLogbookHelper no longer creates duplicate or unnecessary log entries (improved filtering & throttling logic)
|
|
299
|
-
- Fix: Removed obsolete "no runtime today" entries once solar has actually run
|
|
300
|
-
- Fix: Improved handling of weather summary text to avoid broken or cut-off sentences
|
|
301
|
-
- Fix: solarLogbookHelper now updates `last_entry_time` only when a real log entry is written
|
|
302
|
-
- Fix: solarInsightsHelper runtime calculation improved (no incorrect time accumulation on state changes)
|
|
303
|
-
- Fix: solarInsightsHelper now correctly tracks previous solar state for more accurate active time calculation
|
|
304
|
-
- Fix: Added missing `debug.last_update` update on successful calculation
|
|
305
|
-
- Improvement: General stability and plausibility improvements in solar insights and logbook processing
|
|
306
|
-
|
|
307
304
|
## Support
|
|
308
305
|
- [ioBroker Forum](https://forum.iobroker.net/)
|
|
309
306
|
- [GitHub Issues](https://github.com/DasBo1975/ioBroker.poolcontrol/issues)
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "poolcontrol",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.14",
|
|
5
5
|
"news": {
|
|
6
|
+
"1.3.14": {
|
|
7
|
+
"en": "Improved runtime handling and persistence. Fixed season runtime calculation to use the correct season state, improved live runtime updates, added robust numeric runtime second states for safer persistence and recovery, and converted runtime timers to adapter-managed timers for better ioBroker compatibility.",
|
|
8
|
+
"de": "Laufzeit-Handling und Persistenz verbessert. Saisonlaufzeit nutzt jetzt den korrekten Saison-Status, Live-Laufzeiten wurden vereinheitlicht, robuste Sekunden-States fuer Laufzeiten zur sicheren Wiederherstellung hinzugefuegt und Runtime-Timer auf adapterverwaltete Timer fuer bessere ioBroker-Kompatibilitaet umgestellt.",
|
|
9
|
+
"ru": "Улучшена обработка и сохранение во время выполнения. Исправлен расчет времени выполнения сезона для использования правильного состояния сезона, улучшены обновления времени выполнения в режиме реального времени, добавлены надежные числовые значения второго состояния времени выполнения для более безопасного сохранения и восстановления, а также преобразованы таймеры времени выполнения в таймеры, управляемые адаптером, для лучшей совместимости с ioBroker.",
|
|
10
|
+
"pt": "Melhor manipulação e persistência do tempo de execução. Cálculo de tempo de execução de temporada corrigido para usar o estado de temporada correto, atualizações de tempo de execução ao vivo aprimoradas, segundos estados de tempo de execução numéricos robustos adicionados para persistência e recuperação mais seguras e temporizadores de tempo de execução convertidos em temporizadores gerenciados por adaptador para melhor compatibilidade com ioBroker.",
|
|
11
|
+
"nl": "Verbeterde runtime-afhandeling en persistentie. Vaste seizoensruntimeberekening om de juiste seizoensstatus te gebruiken, verbeterde live runtime-updates, robuuste numerieke runtime-secondestatussen toegevoegd voor veiliger persistentie en herstel, en geconverteerde runtime-timers naar door adapter beheerde timers voor betere ioBroker-compatibiliteit.",
|
|
12
|
+
"fr": "Gestion de l'exécution et persistance améliorées. Correction du calcul de la durée d'exécution de la saison pour utiliser l'état de saison correct, mises à jour d'exécution en direct améliorées, ajout de seconds états d'exécution numériques robustes pour une persistance et une récupération plus sûres, et conversion des minuteries d'exécution en minuteries gérées par l'adaptateur pour une meilleure compatibilité ioBroker.",
|
|
13
|
+
"it": "Gestione e persistenza del runtime migliorate. Risolto il problema con il calcolo del runtime della stagione per utilizzare lo stato della stagione corretto, aggiornamenti migliorati del runtime in tempo reale, aggiunti robusti secondi stati di runtime numerici per persistenza e ripristino più sicuri e timer di runtime convertiti in timer gestiti dall'adattatore per una migliore compatibilità con ioBroker.",
|
|
14
|
+
"es": "Manejo y persistencia del tiempo de ejecución mejorados. Se corrigió el cálculo del tiempo de ejecución de la temporada para usar el estado correcto de la temporada, se mejoraron las actualizaciones del tiempo de ejecución en vivo, se agregaron segundos estados de tiempo de ejecución numéricos sólidos para una persistencia y recuperación más seguras y se convirtieron los temporizadores de tiempo de ejecución en temporizadores administrados por adaptador para una mejor compatibilidad con ioBroker.",
|
|
15
|
+
"pl": "Poprawiona obsługa i trwałość środowiska wykonawczego. Naprawiono obliczanie czasu wykonania sezonu w celu wykorzystania prawidłowego stanu sezonu, ulepszono aktualizacje czasu działania na żywo, dodano solidne numeryczne drugie stany czasu działania dla bezpieczniejszej trwałości i odzyskiwania oraz przekonwertowano liczniki czasu działania na zegary zarządzane przez adapter dla lepszej kompatybilności z ioBroker.",
|
|
16
|
+
"uk": "Покращена обробка та збереження часу виконання. Виправлено розрахунок часу виконання сезону для використання правильного стану сезону, покращено поточні оновлення середовища виконання, додано надійні численні секунди часу виконання для безпечнішого збереження та відновлення, а також перетворено таймери часу виконання на таймери, керовані адаптером, для кращої сумісності з ioBroker.",
|
|
17
|
+
"zh-cn": "改进了运行时处理和持久性。修复了季节运行时计算以使用正确的季节状态,改进了实时运行时更新,添加了强大的数字运行时第二状态以实现更安全的持久性和恢复,并将运行时计时器转换为适配器管理的计时器以实现更好的 ioBroker 兼容性。"
|
|
18
|
+
},
|
|
6
19
|
"1.3.13": {
|
|
7
20
|
"en": "Added German and English function overview documentation. Fixed invalid common.installedFrom entry in io-package.json.",
|
|
8
21
|
"de": "Deutsche und englische Funktionsübersicht ergänzt. Ungültigen common.installedFrom-Eintrag in der io-package.json korrigiert.",
|
|
@@ -54,19 +67,6 @@
|
|
|
54
67
|
"pl": "Dodano statystyki fotowoltaiczne (czas pracy, energia, oszczędności) z nowymi stanami analitycznymi i pomocą. Ulepszona obsługa własności active_helper w przypadku fotowoltaiki, energii słonecznej i rozszerzonych pomocników energii słonecznej. Naprawiono logikę cyrkulacji PV, gdy ignorowanie_cyrkulacji jest wyłączone.",
|
|
55
68
|
"uk": "Додано статистику фотоелектричної системи (час роботи, енергія, економія) з новими аналітичними станами та помічником. Покращено керування правами власності active_helper на фотоелектричні, сонячні та розширені сонячні помічники. Виправлена логіка циркуляції PV, коли ignore_on_circulation вимкнено.",
|
|
56
69
|
"zh-cn": "通过新的分析状态和帮助器添加了光伏见解(运行时间、能源、节省)。改进了跨光伏、太阳能和扩展太阳能助手的 active_helper 所有权处理。修复了禁用ignore_on_circulation时的PV循环逻辑。"
|
|
57
|
-
},
|
|
58
|
-
"1.3.9": {
|
|
59
|
-
"en": "Fix solar logbook duplication and invalid entries, improve log stability and weather text handling; fix solar insights runtime calculation and debug timestamp update.",
|
|
60
|
-
"de": "Behebung von doppelten und ungültigen Solar-Logbuch-Einträgen, Verbesserung der Log-Stabilität und Wettertext-Verarbeitung; Korrektur der Laufzeitberechnung im Solar-Insights-Bereich sowie Aktualisierung des Debug-Zeitstempels.",
|
|
61
|
-
"ru": "Исправьте дублирование журнала солнечной энергии и неверные записи, улучшите стабильность журнала и обработку текста о погоде; исправить расчет времени выполнения Solar Insights и обновить временную метку отладки.",
|
|
62
|
-
"pt": "Corrija a duplicação do diário de bordo solar e entradas inválidas, melhore a estabilidade do registro e o manuseio de textos meteorológicos; corrigir o cálculo do tempo de execução do Solar Insights e depurar a atualização do carimbo de data/hora.",
|
|
63
|
-
"nl": "Herstel het dupliceren van zonnelogboeken en ongeldige vermeldingen, verbeter de logstabiliteit en de verwerking van weerteksten; runtimeberekening van zonne-inzichten repareren en tijdstempelupdate debuggen.",
|
|
64
|
-
"fr": "Corrigez la duplication du journal solaire et les entrées invalides, améliorez la stabilité du journal et la gestion des textes météorologiques ; correction du calcul d'exécution des informations solaires et de la mise à jour de l'horodatage de débogage.",
|
|
65
|
-
"it": "Correggere la duplicazione del registro solare e le voci non valide, migliorare la stabilità del registro e la gestione del testo meteorologico; correggere il calcolo del runtime di Solar Insights e l'aggiornamento del timestamp di debug.",
|
|
66
|
-
"es": "Corrija la duplicación del libro de registro solar y las entradas no válidas, mejore la estabilidad del registro y el manejo de textos meteorológicos; corrige el cálculo del tiempo de ejecución de Solar Insights y la actualización de la marca de tiempo de depuración.",
|
|
67
|
-
"pl": "Napraw duplikację dziennika słonecznego i nieprawidłowe wpisy, popraw stabilność dziennika i obsługę tekstu pogodowego; napraw obliczenia czasu działania Solar Insights i aktualizację znacznika czasu debugowania.",
|
|
68
|
-
"uk": "Виправте дублювання сонячного журналу та недійсні записи, покращте стабільність журналу та обробку тексту погоди; виправити розрахунок часу виконання solar insights і налагодити оновлення часових позначок.",
|
|
69
|
-
"zh-cn": "修复太阳能日志重复和无效条目,提高日志稳定性和天气文本处理;修复 Solar Insights 运行时计算和调试时间戳更新。"
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
72
|
"titleLang": {
|
|
@@ -18,6 +18,7 @@ const runtimeHelper = {
|
|
|
18
18
|
runtimeToday: 0, // Tageszeit (s)
|
|
19
19
|
runtimeSeason: 0, // Laufzeit der aktuellen Saison (s)
|
|
20
20
|
startCountToday: 0, // Anzahl Starts heute
|
|
21
|
+
restoreTimer: null, // FIX: ioBroker timer for delayed restore
|
|
21
22
|
resetTimer: null,
|
|
22
23
|
liveTimer: null, // Timer für Live-Updates
|
|
23
24
|
|
|
@@ -37,7 +38,12 @@ const runtimeHelper = {
|
|
|
37
38
|
// vollständig aus der Datenbank laden kann (Überinstallationsschutz)
|
|
38
39
|
// ------------------------------------------------------
|
|
39
40
|
this.adapter.log.debug('[runtimeHelper] Waiting 3 seconds to load persistent states ...');
|
|
40
|
-
await new Promise(resolve =>
|
|
41
|
+
await new Promise(resolve => {
|
|
42
|
+
this.restoreTimer = this.adapter.setTimeout(() => {
|
|
43
|
+
this.restoreTimer = null;
|
|
44
|
+
resolve();
|
|
45
|
+
}, 3000);
|
|
46
|
+
});
|
|
41
47
|
|
|
42
48
|
// Pumpenschalter überwachen
|
|
43
49
|
this.adapter.subscribeStates('pump.pump_switch');
|
|
@@ -65,21 +71,24 @@ const runtimeHelper = {
|
|
|
65
71
|
const totalRaw = (await this.adapter.getStateAsync('runtime.total'))?.val;
|
|
66
72
|
const todayRaw = (await this.adapter.getStateAsync('runtime.today'))?.val;
|
|
67
73
|
const seasonRaw = (await this.adapter.getStateAsync('runtime.season_total'))?.val;
|
|
68
|
-
const countRaw = (await this.adapter.getStateAsync('runtime.start_count_today'))?.val;
|
|
69
74
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
75
|
+
const totalSecondsRaw = (await this.adapter.getStateAsync('runtime.total_seconds'))?.val;
|
|
76
|
+
const todaySecondsRaw = (await this.adapter.getStateAsync('runtime.today_seconds'))?.val;
|
|
77
|
+
const seasonSecondsRaw = (await this.adapter.getStateAsync('runtime.season_total_seconds'))?.val;
|
|
78
|
+
|
|
79
|
+
const countRaw = (await this.adapter.getStateAsync('runtime.start_count_today'))?.val;
|
|
76
80
|
|
|
77
|
-
//
|
|
78
|
-
this.runtimeTotal = this.
|
|
79
|
-
this.runtimeToday = this.
|
|
80
|
-
this.runtimeSeason = this.
|
|
81
|
+
// FIX: Restore prefers robust numeric seconds states and falls back to formatted legacy text states.
|
|
82
|
+
this.runtimeTotal = this._restoreRuntimeValue(totalSecondsRaw, totalRaw, 'runtime.total');
|
|
83
|
+
this.runtimeToday = this._restoreRuntimeValue(todaySecondsRaw, todayRaw, 'runtime.today');
|
|
84
|
+
this.runtimeSeason = this._restoreRuntimeValue(seasonSecondsRaw, seasonRaw, 'runtime.season_total');
|
|
81
85
|
this.startCountToday = Number(countRaw) || 0;
|
|
82
86
|
|
|
87
|
+
await this.adapter.setStateAsync('runtime.total_seconds', { val: this.runtimeTotal, ack: true });
|
|
88
|
+
await this.adapter.setStateAsync('runtime.today_seconds', { val: this.runtimeToday, ack: true });
|
|
89
|
+
await this.adapter.setStateAsync('runtime.season_total_seconds', { val: this.runtimeSeason, ack: true });
|
|
90
|
+
await this.adapter.setStateAsync('runtime.current_session_seconds', { val: 0, ack: true });
|
|
91
|
+
|
|
83
92
|
// Falls Pumpe gerade läuft → Status wiederherstellen
|
|
84
93
|
const active = !!(await this.adapter.getStateAsync('pump.pump_switch'))?.val;
|
|
85
94
|
if (active) {
|
|
@@ -132,8 +141,8 @@ const runtimeHelper = {
|
|
|
132
141
|
this.runtimeToday += delta;
|
|
133
142
|
this.runtimeTotal += delta;
|
|
134
143
|
|
|
135
|
-
//
|
|
136
|
-
const seasonActive =
|
|
144
|
+
// FIX: Use the actual season state used by the adapter; keep legacy fallback if it exists.
|
|
145
|
+
const seasonActive = await this._isSeasonActive();
|
|
137
146
|
if (seasonActive) {
|
|
138
147
|
this.runtimeSeason += delta;
|
|
139
148
|
}
|
|
@@ -167,20 +176,27 @@ const runtimeHelper = {
|
|
|
167
176
|
async _updateStates() {
|
|
168
177
|
try {
|
|
169
178
|
// Falls Pumpe läuft → temporäre Laufzeit seit lastOn einrechnen
|
|
179
|
+
const seasonActive = await this._isSeasonActive();
|
|
180
|
+
let effectiveTotal = this.runtimeTotal;
|
|
170
181
|
let effectiveToday = this.runtimeToday;
|
|
171
182
|
let effectiveSeason = this.runtimeSeason;
|
|
172
183
|
let currentSessionSeconds = 0;
|
|
173
184
|
|
|
174
185
|
if (this.isRunning && this.lastOn) {
|
|
175
186
|
const delta = Math.floor((Date.now() - this.lastOn) / 1000);
|
|
187
|
+
// FIX: Show the currently running session consistently in total and today.
|
|
188
|
+
effectiveTotal += delta;
|
|
176
189
|
effectiveToday += delta;
|
|
177
|
-
|
|
190
|
+
// FIX: Only show the running session in season_total while the same season status is active.
|
|
191
|
+
if (seasonActive) {
|
|
192
|
+
effectiveSeason += delta;
|
|
193
|
+
}
|
|
178
194
|
currentSessionSeconds = delta;
|
|
179
195
|
}
|
|
180
196
|
|
|
181
197
|
// Formatiert schreiben
|
|
182
198
|
const formattedToday = this._formatTime(effectiveToday);
|
|
183
|
-
const formattedTotal = this._formatTime(
|
|
199
|
+
const formattedTotal = this._formatTime(effectiveTotal);
|
|
184
200
|
const formattedSeason = this._formatTime(effectiveSeason);
|
|
185
201
|
const formattedCurrent = this._formatTime(currentSessionSeconds);
|
|
186
202
|
|
|
@@ -188,6 +204,16 @@ const runtimeHelper = {
|
|
|
188
204
|
await this.adapter.setStateAsync('runtime.today', { val: formattedToday, ack: true });
|
|
189
205
|
await this.adapter.setStateAsync('runtime.current_session', { val: formattedCurrent, ack: true });
|
|
190
206
|
await this.adapter.setStateAsync('runtime.season_total', { val: formattedSeason, ack: true });
|
|
207
|
+
|
|
208
|
+
// FIX: Write robust numeric seconds states in parallel to existing formatted text states.
|
|
209
|
+
await this.adapter.setStateAsync('runtime.total_seconds', { val: effectiveTotal, ack: true });
|
|
210
|
+
await this.adapter.setStateAsync('runtime.today_seconds', { val: effectiveToday, ack: true });
|
|
211
|
+
await this.adapter.setStateAsync('runtime.current_session_seconds', {
|
|
212
|
+
val: currentSessionSeconds,
|
|
213
|
+
ack: true,
|
|
214
|
+
});
|
|
215
|
+
await this.adapter.setStateAsync('runtime.season_total_seconds', { val: effectiveSeason, ack: true });
|
|
216
|
+
|
|
191
217
|
await this.adapter.setStateAsync('runtime.start_count_today', { val: this.startCountToday, ack: true });
|
|
192
218
|
|
|
193
219
|
// Poolparameter laden (vor Durchflussprüfung!)
|
|
@@ -242,6 +268,38 @@ const runtimeHelper = {
|
|
|
242
268
|
return `${h}h ${m}m ${s}s`;
|
|
243
269
|
},
|
|
244
270
|
|
|
271
|
+
_restoreRuntimeValue(secondsRaw, formattedRaw, stateName) {
|
|
272
|
+
const seconds = Number(secondsRaw);
|
|
273
|
+
if (Number.isFinite(seconds) && seconds > 0) {
|
|
274
|
+
return Math.floor(seconds);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const parsed = this._parseFormattedTimeToSeconds(formattedRaw);
|
|
278
|
+
if (parsed > 0) {
|
|
279
|
+
return parsed;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (formattedRaw && String(formattedRaw).trim() !== '0h 0m 0s') {
|
|
283
|
+
this.adapter.log.warn(
|
|
284
|
+
`[runtimeHelper] Could not restore ${stateName} from value "${formattedRaw}". Keeping runtime at 0.`,
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return 0;
|
|
289
|
+
},
|
|
290
|
+
|
|
291
|
+
async _isSeasonActive() {
|
|
292
|
+
// FIX: status.season_active is the canonical season state used by the adapter.
|
|
293
|
+
const statusSeason = await this.adapter.getStateAsync('status.season_active');
|
|
294
|
+
if (statusSeason && statusSeason.val !== null && statusSeason.val !== undefined) {
|
|
295
|
+
return !!statusSeason.val;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// FIX: Keep a backward-compatible fallback for installations that still provide this legacy state.
|
|
299
|
+
const controlSeason = await this.adapter.getStateAsync('control.season.active');
|
|
300
|
+
return !!controlSeason?.val;
|
|
301
|
+
},
|
|
302
|
+
|
|
245
303
|
// >>> NEU: formatierten Text (z. B. "3h 12m 5s") in Sekunden zurückrechnen
|
|
246
304
|
_parseFormattedTimeToSeconds(value) {
|
|
247
305
|
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
@@ -272,18 +330,22 @@ const runtimeHelper = {
|
|
|
272
330
|
},
|
|
273
331
|
|
|
274
332
|
_scheduleDailyReset() {
|
|
333
|
+
if (this.resetTimer) {
|
|
334
|
+
this.adapter.clearTimeout(this.resetTimer);
|
|
335
|
+
this.resetTimer = null;
|
|
336
|
+
}
|
|
275
337
|
const now = new Date();
|
|
276
338
|
const nextMidnight = new Date(now);
|
|
277
339
|
nextMidnight.setHours(24, 0, 0, 0);
|
|
278
340
|
const msUntilMidnight = nextMidnight - now;
|
|
279
341
|
|
|
280
|
-
this.resetTimer = setTimeout(async () => {
|
|
342
|
+
this.resetTimer = this.adapter.setTimeout(async () => {
|
|
281
343
|
this.runtimeToday = 0;
|
|
282
344
|
this.startCountToday = 0;
|
|
283
345
|
this.lastOn = this.isRunning ? Date.now() : null;
|
|
284
346
|
|
|
285
347
|
// Laufzeiten zurücksetzen
|
|
286
|
-
this._updateStates();
|
|
348
|
+
await this._updateStates();
|
|
287
349
|
|
|
288
350
|
// --- NEU: Circulation-Werte um Mitternacht zurücksetzen ---
|
|
289
351
|
await this.adapter.setStateAsync('circulation.daily_total', { val: 0, ack: true });
|
|
@@ -313,25 +375,31 @@ const runtimeHelper = {
|
|
|
313
375
|
|
|
314
376
|
_startLiveTimer() {
|
|
315
377
|
if (this.liveTimer) {
|
|
316
|
-
clearInterval(this.liveTimer);
|
|
378
|
+
this.adapter.clearInterval(this.liveTimer);
|
|
317
379
|
}
|
|
318
|
-
this.liveTimer = setInterval(() => this._updateStates(), 10 * 1000);
|
|
380
|
+
this.liveTimer = this.adapter.setInterval(() => this._updateStates(), 10 * 1000);
|
|
319
381
|
this.adapter.log.debug('[runtimeHelper] Live timer started (updates every 10 seconds)');
|
|
320
382
|
},
|
|
321
383
|
|
|
322
384
|
_stopLiveTimer() {
|
|
323
385
|
if (this.liveTimer) {
|
|
324
|
-
clearInterval(this.liveTimer);
|
|
386
|
+
this.adapter.clearInterval(this.liveTimer);
|
|
325
387
|
this.liveTimer = null;
|
|
326
388
|
this.adapter.log.debug('[runtimeHelper] Live timer stopped');
|
|
327
389
|
}
|
|
328
390
|
},
|
|
329
391
|
|
|
330
392
|
cleanup() {
|
|
393
|
+
if (this.restoreTimer) {
|
|
394
|
+
this.adapter.clearTimeout(this.restoreTimer);
|
|
395
|
+
this.restoreTimer = null;
|
|
396
|
+
}
|
|
397
|
+
|
|
331
398
|
if (this.resetTimer) {
|
|
332
|
-
clearTimeout(this.resetTimer);
|
|
399
|
+
this.adapter.clearTimeout(this.resetTimer);
|
|
333
400
|
this.resetTimer = null;
|
|
334
401
|
}
|
|
402
|
+
|
|
335
403
|
this._stopLiveTimer();
|
|
336
404
|
},
|
|
337
405
|
};
|
|
@@ -3,10 +3,14 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Legt alle States für Laufzeit- und Umwälzwerte an:
|
|
5
5
|
* - runtime.total
|
|
6
|
+
* - runtime.total_seconds
|
|
6
7
|
* - runtime.today
|
|
8
|
+
* - runtime.today_seconds
|
|
7
9
|
* - runtime.start_count_today
|
|
8
10
|
* - runtime.current_session
|
|
11
|
+
* - runtime.current_session_seconds
|
|
9
12
|
* - runtime.season_total
|
|
13
|
+
* - runtime.season_total_seconds
|
|
10
14
|
* - circulation.daily_total
|
|
11
15
|
* - circulation.daily_required
|
|
12
16
|
* - circulation.daily_remaining
|
|
@@ -53,6 +57,32 @@ async function createRuntimeStates(adapter) {
|
|
|
53
57
|
await adapter.setStateAsync('runtime.total', { val: '0h 0m 0s', ack: true }); // FIX: Nur setzen, wenn leer
|
|
54
58
|
}
|
|
55
59
|
|
|
60
|
+
// FIX: Gesamtlaufzeit als robuster Rohwert in Sekunden
|
|
61
|
+
await adapter.setObjectNotExistsAsync('runtime.total_seconds', {
|
|
62
|
+
type: 'state',
|
|
63
|
+
common: {
|
|
64
|
+
name: {
|
|
65
|
+
en: 'Total runtime (seconds)',
|
|
66
|
+
de: 'Gesamtlaufzeit (Sekunden)',
|
|
67
|
+
},
|
|
68
|
+
desc: {
|
|
69
|
+
en: 'Total pump runtime as raw value in seconds',
|
|
70
|
+
de: 'Gesamtlaufzeit der Pumpe als Rohwert in Sekunden',
|
|
71
|
+
},
|
|
72
|
+
type: 'number',
|
|
73
|
+
role: 'value',
|
|
74
|
+
unit: 's',
|
|
75
|
+
read: true,
|
|
76
|
+
write: false,
|
|
77
|
+
persist: true,
|
|
78
|
+
},
|
|
79
|
+
native: {},
|
|
80
|
+
});
|
|
81
|
+
const existingTotalSeconds = await adapter.getStateAsync('runtime.total_seconds');
|
|
82
|
+
if (!existingTotalSeconds || existingTotalSeconds.val === null || existingTotalSeconds.val === undefined) {
|
|
83
|
+
await adapter.setStateAsync('runtime.total_seconds', { val: 0, ack: true });
|
|
84
|
+
}
|
|
85
|
+
|
|
56
86
|
// Tageslaufzeit (formatiert)
|
|
57
87
|
await adapter.setObjectNotExistsAsync('runtime.today', {
|
|
58
88
|
type: 'state',
|
|
@@ -78,6 +108,32 @@ async function createRuntimeStates(adapter) {
|
|
|
78
108
|
await adapter.setStateAsync('runtime.today', { val: '0h 0m 0s', ack: true }); // FIX
|
|
79
109
|
}
|
|
80
110
|
|
|
111
|
+
// FIX: Tageslaufzeit als robuster Rohwert in Sekunden
|
|
112
|
+
await adapter.setObjectNotExistsAsync('runtime.today_seconds', {
|
|
113
|
+
type: 'state',
|
|
114
|
+
common: {
|
|
115
|
+
name: {
|
|
116
|
+
en: 'Today runtime (seconds)',
|
|
117
|
+
de: 'Heutige Laufzeit (Sekunden)',
|
|
118
|
+
},
|
|
119
|
+
desc: {
|
|
120
|
+
en: 'Pump runtime for today as raw value in seconds',
|
|
121
|
+
de: 'Heutige Laufzeit der Pumpe als Rohwert in Sekunden',
|
|
122
|
+
},
|
|
123
|
+
type: 'number',
|
|
124
|
+
role: 'value',
|
|
125
|
+
unit: 's',
|
|
126
|
+
read: true,
|
|
127
|
+
write: false,
|
|
128
|
+
persist: true,
|
|
129
|
+
},
|
|
130
|
+
native: {},
|
|
131
|
+
});
|
|
132
|
+
const existingTodaySeconds = await adapter.getStateAsync('runtime.today_seconds');
|
|
133
|
+
if (!existingTodaySeconds || existingTodaySeconds.val === null || existingTodaySeconds.val === undefined) {
|
|
134
|
+
await adapter.setStateAsync('runtime.today_seconds', { val: 0, ack: true });
|
|
135
|
+
}
|
|
136
|
+
|
|
81
137
|
// -------------------------------------------------------------------------
|
|
82
138
|
// NEU: Pumpenstarts heute
|
|
83
139
|
await adapter.setObjectNotExistsAsync('runtime.start_count_today', {
|
|
@@ -129,6 +185,32 @@ async function createRuntimeStates(adapter) {
|
|
|
129
185
|
await adapter.setStateAsync('runtime.current_session', { val: '0h 0m 0s', ack: true }); // FIX
|
|
130
186
|
}
|
|
131
187
|
|
|
188
|
+
// FIX: Aktuelle Session als robuster Rohwert in Sekunden
|
|
189
|
+
await adapter.setObjectNotExistsAsync('runtime.current_session_seconds', {
|
|
190
|
+
type: 'state',
|
|
191
|
+
common: {
|
|
192
|
+
name: {
|
|
193
|
+
en: 'Current runtime (seconds)',
|
|
194
|
+
de: 'Aktuelle Laufzeit (Sekunden)',
|
|
195
|
+
},
|
|
196
|
+
desc: {
|
|
197
|
+
en: 'Current pump runtime since switch-on as raw value in seconds',
|
|
198
|
+
de: 'Aktuelle Laufzeit seit dem Einschalten der Pumpe als Rohwert in Sekunden',
|
|
199
|
+
},
|
|
200
|
+
type: 'number',
|
|
201
|
+
role: 'value',
|
|
202
|
+
unit: 's',
|
|
203
|
+
read: true,
|
|
204
|
+
write: false,
|
|
205
|
+
persist: true,
|
|
206
|
+
},
|
|
207
|
+
native: {},
|
|
208
|
+
});
|
|
209
|
+
const existingCurrentSeconds = await adapter.getStateAsync('runtime.current_session_seconds');
|
|
210
|
+
if (!existingCurrentSeconds || existingCurrentSeconds.val === null || existingCurrentSeconds.val === undefined) {
|
|
211
|
+
await adapter.setStateAsync('runtime.current_session_seconds', { val: 0, ack: true });
|
|
212
|
+
}
|
|
213
|
+
|
|
132
214
|
// NEU: Gesamtlaufzeit der aktuellen Saison (formatiert)
|
|
133
215
|
await adapter.setObjectNotExistsAsync('runtime.season_total', {
|
|
134
216
|
type: 'state',
|
|
@@ -154,6 +236,32 @@ async function createRuntimeStates(adapter) {
|
|
|
154
236
|
await adapter.setStateAsync('runtime.season_total', { val: '0h 0m 0s', ack: true }); // FIX
|
|
155
237
|
}
|
|
156
238
|
|
|
239
|
+
// FIX: Saisonlaufzeit als robuster Rohwert in Sekunden
|
|
240
|
+
await adapter.setObjectNotExistsAsync('runtime.season_total_seconds', {
|
|
241
|
+
type: 'state',
|
|
242
|
+
common: {
|
|
243
|
+
name: {
|
|
244
|
+
en: 'Season runtime (seconds)',
|
|
245
|
+
de: 'Saisonlaufzeit (Sekunden)',
|
|
246
|
+
},
|
|
247
|
+
desc: {
|
|
248
|
+
en: 'Pump runtime for the current season as raw value in seconds',
|
|
249
|
+
de: 'Laufzeit der Pumpe fuer die aktuelle Saison als Rohwert in Sekunden',
|
|
250
|
+
},
|
|
251
|
+
type: 'number',
|
|
252
|
+
role: 'value',
|
|
253
|
+
unit: 's',
|
|
254
|
+
read: true,
|
|
255
|
+
write: false,
|
|
256
|
+
persist: true,
|
|
257
|
+
},
|
|
258
|
+
native: {},
|
|
259
|
+
});
|
|
260
|
+
const existingSeasonSeconds = await adapter.getStateAsync('runtime.season_total_seconds');
|
|
261
|
+
if (!existingSeasonSeconds || existingSeasonSeconds.val === null || existingSeasonSeconds.val === undefined) {
|
|
262
|
+
await adapter.setStateAsync('runtime.season_total_seconds', { val: 0, ack: true });
|
|
263
|
+
}
|
|
264
|
+
|
|
157
265
|
// -------------------------------------------------------------------------
|
|
158
266
|
// --- Kanal circulation ---
|
|
159
267
|
await adapter.setObjectNotExistsAsync('circulation', {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.poolcontrol",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.14",
|
|
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",
|