iobroker.poolcontrol 1.3.7 → 1.3.9

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
@@ -188,6 +188,17 @@ New features are added regularly – please refer to the changelog.
188
188
  ---
189
189
 
190
190
  ## Changelog
191
+ ### 1.3.9 (2026-04-24)
192
+
193
+ - Fix: solarLogbookHelper no longer creates duplicate or unnecessary log entries (improved filtering & throttling logic)
194
+ - Fix: Removed obsolete "no runtime today" entries once solar has actually run
195
+ - Fix: Improved handling of weather summary text to avoid broken or cut-off sentences
196
+ - Fix: solarLogbookHelper now updates `last_entry_time` only when a real log entry is written
197
+ - Fix: solarInsightsHelper runtime calculation improved (no incorrect time accumulation on state changes)
198
+ - Fix: solarInsightsHelper now correctly tracks previous solar state for more accurate active time calculation
199
+ - Fix: Added missing `debug.last_update` update on successful calculation
200
+ - Improvement: General stability and plausibility improvements in solar insights and logbook processing
201
+
191
202
  ### 1.3.7 (2026-04-23)
192
203
 
193
204
  Bugfixes
@@ -213,11 +224,6 @@ frostHelper
213
224
  - Fixed critical i18n issue in solarInsightsHelper and solarLogbookHelper that could lead to instability or crashes
214
225
  - Switched translation handling to I18n.translate() for stable and consistent i18n behavior
215
226
 
216
- ### 1.3.3 (2026-04-18)
217
-
218
- - Added solar COP calculation to evaluate system efficiency
219
- - Added solar logbook helper with easy-to-read daily summaries for better user understanding
220
-
221
227
  ## Support
222
228
  - [ioBroker Forum](https://forum.iobroker.net/)
223
229
  - [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.7",
4
+ "version": "1.3.9",
5
5
  "news": {
6
+ "1.3.9": {
7
+ "en": "Fix solar logbook duplication and invalid entries, improve log stability and weather text handling; fix solar insights runtime calculation and debug timestamp update.",
8
+ "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.",
9
+ "ru": "Исправьте дублирование журнала солнечной энергии и неверные записи, улучшите стабильность журнала и обработку текста о погоде; исправить расчет времени выполнения Solar Insights и обновить временную метку отладки.",
10
+ "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.",
11
+ "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.",
12
+ "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.",
13
+ "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.",
14
+ "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.",
15
+ "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.",
16
+ "uk": "Виправте дублювання сонячного журналу та недійсні записи, покращте стабільність журналу та обробку тексту погоди; виправити розрахунок часу виконання solar insights і налагодити оновлення часових позначок.",
17
+ "zh-cn": "修复太阳能日志重复和无效条目,提高日志稳定性和天气文本处理;修复 Solar Insights 运行时计算和调试时间戳更新。"
18
+ },
6
19
  "1.3.7": {
7
20
  "en": "Fix solarInsights detection for standard solar (use solar.request_active instead of non-existing solar.active). photovoltaicHelper improvements: rounded surplus value in status text and switched afterrun timer to adapter.setTimeout/clearTimeout.",
8
21
  "de": "Fix der solarInsights-Erkennung für Standard-Solar (Verwendung von solar.request_active statt nicht vorhandenem solar.active). Verbesserungen im photovoltaicHelper: Rundung des Überschusswerts im Status-Text und Umstellung des Afterrun-Timers auf adapter.setTimeout/clearTimeout.",
@@ -41,32 +54,6 @@
41
54
  "pl": "Naprawiono krytyczny problem i18n w programach solarInsightsHelper i solarLogbookHelper, który mógł prowadzić do niestabilności lub awarii. Przełączono obsługę tłumaczeń na I18n.translate(), aby zapewnić stabilne działanie.",
42
55
  "uk": "Виправлено критичну проблему i18n у solarInsightsHelper і solarLogbookHelper, яка могла призвести до нестабільності або збоїв. Перемкнуто обробку перекладу на I18n.translate(), щоб забезпечити стабільну роботу.",
43
56
  "zh-cn": "修复了 SolarInsightsHelper 和 SolarLogbookHelper 中可能导致不稳定或崩溃的关键 i18n 问题。将翻译处理切换为 I18n.translate() 以确保稳定运行。"
44
- },
45
- "1.3.4": {
46
- "en": "Fixed critical i18n issue in solarInsightsHelper and solarLogbookHelper that could lead to instability or crashes. Switched translation handling to I18n.translate() to ensure stable operation.",
47
- "de": "Kritischer i18n-Fehler in solarInsightsHelper und solarLogbookHelper behoben, der zu Instabilität oder Abstürzen führen konnte. Übersetzungen wurden auf I18n.translate() umgestellt, um einen stabilen Betrieb sicherzustellen.",
48
- "ru": "Исправлена ​​критическая проблема i18n в SolarInsightsHelper и SolarLogbookHelper, которая могла привести к нестабильности или сбоям. Обработку перевода переключили на I18n.translate() для обеспечения стабильной работы.",
49
- "pt": "Foi corrigido um problema crítico do i18n no solarInsightsHelper e no solarLogbookHelper que poderia causar instabilidade ou travamentos. Manipulação de tradução alterada para I18n.translate() para garantir uma operação estável.",
50
- "nl": "Een kritiek i18n-probleem in solarInsightsHelper en solarLogbookHelper opgelost dat tot instabiliteit of crashes kon leiden. De verwerking van de vertalingen is gewijzigd naar I18n.translate() om een ​​stabiele werking te garanderen.",
51
- "fr": "Correction d'un problème i18n critique dans solarInsightsHelper et solarLogbookHelper qui pouvait entraîner une instabilité ou des plantages. Gestion de la traduction commutée vers I18n.translate() pour garantir un fonctionnement stable.",
52
- "it": "Risolto un problema critico i18n in solarInsightsHelper e solarLogbookHelper che poteva portare a instabilità o arresti anomali. Modificata la gestione della traduzione su I18n.translate() per garantire un funzionamento stabile.",
53
- "es": "Se solucionó un problema crítico de i18n en solarInsightsHelper y solarLogbookHelper que podía provocar inestabilidad o fallas. Se cambió el manejo de traducción a I18n.translate() para garantizar un funcionamiento estable.",
54
- "pl": "Naprawiono krytyczny problem i18n w programach solarInsightsHelper i solarLogbookHelper, który mógł prowadzić do niestabilności lub awarii. Przełączono obsługę tłumaczeń na I18n.translate(), aby zapewnić stabilne działanie.",
55
- "uk": "Виправлено критичну проблему i18n у solarInsightsHelper і solarLogbookHelper, яка могла призвести до нестабільності або збоїв. Перемкнуто обробку перекладу на I18n.translate(), щоб забезпечити стабільну роботу.",
56
- "zh-cn": "修复了 SolarInsightsHelper 和 SolarLogbookHelper 中可能导致不稳定或崩溃的关键 i18n 问题。将翻译处理切换为 I18n.translate() 以确保稳定运行。"
57
- },
58
- "1.3.3": {
59
- "en": "Added solar COP calculation and solar logbook helper with human-readable daily entries based on solar insights.",
60
- "de": "Solar-COP-Berechnung sowie Solar-Logbuch-Helper mit verständlichen Tages-Einträgen basierend auf Solar-Insights hinzugefügt.",
61
- "ru": "Добавлен расчет солнечного КПД и помощник в журнале солнечной энергии с удобочитаемыми ежедневными записями на основе данных о солнечной энергии.",
62
- "pt": "Adicionado cálculo de COP solar e auxiliar de diário de bordo solar com entradas diárias legíveis por humanos com base em insights solares.",
63
- "nl": "Zonne-COP-berekening en zonne-logboekhulp toegevoegd met voor mensen leesbare dagelijkse gegevens op basis van zonne-inzichten.",
64
- "fr": "Ajout du calcul du COP solaire et d'un assistant de journal de bord solaire avec des entrées quotidiennes lisibles par l'homme basées sur des informations solaires.",
65
- "it": "Aggiunto il calcolo del COP solare e l'assistente del registro solare con voci giornaliere leggibili dall'uomo basate su informazioni solari.",
66
- "es": "Se agregó un cálculo de COP solar y un asistente de registro solar con entradas diarias legibles por humanos basadas en conocimientos solares.",
67
- "pl": "Dodano obliczenia COP energii słonecznej i pomocnika dziennika słonecznego z czytelnymi dla człowieka codziennymi wpisami opartymi na spostrzeżeniach dotyczących energii słonecznej.",
68
- "uk": "Додано розрахунок COP сонячної енергії та помічник сонячного журналу із зрозумілими для людини щоденними записами на основі даних про сонячну енергію.",
69
- "zh-cn": "添加了太阳能 COP 计算和太阳能日志助手,其中包含基于太阳能洞察的人类可读的每日条目。"
70
57
  }
71
58
  },
72
59
  "titleLang": {
@@ -15,6 +15,7 @@ const solarInsightsHelper = {
15
15
  checkTimer: null,
16
16
  resetTimer: null,
17
17
  lastCheckTimestamp: null,
18
+ lastSolarLogicActive: false,
18
19
 
19
20
  init(adapter) {
20
21
  this.adapter = adapter;
@@ -35,8 +36,11 @@ const solarInsightsHelper = {
35
36
  return;
36
37
  }
37
38
 
38
- // Tages-Latch sofort setzen, wenn Solar aktiv wird
39
- if ((id === 'solar.request_active' || id === 'solar.extended.active') && state.val === true) {
39
+ // FIX: Tages-Latch auch bei vollständigen ioBroker IDs sicher setzen
40
+ if (
41
+ (this._matchesStateId(id, 'solar.request_active') || this._matchesStateId(id, 'solar.extended.active')) &&
42
+ state.val === true
43
+ ) {
40
44
  void this.adapter.setStateChangedAsync('analytics.insights.solar.results.solar_ran_today', {
41
45
  val: true,
42
46
  ack: true,
@@ -99,6 +103,7 @@ const solarInsightsHelper = {
99
103
  });
100
104
 
101
105
  this.lastCheckTimestamp = null;
106
+ this.lastSolarLogicActive = false;
102
107
 
103
108
  await this.adapter.setStateChangedAsync('analytics.insights.solar.debug.last_update', {
104
109
  val: new Date().toISOString(),
@@ -185,7 +190,13 @@ const solarInsightsHelper = {
185
190
  'ai.weather.outputs.daily_summary',
186
191
  ];
187
192
 
188
- return ids.includes(id);
193
+ // FIX: Also support full ioBroker IDs like "poolcontrol.0.solar.request_active"
194
+ return ids.some(relevantId => id === relevantId || id.endsWith(`.${relevantId}`));
195
+ },
196
+
197
+ _matchesStateId(id, stateId) {
198
+ // FIX: Also support full ioBroker IDs like "poolcontrol.0.solar.request_active"
199
+ return id === stateId || id.endsWith(`.${stateId}`);
189
200
  },
190
201
 
191
202
  async _checkSolarInsights() {
@@ -353,13 +364,18 @@ const solarInsightsHelper = {
353
364
  peakPowerTodayW = 0;
354
365
  }
355
366
 
356
- if (this.lastCheckTimestamp && solarEffectiveNow && Number.isFinite(thermalPowerW) && thermalPowerW > 0) {
367
+ if (this.lastCheckTimestamp && (this.lastSolarLogicActive || solarLogicActive)) {
357
368
  const deltaHours = (nowTs - this.lastCheckTimestamp) / 3600000;
358
369
 
359
- // Schutz gegen unrealistisch große Sprünge
370
+ // FIX: Count active solar minutes based on solar runtime, not only on positive thermal gain.
371
+ // The interval is counted if solar was active at the previous or current check.
360
372
  if (deltaHours > 0 && deltaHours <= 0.5) {
361
- estimatedGainTodayWh = Number((estimatedGainTodayWh + thermalPowerW * deltaHours).toFixed(2));
362
373
  activeMinutesToday = Number((activeMinutesToday + deltaHours * 60).toFixed(2));
374
+
375
+ // FIX: Energy gain is only accumulated when a positive thermal power can be calculated
376
+ if (solarEffectiveNow && Number.isFinite(thermalPowerW) && thermalPowerW > 0) {
377
+ estimatedGainTodayWh = Number((estimatedGainTodayWh + thermalPowerW * deltaHours).toFixed(2));
378
+ }
363
379
  }
364
380
  }
365
381
 
@@ -681,7 +697,14 @@ const solarInsightsHelper = {
681
697
  ack: true,
682
698
  });
683
699
 
700
+ await this.adapter.setStateChangedAsync('analytics.insights.solar.debug.last_update', {
701
+ val: new Date().toISOString(),
702
+ ack: true,
703
+ });
704
+
684
705
  this.lastCheckTimestamp = nowTs;
706
+ this.lastSolarLogicActive = solarLogicActive;
707
+
685
708
  this.adapter.log.debug('[solarInsightsHelper] Block 7 updated successfully');
686
709
  } catch (err) {
687
710
  this.adapter.log.warn(`[solarInsightsHelper] Error in check: ${err.message}`);
@@ -224,10 +224,6 @@ const solarLogbookHelper = {
224
224
 
225
225
  const currentEntry = await this._readString('analytics.insights.solar.logbook.current_entry');
226
226
 
227
- if (currentEntry === entry.text) {
228
- return;
229
- }
230
-
231
227
  const now = new Date();
232
228
  const nowIso = now.toISOString();
233
229
  const timeLabel = this._formatTime(now);
@@ -241,13 +237,31 @@ const solarLogbookHelper = {
241
237
  };
242
238
 
243
239
  const dayLogJsonRaw = await this._readString('analytics.insights.solar.logbook.day_log_json');
244
- const dayLog = this._safeParseArray(dayLogJsonRaw);
240
+ let dayLog = this._safeParseArray(dayLogJsonRaw);
241
+
242
+ // FIX: Remove obsolete "no runtime today" entries once solar has actually run today.
243
+ // The current_entry remains live, but the readable day log should not keep a misleading
244
+ // "Solar did not run today" entry after solar runtime was detected.
245
+ if (entry.type !== 'no_runtime_today') {
246
+ dayLog = dayLog.filter(item => item && item.type !== 'no_runtime_today');
247
+ }
245
248
 
246
- dayLog.push(newLogItem);
249
+ const lastLogItem = dayLog.length > 0 ? dayLog[dayLog.length - 1] : null;
250
+ const shouldAppendLogEntry = this._shouldAppendLogEntry(lastLogItem, entry, now);
247
251
 
248
- const trimmedLog = dayLog.slice(-100);
252
+ // FIX: current_entry is the live readable status and may change often.
253
+ // day_log_json/day_log_text are readable day history and should only receive meaningful entries.
254
+ if (currentEntry === entry.text && !shouldAppendLogEntry) {
255
+ return;
256
+ }
249
257
 
250
- const dayLogText = trimmedLog.map(item => `${item.time} - ${item.text}`).join('\n');
258
+ let trimmedLog = dayLog.slice(-100);
259
+
260
+ if (shouldAppendLogEntry) {
261
+ trimmedLog = [...dayLog, newLogItem].slice(-100);
262
+ }
263
+
264
+ const dayLogText = this._buildDayLogText(trimmedLog);
251
265
 
252
266
  await this.adapter.setStateChangedAsync('analytics.insights.solar.logbook.current_entry', {
253
267
  val: entry.text,
@@ -269,8 +283,10 @@ const solarLogbookHelper = {
269
283
  ack: true,
270
284
  });
271
285
 
286
+ const lastEntryTime = await this._readString('analytics.insights.solar.logbook.last_entry_time');
287
+
272
288
  await this.adapter.setStateChangedAsync('analytics.insights.solar.logbook.last_entry_time', {
273
- val: nowIso,
289
+ val: shouldAppendLogEntry ? nowIso : lastEntryTime,
274
290
  ack: true,
275
291
  });
276
292
 
@@ -472,18 +488,61 @@ const solarLogbookHelper = {
472
488
  };
473
489
  },
474
490
 
491
+ // ================================
492
+ // FIX: Logbook Filter & Throttling
493
+ // ================================
494
+
495
+ _shouldAppendLogEntry(lastLogItem, entry, now) {
496
+ if (!lastLogItem) {
497
+ return true;
498
+ }
499
+
500
+ if (!entry || !entry.type) {
501
+ return false;
502
+ }
503
+
504
+ // Statuswechsel IMMER loggen
505
+ if (lastLogItem.type !== entry.type) {
506
+ return true;
507
+ }
508
+
509
+ const lastTimestamp = Date.parse(lastLogItem.ts);
510
+
511
+ if (!Number.isFinite(lastTimestamp)) {
512
+ return true;
513
+ }
514
+
515
+ // max alle 15 Minuten neuen Eintrag
516
+ const minIntervalMs = 15 * 60 * 1000;
517
+
518
+ return now.getTime() - lastTimestamp >= minIntervalMs;
519
+ },
520
+
521
+ _buildDayLogText(dayLog) {
522
+ return dayLog.map(item => `${item.time} - ${item.text}`).join('\n');
523
+ },
524
+
475
525
  _extractShortWeather(weatherSummary) {
476
526
  if (!weatherSummary || weatherSummary.trim() === '') {
477
527
  return '';
478
528
  }
479
529
 
480
530
  const text = weatherSummary.replace(/\s+/g, ' ').trim();
531
+ const maxLength = 140;
481
532
 
482
- if (text.length <= 140) {
533
+ if (text.length <= maxLength) {
483
534
  return text;
484
535
  }
485
536
 
486
- return `${text.slice(0, 137)}...`;
537
+ // FIX: Do not cut the weather summary in the middle of a word
538
+ const shortened = text.slice(0, maxLength);
539
+ const lastSpaceIndex = shortened.lastIndexOf(' ');
540
+
541
+ if (lastSpaceIndex > 0) {
542
+ return `${shortened.slice(0, lastSpaceIndex)}…`;
543
+ }
544
+
545
+ return `${shortened}…`;
487
546
  },
488
547
 
489
548
  async _readState(id) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.poolcontrol",
3
- "version": "1.3.7",
3
+ "version": "1.3.9",
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",