iobroker.poolcontrol 1.4.1 → 1.4.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 +12 -7
- package/io-package.json +14 -14
- package/lib/helpers/solarLogbookHelper.js +2 -2
- package/lib/helpers/statisticsHelperMonth.js +99 -42
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -283,6 +283,18 @@ New features are added regularly – please refer to the changelog.
|
|
|
283
283
|
---
|
|
284
284
|
|
|
285
285
|
## Changelog
|
|
286
|
+
### 1.4.2 (2026-07-01)
|
|
287
|
+
|
|
288
|
+
- Fixed monthly temperature statistics reset scheduling
|
|
289
|
+
- Monthly reset no longer uses long timeouts above the Node.js/ioBroker limit
|
|
290
|
+
- Added persistent monthly period tracking
|
|
291
|
+
- Missed month changes after adapter downtime are detected safely
|
|
292
|
+
- Monthly reset is now checked daily and executed only once per period
|
|
293
|
+
|
|
294
|
+
- Improved solar logbook logging
|
|
295
|
+
- Oversized solar logbook entries are now logged as debug instead of warning
|
|
296
|
+
- This avoids unnecessary warning noise for non-critical diagnostic information
|
|
297
|
+
|
|
286
298
|
### 1.4.1 (2026-06-30)
|
|
287
299
|
|
|
288
300
|
- Fixed Auto-PV holding logic for already running pumps.
|
|
@@ -314,13 +326,6 @@ New features are added regularly – please refer to the changelog.
|
|
|
314
326
|
- **Additional safeguards:** Added size protection for the solar logbook and debug log to prevent uncontrolled state growth.
|
|
315
327
|
- **Maintenance:** Updated the `@iobroker/adapter-core` dependency to the latest recommended version.
|
|
316
328
|
|
|
317
|
-
### 1.3.33 (2026-06-18)
|
|
318
|
-
|
|
319
|
-
- Added live delta states for standard solar and Solar Extended control:
|
|
320
|
-
- `solar.collector_surface_delta`
|
|
321
|
-
- `solar.extended.collector_pool_reference_delta`
|
|
322
|
-
- Documented that runtime changes to `solar.extended.pool_temperature_source` are applied automatically, but may take up to approximately 60 seconds due to the Solar Extended cyclic check interval.
|
|
323
|
-
|
|
324
329
|
## Archived Release History
|
|
325
330
|
|
|
326
331
|
For older releases and archived version history see:
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "poolcontrol",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.2",
|
|
5
5
|
"news": {
|
|
6
|
+
"1.4.2": {
|
|
7
|
+
"en": "Fixed monthly temperature statistics reset scheduling to avoid long timeout errors on Node.js/ioBroker. Reduced oversized solar logbook warning to debug level.",
|
|
8
|
+
"de": "Monatsreset der Temperaturstatistik korrigiert, damit keine zu langen Timeout-Fehler unter Node.js/ioBroker entstehen. Überdimensionierte Solar-Logbuch-Hinweise von Warn auf Debug reduziert.",
|
|
9
|
+
"ru": "Исправлено расписание сброса ежемесячной статистики температуры, чтобы избежать ошибок длительного ожидания в Node.js/ioBroker. Уменьшено предупреждение о слишком большом размере журнала солнечной энергии до уровня отладки.",
|
|
10
|
+
"pt": "Corrigida a programação de redefinição de estatísticas mensais de temperatura para evitar longos erros de tempo limite no Node.js/ioBroker. Aviso de diário de bordo solar superdimensionado reduzido para o nível de depuração.",
|
|
11
|
+
"nl": "Vaste maandelijkse temperatuurstatistieken die de planning resetten om lange time-outfouten op Node.js/ioBroker te voorkomen. Waarschuwing voor te groot zonne-logboek teruggebracht tot foutopsporingsniveau.",
|
|
12
|
+
"fr": "Correction des statistiques de température mensuelles réinitialisant la planification pour éviter les longues erreurs de délai d'attente sur Node.js/ioBroker. Réduction des avertissements du journal solaire surdimensionné au niveau du débogage.",
|
|
13
|
+
"it": "Risolte le statistiche mensili sulla temperatura che ripristinano la pianificazione per evitare errori di timeout lunghi su Node.js/ioBroker. Avviso di registro solare sovradimensionato ridotto al livello di debug.",
|
|
14
|
+
"es": "Se corrigieron las estadísticas de temperatura mensuales que restablecen la programación para evitar errores de tiempo de espera prolongados en Node.js/ioBroker. Se redujo la advertencia del libro de registro solar de gran tamaño al nivel de depuración.",
|
|
15
|
+
"pl": "Naprawiono harmonogram resetowania miesięcznych statystyk temperatury, aby uniknąć błędów związanych z długim przekroczeniem limitu czasu w Node.js/ioBroker. Zmniejszono ostrzeżenie o zbyt dużym dzienniku słonecznym do poziomu debugowania.",
|
|
16
|
+
"uk": "Виправлено розклад скидання щомісячної статистики температури, щоб уникнути помилок тривалого очікування на Node.js/ioBroker. Зменшено попередження про надмірний сонячний журнал до рівня налагодження.",
|
|
17
|
+
"zh-cn": "修复了每月温度统计重置计划,以避免 Node.js/ioBroker 上的长时间超时错误。将超大太阳能日志警告减少到调试级别。"
|
|
18
|
+
},
|
|
6
19
|
"1.4.1": {
|
|
7
20
|
"en": "Fixed Auto-PV holding logic so a running pump no longer reduces its own available PV power calculation. The displayed PV surplus remains unchanged.",
|
|
8
21
|
"de": "Korrigiert die Auto-PV-Haltebedingung, damit eine laufende Pumpe ihre eigene verfügbare PV-Leistung nicht mehr rechnerisch reduziert. Der angezeigte PV-Überschuss bleibt unverändert.",
|
|
@@ -54,19 +67,6 @@
|
|
|
54
67
|
"pl": "Ulepszona architektura historii chemii z chronioną historią krótkoterminową i codzienną, zapobieganie nadmiernym stanom JSON, dodane zabezpieczenia przed rozrostem bazy danych stanu, ulepszona ochrona dziennika solarnego/dziennika debugowania oraz zaktualizowana zależność od rdzenia adaptera.",
|
|
55
68
|
"uk": "Покращена архітектура хімічної історії із захищеною короткостроковою та щоденною історією, запобіганням надмірним станам JSON, доданим запобіжним засобам проти зростання бази даних стану, покращеному захисту сонячного журналу/журналу налагодження та оновленій залежності ядра адаптера.",
|
|
56
69
|
"zh-cn": "改进了化学历史架构,具有受保护的短期和每日历史记录,防止过大的 JSON 状态,增加了针对状态数据库增长的保护措施,增强了太阳能日志/调试日志保护,并更新了适配器核心依赖性。"
|
|
57
|
-
},
|
|
58
|
-
"1.3.33": {
|
|
59
|
-
"en": "Added live delta states for standard solar and Solar Extended control. Documented Solar Extended pool reference runtime update behavior.",
|
|
60
|
-
"de": "Live-Delta-Datenpunkte für Standard-Solar und Solar Extended ergänzt. Laufzeitverhalten der Solar-Extended-Poolreferenz dokumentiert.",
|
|
61
|
-
"ru": "Добавлены дельта-состояния в реальном времени для стандартного и расширенного управления солнечной энергией. Документированное поведение обновления во время выполнения ссылки на расширенный пул Solar.",
|
|
62
|
-
"pt": "Adicionados estados delta ao vivo para controle solar padrão e solar estendido. Comportamento de atualização de tempo de execução de referência do pool Solar Extended documentado.",
|
|
63
|
-
"nl": "Live deltatoestanden toegevoegd voor standaard zonne-energie en Solar Extended-regeling. Gedocumenteerd runtime-updategedrag van de Solar Extended-poolreferentie.",
|
|
64
|
-
"fr": "Ajout d'états delta en direct pour le contrôle solaire standard et solaire étendu. Comportement documenté de la mise à jour du runtime de référence du pool Solar Extended.",
|
|
65
|
-
"it": "Aggiunti stati delta live per il controllo solare standard e Solar Extended. Comportamento documentato dell'aggiornamento runtime di riferimento del pool Solar Extended.",
|
|
66
|
-
"es": "Se agregaron estados delta en vivo para control solar estándar y solar extendido. Comportamiento de actualización del tiempo de ejecución de referencia del grupo Solar Extended documentado.",
|
|
67
|
-
"pl": "Dodano stany delta na żywo dla standardowego sterowania solarnego i Solar Extended. Udokumentowane zachowanie aktualizacji środowiska uruchomieniowego referencyjnej puli Solar Extended.",
|
|
68
|
-
"uk": "Додано живі дельта-стани для стандартного сонячного та розширеного керування Solar. Задокументована поведінка оновлення середовища виконання довідкового пулу Solar Extended.",
|
|
69
|
-
"zh-cn": "为标准太阳能和太阳能扩展控制添加了实时增量状态。记录了 Solar Extended 池参考运行时更新行为。"
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
72
|
"titleLang": {
|
|
@@ -539,7 +539,7 @@ const solarLogbookHelper = {
|
|
|
539
539
|
}
|
|
540
540
|
|
|
541
541
|
if (wasTrimmed) {
|
|
542
|
-
this.adapter.log.
|
|
542
|
+
this.adapter.log.debug('[solarLogbookHelper] Day log was trimmed to keep JSON and text within 64 KB.');
|
|
543
543
|
}
|
|
544
544
|
|
|
545
545
|
return { entries: limitedEntries, json, text };
|
|
@@ -617,7 +617,7 @@ const solarLogbookHelper = {
|
|
|
617
617
|
}
|
|
618
618
|
|
|
619
619
|
if (Buffer.byteLength(jsonText, 'utf8') > MAX_LOGBOOK_BYTES) {
|
|
620
|
-
this.adapter.log.
|
|
620
|
+
this.adapter.log.debug('[solarLogbookHelper] Oversized day_log_json was discarded before parsing.');
|
|
621
621
|
return [];
|
|
622
622
|
}
|
|
623
623
|
|
|
@@ -19,6 +19,9 @@ const statisticsHelperMonth = {
|
|
|
19
19
|
adapter: null,
|
|
20
20
|
monthResetTimer: null,
|
|
21
21
|
isResetting: false,
|
|
22
|
+
isPeriodCheckRunning: false,
|
|
23
|
+
periodStateId: 'analytics.statistics.temperature.month.last_processed_period',
|
|
24
|
+
maxCheckIntervalMs: 24 * 60 * 60 * 1000,
|
|
22
25
|
sensors: [
|
|
23
26
|
{ id: 'outside', name: 'Außentemperatur' },
|
|
24
27
|
{ id: 'ground', name: 'Bodentemperatur' },
|
|
@@ -42,6 +45,13 @@ const statisticsHelperMonth = {
|
|
|
42
45
|
try {
|
|
43
46
|
await this._createTemperatureStatistics();
|
|
44
47
|
await this._subscribeActiveSensors();
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
await this._checkMonthPeriod();
|
|
51
|
+
} catch (err) {
|
|
52
|
+
adapter.log.warn(`statisticsHelperMonth: Error while checking monthly period: ${err.message}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
45
55
|
await this._scheduleMonthReset();
|
|
46
56
|
adapter.log.debug('statisticsHelperMonth: Initialization completed (sensor monitoring active).');
|
|
47
57
|
} catch (err) {
|
|
@@ -151,6 +161,20 @@ const statisticsHelperMonth = {
|
|
|
151
161
|
await adapter.setStateAsync(fullPath, { val: out.id.endsWith('json') ? '{}' : '', ack: true });
|
|
152
162
|
}
|
|
153
163
|
}
|
|
164
|
+
|
|
165
|
+
await adapter.setObjectNotExistsAsync(this.periodStateId, {
|
|
166
|
+
type: 'state',
|
|
167
|
+
common: {
|
|
168
|
+
name: 'Last processed monthly statistics period',
|
|
169
|
+
type: 'string',
|
|
170
|
+
role: 'text',
|
|
171
|
+
read: true,
|
|
172
|
+
write: false,
|
|
173
|
+
def: '',
|
|
174
|
+
persist: true,
|
|
175
|
+
},
|
|
176
|
+
native: {},
|
|
177
|
+
});
|
|
154
178
|
},
|
|
155
179
|
|
|
156
180
|
/**
|
|
@@ -343,7 +367,47 @@ const statisticsHelperMonth = {
|
|
|
343
367
|
},
|
|
344
368
|
|
|
345
369
|
/**
|
|
346
|
-
*
|
|
370
|
+
* Prüft, ob seit dem letzten erfolgreichen Reset ein neuer Monat begonnen hat.
|
|
371
|
+
*/
|
|
372
|
+
async _checkMonthPeriod() {
|
|
373
|
+
if (this.isPeriodCheckRunning) {
|
|
374
|
+
this.adapter.log.debug('statisticsHelperMonth: Monthly period check already running – skipped.');
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
this.isPeriodCheckRunning = true;
|
|
379
|
+
|
|
380
|
+
try {
|
|
381
|
+
const currentPeriod = this._getCurrentPeriodKey();
|
|
382
|
+
const periodState = await this.adapter.getStateAsync(this.periodStateId);
|
|
383
|
+
const lastProcessedPeriod = typeof periodState?.val === 'string' ? periodState.val.trim() : '';
|
|
384
|
+
|
|
385
|
+
if (!lastProcessedPeriod) {
|
|
386
|
+
await this.adapter.setStateAsync(this.periodStateId, { val: currentPeriod, ack: true });
|
|
387
|
+
this.adapter.log.debug(
|
|
388
|
+
`statisticsHelperMonth: Monthly period initialized with ${currentPeriod}; no reset required.`,
|
|
389
|
+
);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (lastProcessedPeriod === currentPeriod) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const resetSuccessful = await this._resetMonthlyTemperatureStats();
|
|
398
|
+
if (!resetSuccessful) {
|
|
399
|
+
throw new Error(`Monthly reset for period ${currentPeriod} was not completed`);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
await this.adapter.setStateAsync(this.periodStateId, { val: currentPeriod, ack: true });
|
|
403
|
+
this.adapter.log.debug(`statisticsHelperMonth: Monthly period ${currentPeriod} marked as processed.`);
|
|
404
|
+
} finally {
|
|
405
|
+
this.isPeriodCheckRunning = false;
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Nächsten Monatsperioden-Check planen (täglich um 00:10 Uhr, maximal 24 Stunden).
|
|
347
411
|
*/
|
|
348
412
|
async _scheduleMonthReset() {
|
|
349
413
|
if (this.monthResetTimer) {
|
|
@@ -352,39 +416,33 @@ const statisticsHelperMonth = {
|
|
|
352
416
|
}
|
|
353
417
|
|
|
354
418
|
const now = new Date();
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
// if (now.getDate() === 1) {
|
|
360
|
-
// this.adapter.log.debug('statisticsHelperMonth: Today is already the 1st – reset skipped.');
|
|
361
|
-
// // Plan auf nächsten Monat verschieben
|
|
362
|
-
// nextReset.setMonth(nextReset.getMonth() + 1);
|
|
363
|
-
// msUntilReset = nextReset.getTime() - now.getTime();
|
|
364
|
-
// }
|
|
365
|
-
|
|
366
|
-
// Wenn Berechnung negativ oder zu klein ist → Sicherheit
|
|
367
|
-
if (msUntilReset <= 0 || msUntilReset < 10 * 60 * 1000) {
|
|
368
|
-
this.adapter.log.debug('statisticsHelperMonth: msUntilReset was too small – adjusting timer.');
|
|
369
|
-
msUntilReset = 10 * 60 * 1000; // mindestens 10 Minuten warten
|
|
419
|
+
const nextCheck = new Date(now);
|
|
420
|
+
nextCheck.setHours(0, 10, 0, 0);
|
|
421
|
+
if (nextCheck <= now) {
|
|
422
|
+
nextCheck.setDate(nextCheck.getDate() + 1);
|
|
370
423
|
}
|
|
424
|
+
const msUntilCheck = Math.min(nextCheck.getTime() - now.getTime(), this.maxCheckIntervalMs);
|
|
371
425
|
|
|
372
|
-
// Timer setzen
|
|
373
426
|
this.monthResetTimer = this.adapter.setTimeout(async () => {
|
|
374
427
|
this.monthResetTimer = null;
|
|
375
428
|
|
|
376
|
-
|
|
377
|
-
this.
|
|
378
|
-
|
|
379
|
-
|
|
429
|
+
try {
|
|
430
|
+
await this._checkMonthPeriod();
|
|
431
|
+
} catch (err) {
|
|
432
|
+
this.adapter.log.warn(`statisticsHelperMonth: Error during monthly period check: ${err.message}`);
|
|
380
433
|
}
|
|
381
434
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
435
|
+
try {
|
|
436
|
+
await this._scheduleMonthReset();
|
|
437
|
+
} catch (err) {
|
|
438
|
+
this.adapter.log.warn(
|
|
439
|
+
`statisticsHelperMonth: Error while scheduling monthly period check: ${err.message}`,
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
}, msUntilCheck);
|
|
385
443
|
|
|
386
444
|
this.adapter.log.debug(
|
|
387
|
-
`statisticsHelperMonth: Monthly
|
|
445
|
+
`statisticsHelperMonth: Monthly period check scheduled in ${Math.round(msUntilCheck / 60000)} minutes.`,
|
|
388
446
|
);
|
|
389
447
|
},
|
|
390
448
|
|
|
@@ -394,24 +452,9 @@ const statisticsHelperMonth = {
|
|
|
394
452
|
async _resetMonthlyTemperatureStats() {
|
|
395
453
|
const adapter = this.adapter;
|
|
396
454
|
|
|
397
|
-
// 🟢 Neuer Logikblock: Monatsreset erfolgt nur, wenn wirklich neuer Monat begonnen hat
|
|
398
|
-
try {
|
|
399
|
-
const now = new Date();
|
|
400
|
-
const currentDay = now.getDate();
|
|
401
|
-
|
|
402
|
-
// Nur am 1. Tag des Monats ausführen (00:05 Uhr geplant)
|
|
403
|
-
if (currentDay !== 1) {
|
|
404
|
-
adapter.log.debug('[statisticsHelperMonth] Not the first day of the month – reset skipped.');
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
|
-
} catch (err) {
|
|
408
|
-
adapter.log.warn(`[statisticsHelperMonth] Error while checking month start: ${err.message}`);
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
// 🟢 NEU: Schutz vor Endlosschleifen und Mehrfachausführung
|
|
412
455
|
if (this.isResetting) {
|
|
413
456
|
adapter.log.debug('statisticsHelperMonth: Reset already active – skipped.');
|
|
414
|
-
return;
|
|
457
|
+
return false;
|
|
415
458
|
}
|
|
416
459
|
this.isResetting = true;
|
|
417
460
|
|
|
@@ -486,10 +529,12 @@ const statisticsHelperMonth = {
|
|
|
486
529
|
});
|
|
487
530
|
|
|
488
531
|
adapter.log.debug('statisticsHelperMonth: Monthly statistics reset completed.');
|
|
532
|
+
return true;
|
|
489
533
|
} catch (err) {
|
|
490
534
|
adapter.log.warn(`statisticsHelperMonth: Error during monthly reset: ${err.message}`);
|
|
535
|
+
return false;
|
|
491
536
|
} finally {
|
|
492
|
-
this.isResetting = false;
|
|
537
|
+
this.isResetting = false;
|
|
493
538
|
}
|
|
494
539
|
},
|
|
495
540
|
|
|
@@ -515,6 +560,18 @@ const statisticsHelperMonth = {
|
|
|
515
560
|
return `${month.charAt(0).toUpperCase() + month.slice(1)} ${year}`;
|
|
516
561
|
},
|
|
517
562
|
|
|
563
|
+
/**
|
|
564
|
+
* Gibt die aktuelle lokale Monatsperiode als YYYY-MM zurück.
|
|
565
|
+
*
|
|
566
|
+
* @param {Date} date Zu formatierender lokaler Zeitpunkt
|
|
567
|
+
* @returns {string} Lokaler Monats-Schlüssel
|
|
568
|
+
*/
|
|
569
|
+
_getCurrentPeriodKey(date = new Date()) {
|
|
570
|
+
const year = date.getFullYear();
|
|
571
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
572
|
+
return `${year}-${month}`;
|
|
573
|
+
},
|
|
574
|
+
|
|
518
575
|
cleanup() {
|
|
519
576
|
if (this.monthResetTimer) {
|
|
520
577
|
this.adapter.clearTimeout(this.monthResetTimer);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.poolcontrol",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.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",
|