iobroker.poolcontrol 1.3.29 → 1.3.30

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
@@ -271,6 +271,12 @@ New features are added regularly – please refer to the changelog.
271
271
  ---
272
272
 
273
273
  ## Changelog
274
+ ### 1.3.30 (2026-06-05)
275
+
276
+ - Updated release tooling to the required minimum version.
277
+ - Cleaned up outdated Admin i18n keys.
278
+ - Replaced native timers in AI weather helpers with ioBroker adapter timers.
279
+
274
280
  ### 1.3.29 (2026-06-04)
275
281
 
276
282
  - Added Pool Insights V1 with observations, status evaluation and runtime i18n support.
@@ -301,12 +307,6 @@ New features are added regularly – please refer to the changelog.
301
307
  - Internal cleanup and small structural improvements
302
308
  - Further preparation for cleaner review and repository checks
303
309
 
304
- ### 1.3.25 (2026-05-26)
305
-
306
- - Updated README structure and feature overview
307
- - Synchronized German and English function overviews
308
- - Updated repository maintenance dependencies
309
-
310
310
  ## Archived Release History
311
311
 
312
312
  For older releases and archived version history see:
@@ -65,7 +65,6 @@
65
65
  "Logical Control State (true / false)": "Logischer Kontrollstatus (wahr/falsch)",
66
66
  "Mail": "E-Mail",
67
67
  "Male": "Männlich",
68
- "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or in the instance configuration.": "Viele automatische Funktionen (z. B. Solarsteuerung, Photovoltaikmodus, KI-Wetterlogik und Diagnosefunktionen) funktionieren nur, wenn die Poolsaison aktiv ist. Der Saisonstatus kann jederzeit über den Datenpunkt „status.season_active“ oder in der Instanzkonfiguration geändert werden.",
69
68
  "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or your visualization. The instance configuration only provides the initial value when the datapoint is created for the first time.": "Viele automatische Funktionen (z. B. Solarsteuerung, Photovoltaikmodus, KI-Wetterlogik und Diagnosefunktionen) funktionieren nur, wenn die Poolsaison aktiv ist. Der Saisonstatus kann jederzeit über den Datenpunkt „status.season_active“ oder Ihre Visualisierung geändert werden. Die Instanzkonfiguration liefert nur den Anfangswert, wenn der Datenpunkt zum ersten Mal erstellt wird.",
70
69
  "Max Power (Watt)": "Maximale Leistung (Watt)",
71
70
  "Maximum Pool Temperature (°C – Safety Cutoff)": "Maximale Pooltemperatur (°C – Sicherheitsabschaltung)",
@@ -65,7 +65,6 @@
65
65
  "Logical Control State (true / false)": "Estado de control lógico (verdadero/falso)",
66
66
  "Mail": "Correo",
67
67
  "Male": "Masculino",
68
- "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or in the instance configuration.": "Muchas funciones automáticas (por ejemplo, control solar, modo fotovoltaico, lógica meteorológica AI y funciones de diagnóstico) solo funcionan cuando la temporada de piscina está activa. El estado de la temporada se puede cambiar en cualquier momento a través del punto de datos 'status.season_active' o en la configuración de la instancia.",
69
68
  "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or your visualization. The instance configuration only provides the initial value when the datapoint is created for the first time.": "Muchas funciones automáticas (por ejemplo, control solar, modo fotovoltaico, lógica meteorológica AI y funciones de diagnóstico) solo funcionan cuando la temporada de piscina está activa. El estado de la temporada se puede cambiar en cualquier momento a través del punto de datos 'status.season_active' o su visualización. La configuración de la instancia solo proporciona el valor inicial cuando el punto de datos se crea por primera vez.",
70
69
  "Max Power (Watt)": "Potencia máxima (vatios)",
71
70
  "Maximum Pool Temperature (°C – Safety Cutoff)": "Temperatura máxima de la piscina (°C – Límite de seguridad)",
@@ -65,7 +65,6 @@
65
65
  "Logical Control State (true / false)": "État de contrôle logique (vrai/faux)",
66
66
  "Mail": "Mail",
67
67
  "Male": "Mâle",
68
- "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or in the instance configuration.": "De nombreuses fonctionnalités automatiques (par exemple le contrôle solaire, le mode photovoltaïque, la logique météorologique AI et les fonctions de diagnostic) ne fonctionnent que lorsque la saison de la piscine est active. Le statut de la saison peut être modifié à tout moment via le point de données 'status.season_active' ou dans la configuration de l'instance.",
69
68
  "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or your visualization. The instance configuration only provides the initial value when the datapoint is created for the first time.": "De nombreuses fonctionnalités automatiques (par exemple le contrôle solaire, le mode photovoltaïque, la logique météorologique AI et les fonctions de diagnostic) ne fonctionnent que lorsque la saison de la piscine est active. Le statut de la saison peut être modifié à tout moment via le point de données « status.season_active » ou votre visualisation. La configuration de l'instance fournit uniquement la valeur initiale lorsque le point de données est créé pour la première fois.",
70
69
  "Max Power (Watt)": "Puissance maximale (Watts)",
71
70
  "Maximum Pool Temperature (°C – Safety Cutoff)": "Température maximale de la piscine (°C – Coupure de sécurité)",
@@ -65,7 +65,6 @@
65
65
  "Logical Control State (true / false)": "Stato del controllo logico (vero/falso)",
66
66
  "Mail": "Posta",
67
67
  "Male": "Maschio",
68
- "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or in the instance configuration.": "Molte funzionalità automatiche (ad esempio controllo solare, modalità fotovoltaica, logica meteorologica AI e funzioni diagnostiche) funzionano solo quando la stagione della piscina è attiva. Lo stato della stagione può essere modificato in qualsiasi momento tramite il datapoint 'status.season_active' o nella configurazione dell'istanza.",
69
68
  "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or your visualization. The instance configuration only provides the initial value when the datapoint is created for the first time.": "Molte funzionalità automatiche (ad esempio controllo solare, modalità fotovoltaica, logica meteorologica AI e funzioni diagnostiche) funzionano solo quando la stagione della piscina è attiva. Lo stato della stagione può essere modificato in qualsiasi momento tramite il datapoint 'status.season_active' o la tua visualizzazione. La configurazione dell'istanza fornisce il valore iniziale solo quando il datapoint viene creato per la prima volta.",
70
69
  "Max Power (Watt)": "Potenza massima (Watt)",
71
70
  "Maximum Pool Temperature (°C – Safety Cutoff)": "Temperatura massima della piscina (°C – Interruzione di sicurezza)",
@@ -65,7 +65,6 @@
65
65
  "Logical Control State (true / false)": "Logische controlestatus (waar / onwaar)",
66
66
  "Mail": "Mail",
67
67
  "Male": "Mannelijk",
68
- "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or in the instance configuration.": "Veel automatische functies (bijv. zonneregeling, fotovoltaïsche modus, AI-weerlogica en diagnosefuncties) werken alleen als het zwembadseizoen actief is. De seizoensstatus kan op elk moment worden gewijzigd via het datapunt 'status.season_active' of in de instanceconfiguratie.",
69
68
  "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or your visualization. The instance configuration only provides the initial value when the datapoint is created for the first time.": "Veel automatische functies (bijv. zonneregeling, fotovoltaïsche modus, AI-weerlogica en diagnosefuncties) werken alleen als het zwembadseizoen actief is. De seizoensstatus kan op elk moment worden gewijzigd via het datapunt 'status.season_active' of uw visualisatie. De instanceconfiguratie levert alleen de initiële waarde wanneer het datapunt voor de eerste keer wordt aangemaakt.",
70
69
  "Max Power (Watt)": "Maximaal vermogen (Watt)",
71
70
  "Maximum Pool Temperature (°C – Safety Cutoff)": "Maximale zwembadtemperatuur (°C – veiligheidsuitschakeling)",
@@ -65,7 +65,6 @@
65
65
  "Logical Control State (true / false)": "Stan kontroli logicznej (prawda / fałsz)",
66
66
  "Mail": "Poczta",
67
67
  "Male": "Mężczyzna",
68
- "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or in the instance configuration.": "Wiele funkcji automatycznych (np. sterowanie solarne, tryb fotowoltaiczny, logika pogodowa AI i funkcje diagnostyczne) działa tylko wtedy, gdy trwa sezon basenowy. Status sezonu można zmienić w dowolnym momencie poprzez punkt danych „status.season_active” lub w konfiguracji instancji.",
69
68
  "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or your visualization. The instance configuration only provides the initial value when the datapoint is created for the first time.": "Wiele funkcji automatycznych (np. sterowanie solarne, tryb fotowoltaiczny, logika pogodowa AI i funkcje diagnostyczne) działa tylko wtedy, gdy trwa sezon basenowy. Status sezonu można zmienić w dowolnym momencie za pomocą punktu danych „status.season_active” lub za pomocą wizualizacji. Konfiguracja instancji zapewnia wartość początkową tylko wtedy, gdy punkt danych jest tworzony po raz pierwszy.",
70
69
  "Max Power (Watt)": "Maksymalna moc (W)",
71
70
  "Maximum Pool Temperature (°C – Safety Cutoff)": "Maksymalna temperatura basenu (°C – wyłącznik bezpieczeństwa)",
@@ -65,7 +65,6 @@
65
65
  "Logical Control State (true / false)": "Estado de controle lógico (verdadeiro/falso)",
66
66
  "Mail": "Correspondência",
67
67
  "Male": "Macho",
68
- "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or in the instance configuration.": "Muitos recursos automáticos (por exemplo, controle solar, modo fotovoltaico, lógica meteorológica de IA e funções de diagnóstico) só funcionam quando a temporada de piscinas está ativa. O status da temporada pode ser alterado a qualquer momento por meio do ponto de dados 'status.season_active' ou na configuração da instância.",
69
68
  "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or your visualization. The instance configuration only provides the initial value when the datapoint is created for the first time.": "Muitos recursos automáticos (por exemplo, controle solar, modo fotovoltaico, lógica meteorológica de IA e funções de diagnóstico) só funcionam quando a temporada de piscinas está ativa. O status da temporada pode ser alterado a qualquer momento por meio do ponto de dados 'status.season_active' ou de sua visualização. A configuração da instância fornece o valor inicial apenas quando o ponto de dados é criado pela primeira vez.",
70
69
  "Max Power (Watt)": "Potência máxima (Watts)",
71
70
  "Maximum Pool Temperature (°C – Safety Cutoff)": "Temperatura Máxima da Piscina (°C – Corte de Segurança)",
@@ -65,7 +65,6 @@
65
65
  "Logical Control State (true / false)": "Состояние логического управления (истина/ложь)",
66
66
  "Mail": "Почта",
67
67
  "Male": "Мужской",
68
- "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or in the instance configuration.": "Многие автоматические функции (например, управление солнечной энергией, фотоэлектрический режим, логика погоды AI и функции диагностики) работают только во время сезона бассейнов. Статус сезона можно изменить в любое время с помощью точки данных status. Season_active или в конфигурации экземпляра.",
69
68
  "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or your visualization. The instance configuration only provides the initial value when the datapoint is created for the first time.": "Многие автоматические функции (например, управление солнечной энергией, фотоэлектрический режим, логика погоды AI и функции диагностики) работают только во время сезона бассейнов. Статус сезона можно изменить в любое время с помощью точки данных status. Season_active или вашей визуализации. Конфигурация экземпляра предоставляет начальное значение только при первом создании точки данных.",
70
69
  "Max Power (Watt)": "Максимальная мощность (Ватт)",
71
70
  "Maximum Pool Temperature (°C – Safety Cutoff)": "Максимальная температура бассейна (°C – безопасное отключение)",
@@ -65,7 +65,6 @@
65
65
  "Logical Control State (true / false)": "Логічний контрольний стан (істина/хибність)",
66
66
  "Mail": "Пошта",
67
67
  "Male": "Чоловік",
68
- "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or in the instance configuration.": "Багато автоматичних функцій (наприклад, сонячний контроль, фотоелектричний режим, логіка погоди штучного інтелекту та функції діагностики) працюють лише під час сезону басейну. Статус сезону можна будь-коли змінити за допомогою точки даних status.season_active або в конфігурації екземпляра.",
69
68
  "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or your visualization. The instance configuration only provides the initial value when the datapoint is created for the first time.": "Багато автоматичних функцій (наприклад, сонячний контроль, фотоелектричний режим, логіка погоди штучного інтелекту та функції діагностики) працюють лише під час сезону басейну. Статус сезону можна будь-коли змінити за допомогою точки даних status.season_active або вашої візуалізації. Конфігурація екземпляра надає лише початкове значення, коли точка даних створюється вперше.",
70
69
  "Max Power (Watt)": "Максимальна потужність (ват)",
71
70
  "Maximum Pool Temperature (°C – Safety Cutoff)": "Максимальна температура басейну (°C – безпечне обмеження)",
@@ -65,7 +65,6 @@
65
65
  "Logical Control State (true / false)": "逻辑控制状态(真/假)",
66
66
  "Mail": "邮件",
67
67
  "Male": "男性",
68
- "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or in the instance configuration.": "许多自动功能(例如太阳能控制、光伏模式、人工智能天气逻辑和诊断功能)仅在泳池季节活跃时运行。季节状态可以随时通过“status.season_active”数据点或在实例配置中更改。",
69
68
  "Many automatic features (e.g. solar control, photovoltaic mode, AI weather logic and diagnostic functions) only operate when the pool season is active. The season status can be changed at any time via the 'status.season_active' datapoint or your visualization. The instance configuration only provides the initial value when the datapoint is created for the first time.": "许多自动功能(例如太阳能控制、光伏模式、人工智能天气逻辑和诊断功能)仅在泳池季节活跃时运行。季节状态可以随时通过“status.season_active”数据点或可视化更改。实例配置仅在第一次创建数据点时提供初始值。",
70
69
  "Max Power (Watt)": "最大功率(瓦)",
71
70
  "Maximum Pool Temperature (°C – Safety Cutoff)": "最高水池温度(°C – 安全截止值)",
package/io-package.json CHANGED
@@ -1,8 +1,21 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "poolcontrol",
4
- "version": "1.3.29",
4
+ "version": "1.3.30",
5
5
  "news": {
6
+ "1.3.30": {
7
+ "en": "Updated release tooling to the required minimum version. Cleaned up outdated Admin i18n keys. Replaced native timers in AI weather helpers with ioBroker adapter timers.",
8
+ "de": "Release-Werkzeuge auf die erforderliche Mindestversion aktualisiert. Veraltete Admin-i18n-Schlüssel bereinigt. Native Timer in den KI-Wetter-Helpern durch ioBroker-Adapter-Timer ersetzt.",
9
+ "ru": "Обновлены инструменты выпуска до необходимой минимальной версии. Очищены устаревшие ключи администратора i18n. Заменены встроенные таймеры в помощниках погоды AI на таймеры адаптера ioBroker.",
10
+ "pt": "Ferramentas de lançamento atualizadas para a versão mínima exigida. Limpeza de chaves Admin i18n desatualizadas. Temporizadores nativos substituídos em ajudantes meteorológicos de IA por temporizadores adaptadores ioBroker.",
11
+ "nl": "Releasetooling bijgewerkt naar de vereiste minimumversie. Verouderde Admin i18n-sleutels opgeschoond. Native timers in AI-weerhelpers vervangen door ioBroker-adaptertimers.",
12
+ "fr": "Outils de version mis à jour vers la version minimale requise. Nettoyage des clés Admin i18n obsolètes. Remplacement des minuteries natives dans les assistants météo AI par des minuteries d'adaptateur ioBroker.",
13
+ "it": "Strumenti di rilascio aggiornati alla versione minima richiesta. Ripulite le chiavi Admin i18n obsolete. Sostituiti i timer nativi negli assistenti meteorologici AI con i timer dell'adattatore ioBroker.",
14
+ "es": "Herramientas de lanzamiento actualizadas a la versión mínima requerida. Se limpiaron las claves de Admin i18n obsoletas. Se reemplazaron los temporizadores nativos en los asistentes meteorológicos de IA con temporizadores del adaptador ioBroker.",
15
+ "pl": "Zaktualizowano narzędzia wydania do wymaganej wersji minimalnej. Wyczyszczono nieaktualne klucze administratora i18n. Zastąpiono natywne liczniki czasu w pomocnikach pogodowych AI zegarami adaptera ioBroker.",
16
+ "uk": "Оновлено інструмент випуску до необхідної мінімальної версії. Очищено застарілі ключі адміністратора i18n. Вбудовані таймери в помічниках погоди штучного інтелекту замінено на таймери адаптера ioBroker.",
17
+ "zh-cn": "将发布工具更新为所需的最低版本。清理了过时的 Admin i18n 密钥。将 AI 天气助手中的本机计时器替换为 ioBroker 适配器计时器。"
18
+ },
6
19
  "1.3.29": {
7
20
  "en": "Added Pool Insights V1 with observations, status evaluation and runtime i18n support. Improved Pool Insights text generation and removed dependency on external summary blocks. Fixed missing initialization of season and solar warning runtime states from adapter configuration. Added admin UI notes explaining initial values versus runtime datapoint control.",
8
21
  "de": "Pool Insights V1 mit Beobachtungen, Statusbewertung und Runtime-i18n hinzugefügt. Pool-Insights-Texte verbessert und die Abhängigkeit von externen Summary-Blöcken entfernt. Fehlende Initialisierung der Saison- und Solarwarnungs-States aus der Adapterkonfiguration behoben. Hinweise in der Admin-Oberfläche ergänzt, die den Unterschied zwischen Initialwerten und Runtime-Datenpunkten erläutern.",
@@ -54,19 +67,6 @@
54
67
  "pl": "Przerobiono kilka ostrzeżeń i uwag z oficjalnych kontroli ioBroker. Różne drobne ulepszenia i wewnętrzne porządki.",
55
68
  "uk": "Перероблено кілька попереджень і приміток до огляду з офіційних перевірок ioBroker. Різні невеликі покращення та внутрішні очищення.",
56
69
  "zh-cn": "重新设计了官方 ioBroker 检查中的几条警告和审查说明。各种小的改进和内部清理。"
57
- },
58
- "1.3.25": {
59
- "en": "Updated documentation and repository maintenance: improved README structure, synchronized function overviews and updated development dependencies",
60
- "de": "Dokumentation und Repository-Wartung aktualisiert: README-Struktur verbessert, Funktionsübersichten synchronisiert und Entwicklungsabhängigkeiten aktualisiert",
61
- "ru": "Обновленная документация и обслуживание репозитория: улучшенная структура README, синхронизированные обзоры функций и обновленные зависимости разработки.",
62
- "pt": "Documentação atualizada e manutenção de repositório: estrutura README aprimorada, visões gerais de funções sincronizadas e dependências de desenvolvimento atualizadas",
63
- "nl": "Bijgewerkte documentatie en repository-onderhoud: verbeterde README-structuur, gesynchroniseerde functieoverzichten en bijgewerkte ontwikkelingsafhankelijkheden",
64
- "fr": "Documentation mise à jour et maintenance du référentiel : structure README améliorée, aperçus des fonctions synchronisés et dépendances de développement mises à jour",
65
- "it": "Documentazione aggiornata e manutenzione del repository: struttura README migliorata, panoramiche delle funzioni sincronizzate e dipendenze di sviluppo aggiornate",
66
- "es": "Documentación actualizada y mantenimiento del repositorio: estructura README mejorada, descripciones generales de funciones sincronizadas y dependencias de desarrollo actualizadas",
67
- "pl": "Zaktualizowana dokumentacja i konserwacja repozytorium: ulepszona struktura README, zsynchronizowane przeglądy funkcji i zaktualizowane zależności programistyczne",
68
- "uk": "Оновлена ​​документація та обслуговування репозиторію: покращена структура README, синхронізовані огляди функцій та оновлені залежності розробки",
69
- "zh-cn": "更新的文档和存储库维护:改进的自述文件结构、同步的功能概述和更新的开发依赖项"
70
70
  }
71
71
  },
72
72
  "titleLang": {
@@ -41,7 +41,9 @@ const aiForecastHelper = {
41
41
  // ----------------------------------------------------------
42
42
  // NEU: Delay, damit ioBroker alle States laden kann
43
43
  // ----------------------------------------------------------
44
- await new Promise(res => setTimeout(res, 1500));
44
+ await new Promise(resolve => {
45
+ this.adapter.setTimeout(resolve, 1500);
46
+ });
45
47
 
46
48
  // ----------------------------------------------------------
47
49
  // NEU: Sofortige Ausführung beim Adapterstart (wenn aktiviert)
@@ -64,7 +66,7 @@ const aiForecastHelper = {
64
66
  */
65
67
  cleanup() {
66
68
  if (this.timer) {
67
- clearInterval(this.timer);
69
+ this.adapter.clearInterval(this.timer);
68
70
  this.timer = null;
69
71
  }
70
72
  this.adapter && this.adapter.log.debug('[aiForecastHelper] cleanup finished');
@@ -113,7 +115,7 @@ const aiForecastHelper = {
113
115
  async _refreshTimer() {
114
116
  // alten Timer stoppen
115
117
  if (this.timer) {
116
- clearInterval(this.timer);
118
+ this.adapter.clearInterval(this.timer);
117
119
  this.timer = null;
118
120
  }
119
121
 
@@ -132,7 +134,7 @@ const aiForecastHelper = {
132
134
  );
133
135
 
134
136
  // minütlicher Check
135
- this.timer = setInterval(async () => {
137
+ this.timer = this.adapter.setInterval(async () => {
136
138
  const now = new Date();
137
139
  if (now.getHours() === time.hour && now.getMinutes() === time.minute) {
138
140
  try {
@@ -123,7 +123,9 @@ const aiHelper = {
123
123
  // ----------------------------------------------------------
124
124
  // NEU: Delay, damit ioBroker alle States laden kann
125
125
  // ----------------------------------------------------------
126
- await new Promise(res => setTimeout(res, 1500));
126
+ await new Promise(resolve => {
127
+ this.adapter.setTimeout(resolve, 1500);
128
+ });
127
129
 
128
130
  // NEU: Wenn Uhrzeit heute noch in der Zukunft liegt → sofort ausführen
129
131
  try {
@@ -183,7 +185,7 @@ const aiHelper = {
183
185
  */
184
186
  _clearTimers() {
185
187
  for (const t of this.timers) {
186
- clearInterval(t);
188
+ this.adapter.clearInterval(t);
187
189
  }
188
190
  this.timers = [];
189
191
  },
@@ -257,7 +259,7 @@ const aiHelper = {
257
259
  //--------------------------------------------------------
258
260
  this.adapter.log.debug('[aiHelper] setting hourly weather update timer');
259
261
 
260
- const hourlyTimer = setInterval(
262
+ const hourlyTimer = this.adapter.setInterval(
261
263
  async () => {
262
264
  try {
263
265
  const geo = await this._loadGeoLocation();
@@ -303,7 +305,7 @@ const aiHelper = {
303
305
  */
304
306
  _createDailyTimer(timeObj, callback) {
305
307
  const { hour, minute } = timeObj;
306
- const timer = setInterval(async () => {
308
+ const timer = this.adapter.setInterval(async () => {
307
309
  const now = new Date();
308
310
 
309
311
  // --- FIX: Nachholen nur in den ersten 3 Minuten nach Adapterstart ---
@@ -3,7 +3,7 @@
3
3
  const { I18n } = require('@iobroker/adapter-core');
4
4
 
5
5
  const POOL_INSIGHTS_PREFIX = 'analytics.insights.pool';
6
- const DAILY_ANALYSIS_HOUR = 20;
6
+ const DEFAULT_DAILY_ANALYSIS_TIME = '20:00';
7
7
  const SPEECH_COOLDOWN_MS = 6 * 60 * 60 * 1000;
8
8
 
9
9
  const poolInsightsHelper = {
@@ -15,6 +15,7 @@ const poolInsightsHelper = {
15
15
  this.adapter = adapter;
16
16
 
17
17
  this.adapter.subscribeStates(`${POOL_INSIGHTS_PREFIX}.enabled`);
18
+ this.adapter.subscribeStates(`${POOL_INSIGHTS_PREFIX}.schedule_time`);
18
19
  this.adapter.subscribeStates(`${POOL_INSIGHTS_PREFIX}.manual_trigger`);
19
20
  this.adapter.subscribeStates(`${POOL_INSIGHTS_PREFIX}.send_to_speech_queue`);
20
21
 
@@ -32,7 +33,7 @@ const poolInsightsHelper = {
32
33
  return;
33
34
  }
34
35
 
35
- if (id.endsWith(`${POOL_INSIGHTS_PREFIX}.enabled`)) {
36
+ if (id.endsWith(`${POOL_INSIGHTS_PREFIX}.enabled`) || id.endsWith(`${POOL_INSIGHTS_PREFIX}.schedule_time`)) {
36
37
  void this._refreshSchedule();
37
38
  }
38
39
  },
@@ -66,9 +67,11 @@ const poolInsightsHelper = {
66
67
  this.dailyTimer = null;
67
68
  }
68
69
 
70
+ const scheduleTime = await this._readString(`${POOL_INSIGHTS_PREFIX}.schedule_time`);
71
+ const { hours, minutes } = this._parseScheduleTime(scheduleTime);
69
72
  const now = new Date();
70
73
  const next = new Date(now);
71
- next.setHours(DAILY_ANALYSIS_HOUR, 0, 0, 0);
74
+ next.setHours(hours, minutes, 0, 0);
72
75
  if (next <= now) {
73
76
  next.setDate(next.getDate() + 1);
74
77
  }
@@ -84,6 +87,24 @@ const poolInsightsHelper = {
84
87
  this.adapter.log.debug(`[poolInsightsHelper] Daily analysis scheduled for ${next.toISOString()}`);
85
88
  },
86
89
 
90
+ _parseScheduleTime(value) {
91
+ const match = /^([01]\d|2[0-3]):([0-5]\d)$/.exec(value);
92
+ if (match) {
93
+ return {
94
+ hours: Number(match[1]),
95
+ minutes: Number(match[2]),
96
+ };
97
+ }
98
+
99
+ this.adapter.log.debug(
100
+ `[poolInsightsHelper] Invalid schedule_time ${value}, using fallback ${DEFAULT_DAILY_ANALYSIS_TIME}`,
101
+ );
102
+ return {
103
+ hours: 20,
104
+ minutes: 0,
105
+ };
106
+ },
107
+
87
108
  async _runAnalysis(reason, allowSpeech) {
88
109
  if (this.running) {
89
110
  this.adapter.log.debug('[poolInsightsHelper] Analysis already running - skipped');
@@ -177,11 +198,19 @@ const poolInsightsHelper = {
177
198
 
178
199
  if (tempDelta <= 0.2) {
179
200
  level = this._raiseLevel(level, 'info');
180
- recommendations.push({
181
- area: 'temperature',
182
- level: 'info',
183
- text: this._translate('pool_insights_recommendation_temperature_low_change'),
184
- });
201
+ recommendations.push(
202
+ this._createRecommendation(
203
+ 'temperature',
204
+ 'info',
205
+ 'low_temperature_change',
206
+ 0.7,
207
+ this._translate('pool_insights_recommendation_temperature_low_change'),
208
+ ['temperature.surface.min_today', 'temperature.surface.max_today'],
209
+ {
210
+ temperature_delta_c: rounded,
211
+ },
212
+ ),
213
+ );
185
214
  }
186
215
  }
187
216
 
@@ -208,11 +237,19 @@ const poolInsightsHelper = {
208
237
 
209
238
  if (snapshot.pump.startCountToday > 12) {
210
239
  level = this._raiseLevel(level, 'info');
211
- recommendations.push({
212
- area: 'pump',
213
- level: 'info',
214
- text: this._translate('pool_insights_recommendation_many_pump_starts'),
215
- });
240
+ recommendations.push(
241
+ this._createRecommendation(
242
+ 'pump',
243
+ 'info',
244
+ 'many_pump_starts',
245
+ 0.8,
246
+ this._translate('pool_insights_recommendation_many_pump_starts'),
247
+ ['runtime.start_count_today'],
248
+ {
249
+ starts_today: snapshot.pump.startCountToday,
250
+ },
251
+ ),
252
+ );
216
253
  }
217
254
  }
218
255
 
@@ -223,11 +260,19 @@ const poolInsightsHelper = {
223
260
  level: 'warning',
224
261
  text: this._translate('pool_insights_observation_pump_error'),
225
262
  });
226
- recommendations.push({
227
- area: 'pump',
228
- level: 'warning',
229
- text: this._translate('pool_insights_recommendation_pump_error'),
230
- });
263
+ recommendations.push(
264
+ this._createRecommendation(
265
+ 'pump',
266
+ 'warning',
267
+ 'pump_error_active',
268
+ 1,
269
+ this._translate('pool_insights_recommendation_pump_error'),
270
+ ['pump.error'],
271
+ {
272
+ pump_error: true,
273
+ },
274
+ ),
275
+ );
231
276
  }
232
277
 
233
278
  this._appendSolarObservations(snapshot.solar, observations);
@@ -235,11 +280,19 @@ const poolInsightsHelper = {
235
280
 
236
281
  if (snapshot.photovoltaic.startsToday !== null && snapshot.photovoltaic.startsToday > 10) {
237
282
  level = this._raiseLevel(level, 'info');
238
- recommendations.push({
239
- area: 'photovoltaic',
240
- level: 'info',
241
- text: this._translate('pool_insights_recommendation_many_pv_starts'),
242
- });
283
+ recommendations.push(
284
+ this._createRecommendation(
285
+ 'photovoltaic',
286
+ 'info',
287
+ 'many_pv_starts',
288
+ 0.8,
289
+ this._translate('pool_insights_recommendation_many_pv_starts'),
290
+ ['analytics.insights.photovoltaic.results.starts_today'],
291
+ {
292
+ pv_starts_today: snapshot.photovoltaic.startsToday,
293
+ },
294
+ ),
295
+ );
243
296
  }
244
297
 
245
298
  this._appendConsumptionObservations(snapshot.consumption, observations);
@@ -570,6 +623,60 @@ const poolInsightsHelper = {
570
623
  await this.adapter.setStateChangedAsync(id, { val, ack });
571
624
  },
572
625
 
626
+ _createRecommendation(area, level, reason, confidence, text, sourceStates = [], evidence = {}) {
627
+ return {
628
+ area: String(area || ''),
629
+ level: String(level || ''),
630
+ reason: String(reason || ''),
631
+ confidence: this._clampConfidence(confidence),
632
+ text: String(text || ''),
633
+ source_states: Array.isArray(sourceStates)
634
+ ? sourceStates.filter(value => value !== undefined).map(value => String(value))
635
+ : [],
636
+ evidence: this._cleanEvidence(evidence),
637
+ };
638
+ },
639
+
640
+ _clampConfidence(value) {
641
+ const confidence = Number(value);
642
+ if (!Number.isFinite(confidence)) {
643
+ return 0;
644
+ }
645
+ return Math.min(1, Math.max(0, confidence));
646
+ },
647
+
648
+ _cleanEvidence(evidence) {
649
+ if (!evidence || typeof evidence !== 'object' || Array.isArray(evidence)) {
650
+ return {};
651
+ }
652
+
653
+ return this._cleanObject(evidence);
654
+ },
655
+
656
+ _cleanObject(object) {
657
+ const cleaned = {};
658
+ for (const [key, value] of Object.entries(object)) {
659
+ const cleanedValue = this._cleanValue(value);
660
+ if (cleanedValue !== undefined) {
661
+ cleaned[key] = cleanedValue;
662
+ }
663
+ }
664
+ return cleaned;
665
+ },
666
+
667
+ _cleanValue(value) {
668
+ if (value === undefined) {
669
+ return undefined;
670
+ }
671
+ if (Array.isArray(value)) {
672
+ return value.map(entry => this._cleanValue(entry)).filter(entry => entry !== undefined);
673
+ }
674
+ if (value !== null && typeof value === 'object') {
675
+ return this._cleanObject(value);
676
+ }
677
+ return value;
678
+ },
679
+
573
680
  _formatRuntime(seconds) {
574
681
  const totalMinutes = Math.max(0, Math.round(seconds / 60));
575
682
  const hours = Math.floor(totalMinutes / 60);
@@ -84,6 +84,25 @@ async function createPoolInsightsStates(adapter) {
84
84
  persist: true,
85
85
  },
86
86
  },
87
+ {
88
+ id: 'analytics.insights.pool.schedule_time',
89
+ common: {
90
+ name: {
91
+ en: 'Daily pool insights analysis time',
92
+ de: 'Uhrzeit der täglichen Pool-Insights-Analyse',
93
+ },
94
+ desc: {
95
+ en: 'Time for the daily automatic pool insights analysis in HH:mm format.',
96
+ de: 'Uhrzeit für die tägliche automatische Pool-Insights-Analyse im Format HH:mm.',
97
+ },
98
+ type: 'string',
99
+ role: 'text',
100
+ read: true,
101
+ write: true,
102
+ def: '20:00',
103
+ persist: true,
104
+ },
105
+ },
87
106
  {
88
107
  id: 'analytics.insights.pool.manual_trigger',
89
108
  common: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.poolcontrol",
3
- "version": "1.3.29",
3
+ "version": "1.3.30",
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",
@@ -24,7 +24,7 @@
24
24
  "@iobroker/adapter-core": "^3.3.2"
25
25
  },
26
26
  "devDependencies": {
27
- "@alcalzone/release-script": "^5.2.0",
27
+ "@alcalzone/release-script": "^5.2.1",
28
28
  "@alcalzone/release-script-plugin-iobroker": "^5.2.0",
29
29
  "@alcalzone/release-script-plugin-license": "^5.2.0",
30
30
  "@alcalzone/release-script-plugin-manual-review": "^5.2.0",