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 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.1",
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.warn('[solarLogbookHelper] Day log was trimmed to keep JSON and text within 64 KB.');
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.warn('[solarLogbookHelper] Oversized day_log_json was discarded before parsing.');
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
- * Monats-Reset planen (1. Tag des Monats 00:05 Uhr)
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 nextReset = new Date(now.getFullYear(), now.getMonth() + 1, 1, 0, 5, 0, 0);
356
- let msUntilReset = nextReset.getTime() - now.getTime();
357
-
358
- // // Wenn heute bereits der 1. ist → keinen sofortigen Reset starten!
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
- if (this.isResetting) {
377
- this.adapter.log.debug('statisticsHelperMonth: Reset already running – timer skipped.');
378
- await this._scheduleMonthReset();
379
- return;
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
- await this._resetMonthlyTemperatureStats();
383
- await this._scheduleMonthReset();
384
- }, msUntilReset);
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 reset scheduled in ${Math.round(msUntilReset / 60000)} minutes.`,
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; // 🟢 NEU: Flag wieder freigeben
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.1",
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",