iobroker.poolcontrol 0.5.4 → 0.6.0

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
@@ -19,7 +19,8 @@ Er ermöglicht die Automatisierung von Pumpen-, Temperatur- und Solarsteuerung s
19
19
  ## Funktionen
20
20
 
21
21
  - **Pumpensteuerung**
22
- - Betriebsmodi: Automatik, Manuell, Zeitsteuerung, Aus
22
+ - Betriebsmodi: Automatik, Automatik (PV), Manuell, Zeitsteuerung, Aus
23
+ - Automatik (PV) steuert die Pumpe abhängig vom Photovoltaik-Überschuss
23
24
  - Fehlererkennung (kein Stromverbrauch, Leistung trotz „AUS“, Überlast)
24
25
  - Sicherheitsfunktionen (Frostschutz, Überhitzungsschutz)
25
26
 
@@ -34,12 +35,24 @@ Er ermöglicht die Automatisierung von Pumpen-, Temperatur- und Solarsteuerung s
34
35
  - Kollektor-Warnung (mit automatischer Rücksetzung bei 10 % unter der Schwelle)
35
36
  - Optionale Sprachausgabe bei Warnung
36
37
 
38
+ - **Photovoltaiksteuerung (ab v0.6.0)
39
+ - Automatische Pumpensteuerung auf Basis von PV-Erzeugung und Hausverbrauchs
40
+ - Einschaltlogik: Überschuss ≥ (Pumpen-Nennleistung + Sicherheitsaufschlag)
41
+ - Optionaler Nachlauf bei Wolkenphasen
42
+ - Ignorieren bei erreichter Tagesumwälzung
43
+ - Konfiguration über zwei Fremd-Objekt-IDs (power_generated_id, power_house_id)
44
+ - Neuer Pumpenmodus „Automatik (PV)
45
+
37
46
  - **Zeitsteuerung**
38
47
  - Bis zu 3 frei konfigurierbare Zeitfenster pro Woche
39
48
 
40
49
  - **Laufzeit & Umwälzung**
41
50
  - Zählt Laufzeiten (heute, gesamt)
42
51
  - Berechnet tägliche Umwälzung und Restmenge
52
+ - Rückspülerinnerung mit konfigurierbarem Intervall (z. B. alle 7 Tage)
53
+ - Anzeige der letzten Rückspülung inkl. Datum
54
+ - Automatische Rücksetzung nach erfolgter Rückspülung
55
+ - PV-Modus berücksichtigt Umwälzstatus (z. B. „Ignoriere bei Umwälzung erreicht“)
43
56
 
44
57
  - **Verbrauch & Kosten**
45
58
  - Auswertung eines externen kWh-Zählers
@@ -49,16 +62,19 @@ Er ermöglicht die Automatisierung von Pumpen-, Temperatur- und Solarsteuerung s
49
62
  **Hinweis:**
50
63
  Details zum Verhalten der Verbrauchs- und Kostenwerte (z. B. bei Neustarts oder beim Wechsel des Stromzählers) finden Sie in der Datei [help.md](./help.md).
51
64
 
65
+ - **Statistiksystem**
66
+ - Bereich `analytics.statistics.*` mit Tages-, Wochen- und Monatswerten
67
+ - Automatische Berechnung von Min-, Max-, Durchschnitts- und Laufzeitwerten
68
+ - Vollständig persistente Datenpunkte (Überinstallationsschutz)
69
+ - HTML- und JSON-Zusammenfassungen pro Sensor und Gesamtübersicht
70
+
52
71
  - **Sprachausgaben**
53
72
  - Ausgabe über Alexa oder Telegram
54
73
  - Ansagen bei Pumpenstart/-stopp, Fehlern oder Temperaturschwellen
55
74
 
56
75
  - **SystemCheck (Diagnosebereich)**
57
- Ab Version **0.2.0** enthält der Adapter einen neuen Diagnosebereich **SystemCheck**.
58
- Er bietet interne Debug-Logs, mit denen bestimmte Teilbereiche (z. B. Pumpen-, Solar- oder Temperatursteuerung) gezielt überwacht werden können.
59
-
60
- *Funktionen:*
61
- - Auswahl des zu überwachenden Bereichs
76
+ - Interner Diagnosebereich für Debug- und Überwachungsfunktionen
77
+ - Auswahl des zu überwachenden Bereichs (z. B. Pumpe, Solar, Temperatur)
62
78
  - Fortlaufendes Log der letzten Änderungen
63
79
  - Manuelles Löschen des Logs möglich
64
80
 
@@ -90,26 +106,24 @@ Die Konfiguration erfolgt über Tabs im Admin-Interface:
90
106
 
91
107
  ## Geplante Erweiterungen
92
108
 
93
- - Rückspülerinnerung (Intervall in Tagen, Erinnerung über State)
94
- - Wartung Kesseldruck (maximaler Druck, Warnung bei Überschreitung)
95
- - Weitere Komfortfunktionen nach Praxistests
96
- - Kesseldruck-Wartung / Drucksensor-Warnung
97
- - PV-Überschuss-Steuerung (für z.B. Pumpe oder Wärmepumpe)
98
- - Zweite Pumpe (z.B. Wärmetauscher)
99
- - Statistikbereich
100
- - Eigene Widgets für VIS/VIS2
101
- - Erweiterung Wärmepumpen-/Heizlogik
102
- - Steuerung von Poolbeleuchtung
103
- - Steuerung von Poolrobotern
104
- - Steuerung von elektrischen Ventilen
105
- - Steuerung von Gegenstromanlagen
109
+ - Erweiterte PV- und Solar-Effizienzanalyse (COP-Berechnung, Tagesnutzen, Wetterintegration)
110
+ - Statistik-Exportfunktion (CSV/Excel)
111
+ - Diagnostic-Helper zur automatischen Systemprüfung
112
+ - Erweiterung der Heizungs-/Wärmepumpenlogik (`heatHelper`)
113
+ - Drucksensor-Integration zur Kesseldruck-Überwachung
114
+ - Zweite Pumpe (z. B. Wärmetauscher oder Wärmepumpe)
115
+ - Eigene Widgets für VIS/VIS2 (grafische Pool- und Solarvisualisierung)
116
+ - Steuerung von Poolbeleuchtung, Ventilen und Gegenstromanlagen
117
+ - Integration zusätzlicher Sensorboxen (z. B. TempBox, PressureBox, LevelBox)
118
+ - KI- und Sprach-Assistenten-Erweiterung (Pool-Tagesbericht, Tipps, Sprachbefehle)
119
+
106
120
 
107
121
  ---
108
122
 
109
123
  ## Hinweis
110
124
 
111
- Der Adapter befindet sich aktuell in der Entwicklung.
112
- Funktionen können sich ändern – bitte regelmäßig den Changelog beachten.
125
+ Der Adapter befindet sich in aktiver Weiterentwicklung.
126
+ Neue Funktionen werden regelmäßig ergänzt – bitte den Changelog beachten.
113
127
 
114
128
  ---
115
129
 
@@ -121,6 +135,18 @@ Funktionen können sich ändern – bitte regelmäßig den Changelog beachten.
121
135
  ## Changelog
122
136
  ### **WORK IN PROGRESS**
123
137
 
138
+ ## v0.6.0 (2025-11-03)
139
+ - Einführung der vollständigen Photovoltaik-Steuerung mit automatischer Pumpenlogik
140
+ (neuer Pumpenmodus `Automatik (PV)` unter `pump.mode`)
141
+ - Adapter reagiert auf PV-Überschuss basierend auf konfigurierbarer Hausverbrauchs- und Erzeugungsleistung
142
+ - Einschaltlogik: Pumpe EIN bei Überschuss ≥ (Nennleistung + Schwellwert)
143
+ - Berücksichtigung von Saisonstatus, Nachlaufzeit und optionalem „Umwälzung erreicht“-Schutz
144
+ - Automatische Migration ergänzt neuen Modus `auto_pv` in bestehenden Installationen
145
+ - Verbesserte interne Logik, Persistenz und Debug-Protokollierung
146
+
147
+ ## v0.5.5 (2025-11-01)
148
+ - Endlosschleife in Statistik Woche und Monat behoben
149
+
124
150
  ## v0.5.3 (2025-10-30)
125
151
  - Telegram-Benutzerwahl hinzugefügt
126
152
 
@@ -851,8 +851,7 @@
851
851
  },
852
852
  "speech_telegram_placeholder": {
853
853
  "type": "staticText",
854
- "label": "",
855
- "text": "",
854
+ "text": " ",
856
855
  "xs": 12,
857
856
  "sm": 3,
858
857
  "md": 3,
@@ -863,7 +862,6 @@
863
862
  "speech_telegram_users": {
864
863
  "type": "text",
865
864
  "label": "Telegram-Empfänger (Benutzernamen, Komma-getrennt / leer = an alle Benutzer)",
866
- "attr": "speech_telegram_users",
867
865
  "tooltip": "Beispiel: Dirk,Dennis (leer = an alle Benutzer senden)",
868
866
  "default": "",
869
867
  "xs": 12,
@@ -948,7 +946,7 @@
948
946
  },
949
947
  "consumption": {
950
948
  "type": "panel",
951
- "label": "Verbrauch & Kosten",
949
+ "label": "PV, Verbrauch & Kosten",
952
950
  "items": {
953
951
  "divider_cons1": {
954
952
  "type": "divider",
@@ -1004,7 +1002,59 @@
1004
1002
  "md": 12,
1005
1003
  "lg": 12,
1006
1004
  "xl": 12
1007
- }
1005
+ },
1006
+
1007
+ "divider_pv1": {
1008
+ "type": "divider",
1009
+ "newLine": true
1010
+ },
1011
+ "pv_header": {
1012
+ "type": "header",
1013
+ "text": "Photovoltaik (Überschusserkennung)",
1014
+ "size": 4,
1015
+ "newLine": true,
1016
+ "xs": 12,
1017
+ "sm": 12,
1018
+ "md": 12,
1019
+ "lg": 12,
1020
+ "xl": 12
1021
+ },
1022
+ "power_generated_id": {
1023
+ "type": "objectId",
1024
+ "label": "Objekt-ID PV-Erzeugungsleistung (W)",
1025
+ "default": "",
1026
+ "xs": 12,
1027
+ "sm": 6,
1028
+ "md": 6,
1029
+ "lg": 6,
1030
+ "xl": 6,
1031
+ "tooltip": "Datenpunkt mit aktueller PV-Leistung (Watt)"
1032
+ },
1033
+ "power_house_id": {
1034
+ "type": "objectId",
1035
+ "label": "Objekt-ID Hausverbrauch (W)",
1036
+ "default": "",
1037
+ "xs": 12,
1038
+ "sm": 6,
1039
+ "md": 6,
1040
+ "lg": 6,
1041
+ "xl": 6,
1042
+ "tooltip": "Datenpunkt mit aktuellem Hausverbrauch (Watt)"
1043
+ },
1044
+ "threshold_w": {
1045
+ "type": "number",
1046
+ "label": "Schwellwert für PV-Überschuss (W)",
1047
+ "default": 200,
1048
+ "min": 0,
1049
+ "max": 2000,
1050
+ "step": 50,
1051
+ "xs": 12,
1052
+ "sm": 3,
1053
+ "md": 3,
1054
+ "lg": 3,
1055
+ "xl": 3,
1056
+ "tooltip": "Ab welcher Differenz zwischen PV und Hausverbrauch ein Überschuss gilt"
1057
+ }
1008
1058
  }
1009
1059
  },
1010
1060
  "help": {
package/io-package.json CHANGED
@@ -1,8 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "poolcontrol",
4
- "version": "0.5.4",
4
+ "version": "0.6.0",
5
5
  "news": {
6
+ "0.6.0": {
7
+ "en": "Added complete photovoltaic control with automatic pump management (mode 'Automatik (PV)'). The adapter can now react to PV surplus based on configurable house consumption and generation values. Includes migration for existing installations. Improved system consistency and internal logging.",
8
+ "de": "Vollständige Photovoltaik-Steuerung mit automatischer Pumpenlogik (Modus 'Automatik (PV)') hinzugefügt. Der Adapter reagiert nun auf PV-Überschuss anhand konfigurierbarer Hausverbrauchs- und Erzeugungswerte. Migration für bestehende Installationen integriert. Systemkonsistenz und interne Protokollierung verbessert.",
9
+ "ru": "Добавлено полное управление фотоэлектрической системой с автоматическим управлением насосом (режим 'Automatik (PV)'). Адаптер теперь реагирует на избыток PV на основе настраиваемых значений потребления и генерации. Включена миграция для существующих установок. Улучшена системная согласованность и внутреннее ведение журнала.",
10
+ "pt": "Adicionado controle fotovoltaico completo com gerenciamento automático da bomba (modo 'Automatik (PV)'). O adaptador agora reage ao excedente de PV com base nos valores configuráveis de consumo e geração da casa. Inclui migração para instalações existentes. Consistência do sistema e registro interno aprimorados.",
11
+ "nl": "Volledige fotovoltaïsche besturing toegevoegd met automatische pompbesturing (modus 'Automatik (PV)'). De adapter reageert nu op PV-overschot op basis van configureerbare huisverbruik- en opwekkingswaarden. Migratie voor bestaande installaties inbegrepen. Verbeterde systeemconsistentie en interne logboekregistratie.",
12
+ "fr": "Ajout du contrôle photovoltaïque complet avec gestion automatique de la pompe (mode 'Automatik (PV)'). L'adaptateur réagit désormais au surplus photovoltaïque en fonction des valeurs configurables de consommation et de production domestiques. Migration incluse pour les installations existantes. Cohérence du système et journalisation interne améliorées.",
13
+ "it": "Aggiunto controllo fotovoltaico completo con gestione automatica della pompa (modalità 'Automatik (PV)'). L'adattatore ora reagisce al surplus fotovoltaico in base ai valori configurabili di consumo e generazione domestici. Migrazione inclusa per le installazioni esistenti. Migliorata la coerenza del sistema e la registrazione interna.",
14
+ "es": "Se añadió control fotovoltaico completo con gestión automática de la bomba (modo 'Automatik (PV)'). El adaptador ahora reacciona al excedente fotovoltaico según los valores configurables de consumo y generación de la casa. Incluye migración para instalaciones existentes. Mejorada la coherencia del sistema y el registro interno.",
15
+ "pl": "Dodano pełną kontrolę fotowoltaiczną z automatycznym zarządzaniem pompą (tryb 'Automatik (PV)'). Adapter reaguje teraz na nadwyżkę PV w oparciu o konfigurowalne wartości zużycia i produkcji energii. Zawiera migrację dla istniejących instalacji. Poprawiono spójność systemu i wewnętrzne logowanie.",
16
+ "uk": "Додано повний фотогальванічний контроль з автоматичним керуванням насосом (режим 'Automatik (PV)'). Адаптер тепер реагує на надлишок PV на основі налаштовуваних значень споживання та генерації. Включено міграцію для існуючих установок. Покращено системну узгодженість і внутрішнє журналювання.",
17
+ "zh-cn": "新增完整的光伏控制与自动泵管理(模式“Automatik (PV)”)。适配器现在可根据可配置的家庭耗电与发电数值响应光伏盈余。包含对现有安装的迁移。改进了系统一致性和内部日志记录。"
18
+ },
19
+ "0.5.5": {
20
+ "en": "Fixed remaining timer recursion issue in weekly and monthly statistics to fully prevent infinite reset loops. Cleaned up jsonConfig structure and improved timer handling.",
21
+ "de": "Verbleibende Timer-Rekursion in Wochen- und Monatsstatistik behoben, um Endlosschleifen beim Reset endgültig zu verhindern. jsonConfig-Struktur bereinigt und Timer-Handling verbessert.",
22
+ "ru": "Исправлена оставшаяся рекурсия таймера в еженедельной и ежемесячной статистике для полного предотвращения бесконечных циклов сброса. Упрощена структура jsonConfig и улучшено управление таймерами.",
23
+ "pt": "Corrigida a recursão restante do temporizador nas estatísticas semanais e mensais para evitar completamente loops de redefinição infinitos. Estrutura jsonConfig limpa e manuseio de temporizador aprimorado.",
24
+ "nl": "Overgebleven timerrecursie in week- en maandstatistieken opgelost om oneindige resetlussen volledig te voorkomen. jsonConfig-structuur opgeschoond en timerafhandeling verbeterd.",
25
+ "fr": "Correction de la récursion restante du minuteur dans les statistiques hebdomadaires et mensuelles afin d'éviter définitivement les boucles de réinitialisation infinies. Structure jsonConfig nettoyée et gestion du minuteur améliorée.",
26
+ "it": "Corretta la ricorsione residua del timer nelle statistiche settimanali e mensili per prevenire completamente i loop di reset infiniti. Pulita la struttura jsonConfig e migliorata la gestione dei timer.",
27
+ "es": "Corregida la recursión restante del temporizador en las estadísticas semanales y mensuales para evitar completamente los bucles de reinicio infinitos. Estructura jsonConfig limpiada y manejo del temporizador mejorado.",
28
+ "pl": "Naprawiono pozostałą rekursję timera w statystykach tygodniowych i miesięcznych, aby całkowicie zapobiec nieskończonym pętlom resetowania. Uporządkowano strukturę jsonConfig i ulepszono obsługę timera.",
29
+ "uk": "Виправлено залишкову рекурсію таймера у тижневій та місячній статистиці, щоб повністю запобігти нескінченним циклам скидання. Очищено структуру jsonConfig і покращено обробку таймерів.",
30
+ "zh-cn": "修复了每周和每月统计中的剩余计时器递归问题,以完全防止无限重置循环。清理了 jsonConfig 结构并改进了计时器处理。"
31
+ },
6
32
  "0.5.4": {
7
33
  "en": "Fixed a rare infinite loop during weekly and monthly statistics reset that could cause Redis overload. Added timer protection and improved stability.",
8
34
  "de": "Selten auftretende Endlosschleife beim Wochen- und Monatsreset der Statistik behoben, die zu Redis-Überlastung führen konnte. Timer-Schutz und Stabilität verbessert.",
@@ -65,33 +91,7 @@
65
91
  "pl": "Dodano tygodniowe i miesięczne statystyki temperatury w analytics.statistics.temperature.week i analytics.statistics.temperature.month z automatycznymi podsumowaniami, niezależnymi pomocnikami i trwałymi punktami danych.",
66
92
  "uk": "Додано щотижневу та щомісячну статистику температури в analytics.statistics.temperature.week та analytics.statistics.temperature.month з автоматичними зведеннями, незалежними помічниками та постійними точками даних.",
67
93
  "zh-cn": "在 analytics.statistics.temperature.week 和 analytics.statistics.temperature.month 中添加了每周和每月温度统计,具有自动摘要、独立助手和持久数据点。"
68
- },
69
- "0.4.0": {
70
- "en": "Added daily temperature statistics under analytics.statistics.temperature.today with automatic min/max/average tracking, JSON and HTML summaries, and midnight reset logic.",
71
- "de": "Tägliche Temperaturstatistik unter analytics.statistics.temperature.today hinzugefügt mit automatischer Erfassung von Min-/Max-/Durchschnittswerten, JSON- und HTML-Zusammenfassungen sowie Mitternachts-Reset.",
72
- "ru": "Добавлена ежедневная статистика температуры в analytics.statistics.temperature.today с автоматическим отслеживанием мин./макс./средних значений, JSON и HTML сводками и логикой сброса в полночь.",
73
- "pt": "Adicionadas estatísticas diárias de temperatura em analytics.statistics.temperature.today com rastreamento automático de mínimo/máximo/média, resumos em JSON e HTML e redefinição automática à meia-noite.",
74
- "nl": "Dagelijkse temperatuurstatistieken toegevoegd onder analytics.statistics.temperature.today met automatische min/max/gemiddelde tracking, JSON- en HTML-samenvattingen en middernachtreset.",
75
- "fr": "Ajout de statistiques quotidiennes de température sous analytics.statistics.temperature.today avec suivi automatique min/max/moyenne, résumés JSON et HTML et réinitialisation automatique à minuit.",
76
- "it": "Aggiunte statistiche giornaliere della temperatura in analytics.statistics.temperature.today con monitoraggio automatico di min/max/media, riepiloghi JSON e HTML e reset automatico a mezzanotte.",
77
- "es": "Se añadieron estadísticas diarias de temperatura en analytics.statistics.temperature.today con seguimiento automático de mínimos/máximos/promedios, resúmenes en JSON y HTML y reinicio automático a medianoche.",
78
- "pl": "Dodano dzienne statystyki temperatury w analytics.statistics.temperature.today z automatycznym śledzeniem wartości min/max/średnich, podsumowaniami JSON i HTML oraz resetem o północy.",
79
- "uk": "Додано щоденну статистику температури в analytics.statistics.temperature.today з автоматичним відстеженням мін/макс/середніх значень, JSON і HTML зведеннями та скиданням опівночі.",
80
- "zh-cn": "在 analytics.statistics.temperature.today 中添加了每日温度统计,具有自动最小/最大/平均跟踪、JSON 和 HTML 摘要以及午夜重置功能。"
81
- },
82
- "0.3.1": {
83
- "en": "Frost protection logic stabilized: fixed hysteresis of +2 °C and rounded temperature values to avoid pump switching fluctuations around 3 °C.",
84
- "de": "Frostschutz-Logik stabilisiert: feste Hysterese von +2 °C und gerundete Temperaturwerte zur Vermeidung von Pumpenschaltflattern um 3 °C.",
85
- "ru": "Логика защиты от замерзания стабилизирована: фиксированная гистерезис +2 °C и округленные значения температуры для предотвращения колебаний включения насоса около 3 °C.",
86
- "pt": "Lógica de proteção contra congelamento estabilizada: histerese fixa de +2 °C e valores de temperatura arredondados para evitar flutuações de comutação da bomba em torno de 3 °C.",
87
- "nl": "Vorstbeschermingslogica gestabiliseerd: vaste hysterese van +2 °C en afgeronde temperatuurwaarden om pompfluctuaties rond 3 °C te voorkomen.",
88
- "fr": "Logique de protection antigel stabilisée : hystérésis fixe de +2 °C et valeurs de température arrondies pour éviter les fluctuations de commutation de la pompe autour de 3 °C.",
89
- "it": "Logica di protezione antigelo stabilizzata: isteresi fissa di +2 °C e valori di temperatura arrotondati per evitare fluttuazioni di commutazione della pompa intorno a 3 °C.",
90
- "es": "Lógica de protección contra heladas estabilizada: histéresis fija de +2 °C y valores de temperatura redondeados para evitar fluctuaciones de conmutación de la bomba alrededor de 3 °C.",
91
- "pl": "Ustabilizowano logikę ochrony przed zamarzaniem: stała histereza +2 °C i zaokrąglone wartości temperatury, aby uniknąć wahań przełączania pompy w okolicach 3 °C.",
92
- "uk": "Стабілізовано логіку захисту від замерзання: фіксована гістерезис +2 °C і округлені значення температури, щоб уникнути коливань увімкнення насоса біля 3 °C.",
93
- "zh-cn": "防冻逻辑稳定:固定 +2 °C 滞后并四舍五入温度值,以避免泵在 3 °C 附近频繁切换。"
94
- }
94
+ }
95
95
  },
96
96
  "titleLang": {
97
97
  "en": "PoolControl",
@@ -9,7 +9,7 @@
9
9
  * - Wird beim Adapterstart einmalig ausgeführt.
10
10
  * - Korrigiert veraltete Definitionen (z. B. Schreibrechte, persist-Flags, etc.)
11
11
  *
12
- * Version: 1.0.1
12
+ * Version: 1.0.2
13
13
  */
14
14
 
15
15
  const migrationHelper = {
@@ -31,6 +31,7 @@ const migrationHelper = {
31
31
  // ------------------------------------------------------
32
32
  await this._fixSpeechQueue();
33
33
  await this._fixSolarWarnActivePersist();
34
+ await this._fixPumpModeStates(); // NEU: PV-Automatik hinzufügen
34
35
 
35
36
  // Weitere Routinen folgen hier später:
36
37
  // await this._ensurePumpReason();
@@ -112,6 +113,39 @@ const migrationHelper = {
112
113
  this.adapter.log.warn(`[migrationHelper] Fehler bei Prüfung von ${id}: ${err.message}`);
113
114
  }
114
115
  },
116
+
117
+ // ------------------------------------------------------
118
+ // Migration: Ergänze neuen Pumpenmodus "Automatik (PV)"
119
+ // ------------------------------------------------------
120
+
121
+ /**
122
+ * Prüft den State pump.mode und ergänzt, falls nötig, den neuen
123
+ * Eintrag "auto_pv" → "Automatik (PV)".
124
+ * Dadurch wird der PV-Modus automatisch in bestehenden Installationen sichtbar.
125
+ */
126
+ async _fixPumpModeStates() {
127
+ const id = 'pump.mode';
128
+ try {
129
+ const obj = await this.adapter.getObjectAsync(id);
130
+ if (!obj) {
131
+ this.adapter.log.debug(`[migrationHelper] ${id} existiert nicht – keine Anpassung nötig.`);
132
+ return;
133
+ }
134
+
135
+ const states = obj.common?.states || {};
136
+ if (!states.auto_pv) {
137
+ states.auto_pv = 'Automatik (PV)';
138
+ this.adapter.log.info(`[migrationHelper] Ergänze neuen Modus "Automatik (PV)" in pump.mode`);
139
+ await this.adapter.extendObjectAsync(id, {
140
+ common: { states },
141
+ });
142
+ } else {
143
+ this.adapter.log.debug(`[migrationHelper] pump.mode enthält bereits "Automatik (PV)".`);
144
+ }
145
+ } catch (err) {
146
+ this.adapter.log.warn(`[migrationHelper] Fehler bei Prüfung von ${id}: ${err.message}`);
147
+ }
148
+ },
115
149
  };
116
150
 
117
151
  module.exports = migrationHelper;
@@ -0,0 +1,273 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * photovoltaicHelper
5
+ * -------------------------------------------------------------
6
+ * - Liest PV-Erzeugung und Hausverbrauch (Foreign States aus Admin-Config)
7
+ * - Berechnet Überschussleistung und setzt Photovoltaik-States
8
+ * - Schaltet die Pumpe nur im Modus 'auto_pv' über pump.pump_switch
9
+ * - Respektiert Saison, Nachlaufzeit (Entprellung) und optionales "Umwälzung erreicht"
10
+ * - Einschaltlogik: Überschuss >= (pump_max_watt + threshold_w)
11
+ * -------------------------------------------------------------
12
+ */
13
+
14
+ const photovoltaicHelper = {
15
+ adapter: null,
16
+ genId: null,
17
+ houseId: null,
18
+ afterrunTimer: null,
19
+ _pvPumpHoldUntil: 0,
20
+ _desiredPump: null,
21
+ _lastCalc: 0,
22
+
23
+ init(adapter) {
24
+ this.adapter = adapter;
25
+
26
+ this.genId = adapter.config?.power_generated_id || '';
27
+ this.houseId = adapter.config?.power_house_id || '';
28
+
29
+ if (!this.genId || !this.houseId) {
30
+ this.adapter.log.info(
31
+ '[photovoltaicHelper] PV-IDs in der Instanz-Konfiguration fehlen. Überschusserkennung bleibt passiv.',
32
+ );
33
+ } else {
34
+ try {
35
+ this.adapter.subscribeForeignStates(this.genId);
36
+ this.adapter.subscribeForeignStates(this.houseId);
37
+ this.adapter.log.info(`[photovoltaicHelper] Subscribed: PV="${this.genId}", Haus="${this.houseId}"`);
38
+ } catch (err) {
39
+ this.adapter.log.warn(`[photovoltaicHelper] Konnte Foreign-States nicht abonnieren: ${err.message}`);
40
+ }
41
+ }
42
+
43
+ this.adapter.subscribeStates('photovoltaic.afterrun_min');
44
+ this.adapter.subscribeStates('photovoltaic.ignore_on_circulation');
45
+ this.adapter.subscribeStates('status.season_active');
46
+ this.adapter.subscribeStates('pump.mode');
47
+
48
+ this._safeRecalc('init');
49
+ this.adapter.log.info('[photovoltaicHelper] Initialisierung abgeschlossen.');
50
+ },
51
+
52
+ async handleStateChange(id, state) {
53
+ if (!state) {
54
+ return;
55
+ }
56
+ try {
57
+ if (this.genId && id === this.genId) {
58
+ await this._updateNumberState('photovoltaic.power_generated_w', Number(state.val) || 0);
59
+ await this._safeRecalc('foreign:pv');
60
+ return;
61
+ }
62
+ if (this.houseId && id === this.houseId) {
63
+ await this._updateNumberState('photovoltaic.power_house_w', Number(state.val) || 0);
64
+ await this._safeRecalc('foreign:house');
65
+ return;
66
+ }
67
+
68
+ if (id.endsWith('photovoltaic.afterrun_min')) {
69
+ this.adapter.log.debug(`[photovoltaicHelper] Nachlaufzeit geändert auf ${Number(state.val) || 0} min`);
70
+ return;
71
+ }
72
+ if (id.endsWith('photovoltaic.ignore_on_circulation')) {
73
+ this.adapter.log.debug(
74
+ `[photovoltaicHelper] Flag "PV ignorieren bei Umwälzung erreicht" = ${!!state.val}`,
75
+ );
76
+ return;
77
+ }
78
+
79
+ if (id.endsWith('status.season_active') || id.endsWith('pump.mode')) {
80
+ await this._safeRecalc('mode/season');
81
+ return;
82
+ }
83
+ } catch (err) {
84
+ this.adapter.log.warn(`[photovoltaicHelper] Fehler in handleStateChange: ${err.message}`);
85
+ }
86
+ },
87
+
88
+ async _recalc(_sourceTag = '') {
89
+ const now = Date.now();
90
+ if (now - this._lastCalc < 250) {
91
+ return;
92
+ }
93
+ this._lastCalc = now;
94
+
95
+ const seasonActive = !!(await this.adapter.getStateAsync('status.season_active'))?.val;
96
+ const pumpMode = (await this.adapter.getStateAsync('pump.mode'))?.val || 'auto';
97
+
98
+ const gen = Number((await this.adapter.getStateAsync('photovoltaic.power_generated_w'))?.val ?? 0) || 0;
99
+ const house = Number((await this.adapter.getStateAsync('photovoltaic.power_house_w'))?.val ?? 0) || 0;
100
+
101
+ // Schwelle & Pumpenleistung
102
+ const thresholdState = Number((await this.adapter.getStateAsync('photovoltaic.threshold_w'))?.val ?? NaN);
103
+ const threshold = Number.isFinite(thresholdState)
104
+ ? thresholdState
105
+ : Number(this.adapter.config?.threshold_w || 200);
106
+
107
+ const pumpMax = Number((await this.adapter.getStateAsync('pump.pump_max_watt'))?.val ?? 0);
108
+
109
+ const afterrunMin = Math.max(
110
+ 0,
111
+ Number((await this.adapter.getStateAsync('photovoltaic.afterrun_min'))?.val ?? 0) || 0,
112
+ );
113
+ const ignoreOnCirc = !!((await this.adapter.getStateAsync('photovoltaic.ignore_on_circulation'))?.val ?? false);
114
+
115
+ // SAFETY: Solarüberhitzungsschutz
116
+ try {
117
+ const collectorWarning = !!(await this.adapter.getStateAsync('solar.collector_warning'))?.val;
118
+ if (collectorWarning) {
119
+ this.adapter.log.warn(
120
+ '[photovoltaicHelper] Kollektorüberhitzung erkannt → Pumpe ZWANGSEIN (Sicherheits-Override aktiv)',
121
+ );
122
+ return this._maybeStartPump('solar_overheat_protection');
123
+ }
124
+ } catch (err) {
125
+ this.adapter.log.warn(`[photovoltaicHelper] Fehler beim Prüfen der Solarüberhitzung: ${err.message}`);
126
+ }
127
+
128
+ // Überschussberechnung
129
+ const surplus = Math.max(0, gen - house);
130
+ await this._updateNumberState('photovoltaic.power_surplus_w', surplus);
131
+
132
+ // **NEU:** Einschaltlogik = Pumpenleistung + Sicherheitsaufschlag
133
+ const requiredPower = pumpMax + threshold;
134
+ const surplusActive = surplus >= requiredPower && seasonActive;
135
+ await this._updateBoolState('photovoltaic.surplus_active', surplusActive);
136
+
137
+ const txt = surplusActive
138
+ ? `Überschuss aktiv (${surplus} W ≥ ${pumpMax}+${threshold} W)`
139
+ : `Kein Überschuss (${surplus} W < ${pumpMax}+${threshold} W)`;
140
+ await this._updateStringState('photovoltaic.status_text', txt);
141
+ await this._updateStringState('photovoltaic.last_update', new Date().toISOString());
142
+
143
+ // Saison/Modus prüfen
144
+ if (!seasonActive) {
145
+ this.adapter.log.debug('[photovoltaicHelper] Saison inaktiv → keine PV-Schaltlogik.');
146
+ return this._maybeStopPump(false, 0, 'season_inactive');
147
+ }
148
+ if (pumpMode !== 'auto_pv') {
149
+ this.adapter.log.debug(
150
+ `[photovoltaicHelper] Pumpenmodus ist '${pumpMode}' ≠ 'auto_pv' → keine PV-Schaltlogik.`,
151
+ );
152
+ return this._maybeStopPump(false, 0, 'mode_not_auto_pv');
153
+ }
154
+
155
+ // Optional: Umwälzung erreicht?
156
+ if (ignoreOnCirc) {
157
+ try {
158
+ const remainingState = await this.adapter.getForeignStateAsync(
159
+ 'poolcontrol.0.circulation.daily_remaining',
160
+ );
161
+ const remaining = Number(remainingState?.val ?? NaN);
162
+ if (Number.isFinite(remaining) && remaining <= 0) {
163
+ this.adapter.log.debug(
164
+ `[photovoltaicHelper] Tagesumwälzung erreicht (daily_remaining = ${remaining}) → PV-Steuerung ignoriert.`,
165
+ );
166
+ return this._maybeStopPump(false, afterrunMin, 'circulation_reached');
167
+ }
168
+ } catch (err) {
169
+ this.adapter.log.debug(
170
+ `[photovoltaicHelper] daily_remaining konnte nicht gelesen werden: ${err.message}`,
171
+ );
172
+ }
173
+ }
174
+
175
+ // Schaltlogik
176
+ if (surplusActive) {
177
+ return this._maybeStartPump('pv_surplus');
178
+ }
179
+ return this._maybeStopPump(false, afterrunMin, 'pv_ended_afterrun');
180
+ },
181
+
182
+ async _maybeStartPump(reason) {
183
+ if (this._desiredPump === true) {
184
+ return;
185
+ }
186
+ this._desiredPump = true;
187
+ if (this.afterrunTimer) {
188
+ clearTimeout(this.afterrunTimer);
189
+ this.afterrunTimer = null;
190
+ }
191
+ this._pvPumpHoldUntil = 0;
192
+ this.adapter.log.info(`[photovoltaicHelper] Pumpe EIN (Grund: ${reason})`);
193
+ await this._setPumpSwitch(true);
194
+ },
195
+
196
+ async _maybeStopPump(immediate, afterrunMin, tag) {
197
+ if (immediate || !afterrunMin || afterrunMin <= 0) {
198
+ if (this._desiredPump === false) {
199
+ return;
200
+ }
201
+ this._desiredPump = false;
202
+ this.adapter.log.info(`[photovoltaicHelper] Pumpe AUS (${tag}, ohne Nachlauf)`);
203
+ await this._setPumpSwitch(false);
204
+ return;
205
+ }
206
+
207
+ const holdMs = Math.round(afterrunMin * 60 * 1000);
208
+ this._pvPumpHoldUntil = Date.now() + holdMs;
209
+ if (this.afterrunTimer) {
210
+ clearTimeout(this.afterrunTimer);
211
+ }
212
+ this.afterrunTimer = setTimeout(async () => {
213
+ const active = !!(await this.adapter.getStateAsync('photovoltaic.surplus_active'))?.val;
214
+ if (active) {
215
+ this.adapter.log.debug('[photovoltaicHelper] Nachlauf abgebrochen – Überschuss wieder aktiv.');
216
+ return;
217
+ }
218
+ this._desiredPump = false;
219
+ this.adapter.log.info('[photovoltaicHelper] Pumpe AUS (Nachlauf beendet)');
220
+ await this._setPumpSwitch(false);
221
+ }, holdMs);
222
+ this.adapter.log.debug(`[photovoltaicHelper] Nachlauf gestartet: ${afterrunMin} min (${tag})`);
223
+ },
224
+
225
+ async _setPumpSwitch(on) {
226
+ try {
227
+ await this.adapter.setStateAsync('pump.pump_switch', { val: !!on, ack: false });
228
+ } catch (err) {
229
+ this.adapter.log.warn(`[photovoltaicHelper] Konnte pump.pump_switch nicht setzen: ${err.message}`);
230
+ }
231
+ },
232
+
233
+ async _updateNumberState(id, val) {
234
+ try {
235
+ await this.adapter.setStateAsync(id, { val: Number(val) || 0, ack: true });
236
+ } catch (e) {
237
+ this.adapter.log.warn(`[photovoltaicHelper] setNumber ${id} fehlgeschlagen: ${e.message}`);
238
+ }
239
+ },
240
+ async _updateBoolState(id, val) {
241
+ try {
242
+ await this.adapter.setStateAsync(id, { val: !!val, ack: true });
243
+ } catch (e) {
244
+ this.adapter.log.warn(`[photovoltaicHelper] setBool ${id} fehlgeschlagen: ${e.message}`);
245
+ }
246
+ },
247
+ async _updateStringState(id, val) {
248
+ try {
249
+ await this.adapter.setStateAsync(id, { val: String(val ?? ''), ack: true });
250
+ } catch (e) {
251
+ this.adapter.log.warn(`[photovoltaicHelper] setString ${id} fehlgeschlagen: ${e.message}`);
252
+ }
253
+ },
254
+
255
+ async _safeRecalc(tag) {
256
+ try {
257
+ await this._recalc(tag);
258
+ } catch (err) {
259
+ this.adapter.log.warn(`[photovoltaicHelper] Recalc-Fehler (${tag}): ${err.message}`);
260
+ }
261
+ },
262
+
263
+ cleanup() {
264
+ if (this.afterrunTimer) {
265
+ clearTimeout(this.afterrunTimer);
266
+ this.afterrunTimer = null;
267
+ }
268
+ this._pvPumpHoldUntil = 0;
269
+ this._desiredPump = null;
270
+ },
271
+ };
272
+
273
+ module.exports = photovoltaicHelper;
@@ -347,26 +347,31 @@ const statisticsHelperMonth = {
347
347
 
348
348
  const now = new Date();
349
349
  const nextReset = new Date(now.getFullYear(), now.getMonth() + 1, 1, 0, 5, 0, 0);
350
- const msUntilReset = nextReset.getTime() - now.getTime();
351
-
352
- // 🟢 NEU: Schutz falls Resetzeitpunkt in der Vergangenheit liegt
353
- if (msUntilReset < 60 * 1000) {
354
- // unter 1 Minute Differenz
355
- adapter.log.warn(
356
- 'statisticsHelperMonth: Berechneter Resetzeitpunkt liegt in der Vergangenheit – Korrigiere auf nächsten Monat.',
357
- );
358
- const corrected = new Date(now.getFullYear(), now.getMonth() + 1, 1, 0, 5, 0, 0);
359
- const diff = corrected.getTime() - now.getTime();
360
- this.monthResetTimer = setTimeout(async () => {
361
- await this._resetMonthlyTemperatureStats();
362
- await this._scheduleMonthReset();
363
- }, diff);
364
- return;
350
+ let msUntilReset = nextReset.getTime() - now.getTime();
351
+
352
+ // Wenn heute bereits der 1. ist keinen sofortigen Reset starten!
353
+ if (now.getDate() === 1) {
354
+ adapter.log.debug('statisticsHelperMonth: Heute ist bereits der 1. Reset wurde übersprungen.');
355
+ // Plan auf nächsten Monat verschieben
356
+ nextReset.setMonth(nextReset.getMonth() + 1);
357
+ msUntilReset = nextReset.getTime() - now.getTime();
358
+ }
359
+
360
+ // Wenn Berechnung negativ oder zu klein ist → Sicherheit
361
+ if (msUntilReset <= 0 || msUntilReset < 10 * 60 * 1000) {
362
+ adapter.log.debug('statisticsHelperMonth: msUntilReset war zu klein – korrigiere Timer.');
363
+ msUntilReset = 10 * 60 * 1000; // mindestens 10 Minuten warten
365
364
  }
366
365
 
366
+ // Timer setzen
367
367
  this.monthResetTimer = setTimeout(async () => {
368
+ if (this.isResetting) {
369
+ adapter.log.debug('statisticsHelperMonth: Reset läuft bereits – Timer übersprungen.');
370
+ return;
371
+ }
372
+
368
373
  await this._resetMonthlyTemperatureStats();
369
- await this._scheduleMonthReset();
374
+ // await this._scheduleMonthReset();
370
375
  }, msUntilReset);
371
376
 
372
377
  adapter.log.debug(
@@ -389,7 +389,7 @@ const statisticsHelperWeek = {
389
389
 
390
390
  this.weekResetTimer = setTimeout(async () => {
391
391
  await this._resetWeeklyTemperatureStats();
392
- await this._scheduleWeekReset();
392
+ // await this._scheduleWeekReset();
393
393
  }, msUntilReset);
394
394
 
395
395
  adapter.log.debug(`statisticsHelperWeek: Wochen-Reset geplant in ${Math.round(msUntilReset / 60000)} Minuten.`);
@@ -151,10 +151,16 @@ async function createControlStates(adapter) {
151
151
  role: 'date',
152
152
  read: true,
153
153
  write: false,
154
+ persist: true,
154
155
  },
155
156
  native: {},
156
157
  });
157
- await adapter.setStateAsync('control.pump.backwash_last_date', { val: '', ack: true });
158
+
159
+ // 🟢 Überinstallationsschutz – nur schreiben, wenn kein Wert existiert
160
+ const existingLastDate = await adapter.getStateAsync('control.pump.backwash_last_date');
161
+ if (existingLastDate === null || existingLastDate.val === null || existingLastDate.val === undefined) {
162
+ await adapter.setStateAsync('control.pump.backwash_last_date', { val: '', ack: true });
163
+ }
158
164
 
159
165
  await adapter.setObjectNotExistsAsync('control.pump.backwash_required', {
160
166
  type: 'state',
@@ -0,0 +1,161 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * createPhotovoltaicStates(adapter)
5
+ * -------------------------------------------------------------
6
+ * Legt alle States für den Photovoltaik-Bereich an.
7
+ * - persistente States
8
+ * - überinstallationsgeschützt (keine Überschreibung vorhandener Werte)
9
+ * - konsistent im Stil der übrigen State-Dateien
10
+ * -------------------------------------------------------------
11
+ */
12
+
13
+ /**
14
+ * @param {object} adapter - ioBroker Adapterinstanz
15
+ * @returns {Promise<void>}
16
+ */
17
+ async function createPhotovoltaicStates(adapter) {
18
+ adapter.log.debug('[createPhotovoltaicStates] Initialisierung gestartet.');
19
+
20
+ // --- Photovoltaik-Hauptordner ---
21
+ await adapter.setObjectNotExistsAsync('photovoltaic', {
22
+ type: 'channel',
23
+ common: { name: 'Photovoltaik (Überschusserkennung)' },
24
+ native: {},
25
+ });
26
+
27
+ // --- State-Liste ---
28
+ const states = [
29
+ {
30
+ id: 'power_generated_w',
31
+ name: 'PV-Erzeugungsleistung (W)',
32
+ desc: 'Aktuell erzeugte Leistung der PV-Anlage in Watt',
33
+ type: 'number',
34
+ role: 'value.power',
35
+ unit: 'W',
36
+ read: true,
37
+ write: false,
38
+ def: 0,
39
+ },
40
+ {
41
+ id: 'power_house_w',
42
+ name: 'Hausverbrauch (W)',
43
+ desc: 'Aktueller Stromverbrauch des Hauses in Watt',
44
+ type: 'number',
45
+ role: 'value.power',
46
+ unit: 'W',
47
+ read: true,
48
+ write: false,
49
+ def: 0,
50
+ },
51
+ {
52
+ id: 'power_surplus_w',
53
+ name: 'PV-Überschussleistung (W)',
54
+ desc: 'Berechneter Überschuss zwischen PV-Erzeugung und Hausverbrauch',
55
+ type: 'number',
56
+ role: 'value.power',
57
+ unit: 'W',
58
+ read: true,
59
+ write: false,
60
+ def: 0,
61
+ },
62
+ {
63
+ id: 'surplus_active',
64
+ name: 'PV-Überschuss aktiv',
65
+ desc: 'Zeigt an, ob aktuell ein PV-Überschuss vorliegt (true/false)',
66
+ type: 'boolean',
67
+ role: 'indicator',
68
+ read: true,
69
+ write: false,
70
+ def: false,
71
+ },
72
+ {
73
+ id: 'afterrun_min',
74
+ name: 'Nachlaufzeit (Minuten)',
75
+ desc: 'Dauer, wie lange die Pumpe nach Ende des PV-Überschusses weiterläuft',
76
+ type: 'number',
77
+ role: 'level',
78
+ unit: 'min',
79
+ read: true,
80
+ write: true,
81
+ def: 2,
82
+ },
83
+ {
84
+ id: 'ignore_on_circulation',
85
+ name: 'PV ignorieren, wenn Umwälzmenge erreicht',
86
+ desc: 'Wenn aktiviert, wird PV-Steuerung deaktiviert, sobald Tagesumwälzung erfüllt ist',
87
+ type: 'boolean',
88
+ role: 'switch.enable',
89
+ read: true,
90
+ write: true,
91
+ def: false,
92
+ },
93
+ {
94
+ id: 'threshold_w',
95
+ name: 'Schwellwert für PV-Überschuss (W)',
96
+ desc: 'Watt-Schwelle, ab der ein Überschuss erkannt wird',
97
+ type: 'number',
98
+ role: 'value',
99
+ unit: 'W',
100
+ read: true,
101
+ write: false,
102
+ def: 200,
103
+ },
104
+ {
105
+ id: 'status_text',
106
+ name: 'Statusmeldung (Text)',
107
+ desc: 'Klartextstatus der PV-Erkennung (z. B. Überschuss aktiv)',
108
+ type: 'string',
109
+ role: 'text',
110
+ read: true,
111
+ write: false,
112
+ def: '',
113
+ },
114
+ {
115
+ id: 'last_update',
116
+ name: 'Letzte Aktualisierung',
117
+ desc: 'Zeitstempel der letzten Berechnung der PV-Werte',
118
+ type: 'string',
119
+ role: 'date',
120
+ read: true,
121
+ write: false,
122
+ def: '',
123
+ },
124
+ ];
125
+
126
+ // --- States anlegen ---
127
+ for (const s of states) {
128
+ const id = `photovoltaic.${s.id}`;
129
+
130
+ await adapter.setObjectNotExistsAsync(id, {
131
+ type: 'state',
132
+ common: {
133
+ name: s.name,
134
+ desc: s.desc,
135
+ type: s.type,
136
+ role: s.role,
137
+ read: s.read,
138
+ write: s.write,
139
+ def: s.def,
140
+ unit: s.unit || '',
141
+ persist: true,
142
+ },
143
+ native: {},
144
+ });
145
+
146
+ // Überinstallationsschutz
147
+ const existing = await adapter.getStateAsync(id);
148
+ if (existing === null || existing === undefined) {
149
+ await adapter.setStateAsync(id, { val: s.def, ack: true });
150
+ adapter.log.debug(
151
+ `[createPhotovoltaicStates] Neuer State '${id}' initialisiert mit Default-Wert ${s.def}.`,
152
+ );
153
+ } else {
154
+ adapter.log.debug(`[createPhotovoltaicStates] State '${id}' bereits vorhanden – Wert bleibt erhalten.`);
155
+ }
156
+ }
157
+
158
+ adapter.log.info('[createPhotovoltaicStates] Initialisierung abgeschlossen.');
159
+ }
160
+
161
+ module.exports = { createPhotovoltaicStates };
@@ -110,6 +110,7 @@ async function createPumpStates(adapter) {
110
110
  persist: true, // NEU: dauerhaft speichern
111
111
  states: {
112
112
  auto: 'Automatik',
113
+ auto_pv: 'Automatik (PV)',
113
114
  manual: 'Manuell',
114
115
  off: 'Aus',
115
116
  time: 'Zeit',
package/main.js CHANGED
@@ -19,6 +19,7 @@ const consumptionHelper = require('./lib/helpers/consumptionHelper');
19
19
  const solarHelper = require('./lib/helpers/solarHelper');
20
20
  const frostHelper = require('./lib/helpers/frostHelper');
21
21
  const statusHelper = require('./lib/helpers/statusHelper');
22
+ const photovoltaicHelper = require('./lib/helpers/photovoltaicHelper');
22
23
  const controlHelper = require('./lib/helpers/controlHelper');
23
24
  const controlHelper2 = require('./lib/helpers/controlHelper2');
24
25
  const debugLogHelper = require('./lib/helpers/debugLogHelper');
@@ -29,6 +30,7 @@ const { createPumpStates } = require('./lib/stateDefinitions/pumpStates');
29
30
  const { createPumpStates2 } = require('./lib/stateDefinitions/pumpStates2');
30
31
  const { createPumpStates3 } = require('./lib/stateDefinitions/pumpStates3');
31
32
  const { createSolarStates } = require('./lib/stateDefinitions/solarStates');
33
+ const { createPhotovoltaicStates } = require('./lib/stateDefinitions/photovoltaicStates');
32
34
  const { createGeneralStates } = require('./lib/stateDefinitions/generalStates');
33
35
  const { createTimeStates } = require('./lib/stateDefinitions/timeStates');
34
36
  const { createRuntimeStates } = require('./lib/stateDefinitions/runtimeStates');
@@ -67,6 +69,9 @@ class Poolcontrol extends utils.Adapter {
67
69
  // --- Solarverwaltung ---
68
70
  await createSolarStates(this);
69
71
 
72
+ // --- Photovoltaik ---
73
+ await createPhotovoltaicStates(this);
74
+
70
75
  // --- Zeitsteuerung ---
71
76
  await createTimeStates(this);
72
77
 
@@ -113,6 +118,7 @@ class Poolcontrol extends utils.Adapter {
113
118
  speechHelper.init(this);
114
119
  consumptionHelper.init(this);
115
120
  solarHelper.init(this);
121
+ photovoltaicHelper.init(this);
116
122
  frostHelper.init(this);
117
123
  statusHelper.init(this);
118
124
  controlHelper.init(this);
@@ -225,6 +231,11 @@ class Poolcontrol extends utils.Adapter {
225
231
  } catch (e) {
226
232
  this.log.warn(`[consumptionHelper] Fehler in handleStateChange: ${e.message}`);
227
233
  }
234
+ try {
235
+ photovoltaicHelper.handleStateChange(id, state);
236
+ } catch (e) {
237
+ this.log.warn(`[photovoltaicHelper] Fehler in handleStateChange: ${e.message}`);
238
+ }
228
239
  try {
229
240
  statusHelper.handleStateChange(id, state);
230
241
  } catch (e) {
@@ -242,6 +253,17 @@ class Poolcontrol extends utils.Adapter {
242
253
  controlHelper2.handleStateChange(id, state);
243
254
  }
244
255
 
256
+ // --- Photovoltaik-Parameter ---
257
+ if (id.endsWith('photovoltaic.afterrun_min')) {
258
+ this.log.debug(`[onStateChange] Nachlaufzeit (PV) geändert auf ${state.val} Minuten`);
259
+ this.config.pv_afterrun_min = Number(state.val);
260
+ }
261
+
262
+ if (id.endsWith('photovoltaic.ignore_on_circulation')) {
263
+ this.log.debug(`[onStateChange] PV-Logik ignorieren bei Umwälzmenge = ${state.val}`);
264
+ this.config.pv_ignore_on_circulation = !!state.val;
265
+ }
266
+
245
267
  await debugLogHelper.handleStateChange(id, state);
246
268
  }
247
269
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.poolcontrol",
3
- "version": "0.5.4",
3
+ "version": "0.6.0",
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",