iobroker.poolcontrol 1.4.0 → 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,25 @@ 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
+
298
+ ### 1.4.1 (2026-06-30)
299
+
300
+ - Fixed Auto-PV holding logic for already running pumps.
301
+ - When Auto-PV already controls the pump, the current pump power is now considered for the holding decision.
302
+ - This prevents a running pump from triggering its own Auto-PV afterrun/stop cycle after startup.
303
+ - The displayed PV surplus (`photovoltaic.power_surplus_w`) remains the real remaining surplus and is not artificially adjusted.
304
+
286
305
  ### 1.4.0 (2026-06-29)
287
306
 
288
307
  - Added a reset button for pump learning to quickly clear learned values after a pump replacement or incorrect learning while keeping user settings intact.
@@ -307,20 +326,6 @@ New features are added regularly – please refer to the changelog.
307
326
  - **Additional safeguards:** Added size protection for the solar logbook and debug log to prevent uncontrolled state growth.
308
327
  - **Maintenance:** Updated the `@iobroker/adapter-core` dependency to the latest recommended version.
309
328
 
310
- ### 1.3.33 (2026-06-18)
311
-
312
- - Added live delta states for standard solar and Solar Extended control:
313
- - `solar.collector_surface_delta`
314
- - `solar.extended.collector_pool_reference_delta`
315
- - 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.
316
-
317
- ### 1.3.32 (2026-06-08)
318
-
319
- - Added circulation plausibility diagnostics for daily circulation calculations.
320
- - Added detection of implausible pump power values, flow rates and daily circulation volume jumps.
321
- - Added detailed diagnostic states under `circulation.plausibility` for troubleshooting and analysis.
322
- - Improved diagnostics for circulation calculations without changing existing pump, PV or solar control logic.
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,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "poolcontrol",
4
- "version": "1.4.0",
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
+ },
19
+ "1.4.1": {
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.",
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.",
22
+ "ru": "Исправлена ​​логика удержания Auto-PV, поэтому работающий насос больше не уменьшает собственный расчет доступной фотоэлектрической мощности. Отображаемый излишек фотоэлектрической энергии остается неизменным.",
23
+ "pt": "Lógica de retenção Auto-PV corrigida para que uma bomba em funcionamento não reduza mais seu próprio cálculo de potência fotovoltaica disponível. O excedente fotovoltaico exibido permanece inalterado.",
24
+ "nl": "Vaste Auto-PV-houdlogica zodat een draaiende pomp niet langer zijn eigen beschikbare PV-vermogensberekening vermindert. Het weergegeven PV-overschot blijft ongewijzigd.",
25
+ "fr": "Correction de la logique de maintien Auto-PV afin qu'une pompe en marche ne réduise plus son propre calcul de puissance PV disponible. L'excédent PV affiché reste inchangé.",
26
+ "it": "Risolto il problema con la logica di mantenimento FV automatica in modo che una pompa in funzione non riducesse più il proprio calcolo della potenza FV disponibile. Il surplus FV visualizzato rimane invariato.",
27
+ "es": "Se corrigió la lógica de retención automática de PV para que una bomba en funcionamiento ya no reduzca su propio cálculo de potencia PV disponible. El excedente de PV mostrado permanece sin cambios.",
28
+ "pl": "Naprawiono logikę wstrzymywania Auto-PV, dzięki czemu działająca pompa nie zmniejsza już własnej dostępnej mocy obliczeniowej PV. Wyświetlana nadwyżka PV pozostaje niezmieniona.",
29
+ "uk": "Виправлена ​​логіка утримування автоматичної PV, тому працюючий насос більше не зменшує власний розрахунок доступної PV потужності. Відображений надлишок PV залишається незмінним.",
30
+ "zh-cn": "修复了自动光伏保持逻辑,因此运行中的泵不再减少其自身的可用光伏功率计算。显示的PV剩余量保持不变。"
31
+ },
6
32
  "1.4.0": {
7
33
  "en": "Added pump learning reset button with multilingual status messages, made the daily circulation factor writable and persistent with instant recalculation, introduced temperature-dependent automatic circulation factor adjustment, and extended time control with optional interval operation including diagnostic status messages.",
8
34
  "de": "Reset-Button für das Pumpen-Learning mit mehrsprachigen Statusmeldungen hinzugefügt, täglichen Umwälzfaktor beschreibbar und persistent gemacht inklusive sofortiger Neuberechnung, temperaturabhängige automatische Anpassung des Umwälzfaktors ergänzt sowie die Zeitsteuerung um einen optionalen Intervallbetrieb mit Diagnosestatus erweitert.",
@@ -41,32 +67,6 @@
41
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.",
42
68
  "uk": "Покращена архітектура хімічної історії із захищеною короткостроковою та щоденною історією, запобіганням надмірним станам JSON, доданим запобіжним засобам проти зростання бази даних стану, покращеному захисту сонячного журналу/журналу налагодження та оновленій залежності ядра адаптера.",
43
69
  "zh-cn": "改进了化学历史架构,具有受保护的短期和每日历史记录,防止过大的 JSON 状态,增加了针对状态数据库增长的保护措施,增强了太阳能日志/调试日志保护,并更新了适配器核心依赖性。"
44
- },
45
- "1.3.33": {
46
- "en": "Added live delta states for standard solar and Solar Extended control. Documented Solar Extended pool reference runtime update behavior.",
47
- "de": "Live-Delta-Datenpunkte für Standard-Solar und Solar Extended ergänzt. Laufzeitverhalten der Solar-Extended-Poolreferenz dokumentiert.",
48
- "ru": "Добавлены дельта-состояния в реальном времени для стандартного и расширенного управления солнечной энергией. Документированное поведение обновления во время выполнения ссылки на расширенный пул Solar.",
49
- "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.",
50
- "nl": "Live deltatoestanden toegevoegd voor standaard zonne-energie en Solar Extended-regeling. Gedocumenteerd runtime-updategedrag van de Solar Extended-poolreferentie.",
51
- "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.",
52
- "it": "Aggiunti stati delta live per il controllo solare standard e Solar Extended. Comportamento documentato dell'aggiornamento runtime di riferimento del pool Solar Extended.",
53
- "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.",
54
- "pl": "Dodano stany delta na żywo dla standardowego sterowania solarnego i Solar Extended. Udokumentowane zachowanie aktualizacji środowiska uruchomieniowego referencyjnej puli Solar Extended.",
55
- "uk": "Додано живі дельта-стани для стандартного сонячного та розширеного керування Solar. Задокументована поведінка оновлення середовища виконання довідкового пулу Solar Extended.",
56
- "zh-cn": "为标准太阳能和太阳能扩展控制添加了实时增量状态。记录了 Solar Extended 池参考运行时更新行为。"
57
- },
58
- "1.3.32": {
59
- "en": "Added circulation plausibility diagnostics. New checks detect implausible pump power, flow rates, and daily circulation jumps. Added detailed diagnostic states under circulation.plausibility to simplify troubleshooting and analysis of circulation calculations.",
60
- "de": "Plausibilitätsdiagnose für die Umwälzberechnung hinzugefügt. Neue Prüfungen erkennen unplausible Pumpenleistungen, Durchflusswerte und Sprünge der Tagesumwälzung. Detaillierte Diagnose-States unter circulation.plausibility erleichtern die Fehlersuche und Analyse der Umwälzberechnung.",
61
- "ru": "Добавлена ​​диагностика достоверности циркуляции. Новые проверки выявляют неправдоподобную мощность насоса, скорость потока и скачки суточной циркуляции. Добавлены подробные диагностические состояния в разделе «циркуляция.достоверность» для упрощения поиска и устранения неисправностей и анализа расчетов циркуляции.",
62
- "pt": "Adicionados diagnósticos de plausibilidade de circulação. Novas verificações detectam potências de bomba, taxas de fluxo e saltos diários de circulação implausíveis. Adicionados estados de diagnóstico detalhados em circulação.plausibilidade para simplificar a solução de problemas e a análise de cálculos de circulação.",
63
- "nl": "Diagnostiek van circulatieplausibiliteit toegevoegd. Nieuwe controles detecteren onwaarschijnlijk pompvermogen, debieten en dagelijkse circulatiesprongen. Gedetailleerde diagnostische statussen toegevoegd onder circulatie.plausibiliteit om probleemoplossing en analyse van circulatieberekeningen te vereenvoudigen.",
64
- "fr": "Ajout de diagnostics de plausibilité de la circulation. De nouveaux contrôles détectent une puissance de pompe, des débits et des sauts de circulation quotidiens invraisemblables. Ajout d'états de diagnostic détaillés sous circulation.plausibilité pour simplifier le dépannage et l'analyse des calculs de circulation.",
65
- "it": "Aggiunta diagnostica di plausibilità della circolazione. Nuovi controlli rilevano potenza della pompa, portate e salti di circolazione giornalieri non plausibili. Aggiunti stati diagnostici dettagliati in circolazione.plausibilità per semplificare la risoluzione dei problemi e l'analisi dei calcoli della circolazione.",
66
- "es": "Se agregaron diagnósticos de plausibilidad de circulación. Las nuevas comprobaciones detectan potencias de bombeo, caudales y saltos diarios de circulación inverosímiles. Se agregaron estados de diagnóstico detallados bajo circulación. Plausibilidad para simplificar la resolución de problemas y el análisis de los cálculos de circulación.",
67
- "pl": "Dodano diagnostykę wiarygodności obiegu. Nowe kontrole wykrywają nieprawdopodobną moc pompy, natężenie przepływu i codzienne skoki cyrkulacji. Dodano szczegółowe stany diagnostyczne w obszarze cyrkulacja.wiarygodność, aby uprościć rozwiązywanie problemów i analizę obliczeń cyrkulacji.",
68
- "uk": "Додана діагностика вірогідності циркуляції. Нові перевірки виявляють неправдоподібну потужність насоса, швидкість потоку та щоденні стрибки циркуляції. Додано детальні діагностичні стани під циркуляцією. Правдоподібність для спрощення пошуку несправностей і аналізу розрахунків циркуляції.",
69
- "zh-cn": "添加了循环合理性诊断。新的检查可以检测到难以置信的泵功率、流量和每日循环跳跃。在循环下添加了详细的诊断状态。合理性以简化循环计算的故障排除和分析。"
70
70
  }
71
71
  },
72
72
  "titleLang": {
@@ -8,6 +8,7 @@
8
8
  * - Schaltet die Pumpe nur im Modus 'auto_pv' über pump.pump_switch
9
9
  * - Respektiert Saison, Nachlaufzeit (Entprellung) und optionales "Umwälzung erreicht"
10
10
  * - Einschaltlogik: Überschuss >= (pump_max_watt + threshold_w)
11
+ * - Haltebedingung: Restüberschuss + aktuelle Pumpenleistung >= erforderliche Leistung
11
12
  * -------------------------------------------------------------
12
13
  */
13
14
 
@@ -133,13 +134,32 @@ const photovoltaicHelper = {
133
134
  // FIX: Nur für die Textausgabe auf ganze Watt runden
134
135
  const surplusDisplay = Math.round(surplus);
135
136
 
136
- // **NEU:** Einschaltlogik = Pumpenleistung + Sicherheitsaufschlag
137
137
  const requiredPower = pumpMax + threshold;
138
- const surplusActive = surplus >= requiredPower && seasonActive;
138
+
139
+ // Wenn Auto-PV die laufende Pumpe tatsächlich hält, ist ihre Leistungsaufnahme
140
+ // bereits im Hausverbrauch enthalten und wird nur für die Halteentscheidung addiert.
141
+ const activeHelper = (await this.adapter.getStateAsync('pump.active_helper'))?.val || '';
142
+ const pumpSwitch = !!(await this.adapter.getStateAsync('pump.pump_switch'))?.val;
143
+ const currentPumpPower = Math.max(
144
+ 0,
145
+ Number((await this.adapter.getStateAsync('pump.current_power'))?.val ?? 0) || 0,
146
+ );
147
+ const pvHoldsRunningPump =
148
+ pumpMode === 'auto_pv' &&
149
+ activeHelper === 'photovoltaicHelper' &&
150
+ pumpSwitch &&
151
+ this._desiredPump === true &&
152
+ !this.afterrunTimer;
153
+ const availablePowerForDecision = surplus + (pvHoldsRunningPump ? currentPumpPower : 0);
154
+ const surplusActive = availablePowerForDecision >= requiredPower && seasonActive;
139
155
 
140
156
  const txt = surplusActive
141
- ? `Überschuss aktiv (${surplusDisplay} W ≥ ${pumpMax}+${threshold} W)`
142
- : `Kein Überschuss (${surplusDisplay} W < ${pumpMax}+${threshold} W)`;
157
+ ? pvHoldsRunningPump
158
+ ? `Überschuss aktiv (Halteprüfung: ${surplusDisplay}+${Math.round(currentPumpPower)} W ${pumpMax}+${threshold} W)`
159
+ : `Überschuss aktiv (${surplusDisplay} W ≥ ${pumpMax}+${threshold} W)`
160
+ : pvHoldsRunningPump
161
+ ? `Kein ausreichender Überschuss (Halteprüfung: ${surplusDisplay}+${Math.round(currentPumpPower)} W < ${pumpMax}+${threshold} W)`
162
+ : `Kein Überschuss (${surplusDisplay} W < ${pumpMax}+${threshold} W)`;
143
163
 
144
164
  // FIX: Bestehende Ergebnisstates zuerst lesen, damit last_update nur bei echter Ergebnisänderung gesetzt wird
145
165
  const currentSurplus = Number((await this.adapter.getStateAsync('photovoltaic.power_surplus_w'))?.val ?? 0);
@@ -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.0",
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",