iobroker.poolcontrol 0.0.8 → 0.0.10
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/LICENSE +17 -18
- package/README.md +32 -3
- package/admin/jsonConfig.json +36 -6
- package/io-package.json +30 -100
- package/lib/helpers/pumpHelper.js +14 -0
- package/lib/helpers/runtimeHelper.js +35 -5
- package/lib/helpers/statusHelper.js +226 -0
- package/lib/helpers/temperatureHelper.js +19 -0
- package/lib/stateDefinitions/consumptionStates.js +13 -2
- package/lib/stateDefinitions/runtimeStates.js +8 -0
- package/lib/stateDefinitions/statusStates.js +185 -0
- package/lib/stateDefinitions/temperatureStates.js +4 -0
- package/main.js +14 -0
- package/package.json +6 -10
package/LICENSE
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2025 DasBo1975
|
|
3
|
+
Copyright (c) 2025 DasBo1975
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
sowie Personen, denen die Software zur Verfügung gestellt wird, dies zu gestatten,
|
|
12
|
-
unter der Bedingung, dass der oben genannte Urheberrechtshinweis und dieser
|
|
13
|
-
Erlaubnishinweis in allen Kopien oder wesentlichen Teilen der Software
|
|
14
|
-
beibehalten werden.
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
[](https://github.com/DasBo1975/ioBroker.poolcontrol/blob/main/LICENSE)
|
|
5
9
|
|
|
6
10
|
Der Adapter **ioBroker.poolcontrol** dient zur Steuerung und Überwachung von Poolanlagen.
|
|
7
11
|
Er ermöglicht die Automatisierung von Pumpen, Temperatur- und Solarsteuerung sowie Verbrauchsauswertung.
|
|
@@ -90,6 +94,30 @@ Funktionen können sich ändern, bitte regelmäßig den Changelog beachten.
|
|
|
90
94
|
## Changelog
|
|
91
95
|
Auszug, vollständige Liste siehe `io-package.json`:
|
|
92
96
|
|
|
97
|
+
### 0.0.10
|
|
98
|
+
|
|
99
|
+
Statusübersicht
|
|
100
|
+
Ab Version 0.0.10 gibt es einen eigenen Bereich `status.*` mit folgenden Datenpunkten:
|
|
101
|
+
|
|
102
|
+
- **status.summary** → Textübersicht (Pumpe, Modus, Temperaturen, Laufzeit, Umwälzung)
|
|
103
|
+
- **status.overview_json** → Übersicht als JSON (maschinenlesbar)
|
|
104
|
+
- **status.last_summary_update** → Zeitpunkt der letzten Aktualisierung
|
|
105
|
+
- **status.pump_last_start** → Letzter Pumpenstart (Zeitstempel)
|
|
106
|
+
- **status.pump_last_stop** → Letztes Pumpenende (Zeitstempel)
|
|
107
|
+
- **status.pump_was_on_today** → Boolean, ob die Pumpe heute lief
|
|
108
|
+
- **status.pump_today_count** → Anzahl der Starts heute (Reset um Mitternacht)
|
|
109
|
+
- **status.system_ok** → Boolean, ob das System fehlerfrei läuft
|
|
110
|
+
- **status.system_warning** → Boolean, wenn eine Warnung aktiv ist
|
|
111
|
+
- **status.system_warning_text** → Beschreibung der aktiven Warnung
|
|
112
|
+
- **status.season_active** → Anzeige, ob die Poolsaison aktiv ist
|
|
113
|
+
|
|
114
|
+
Diese Datenpunkte sind besonders für **VIS/vis2, Alexa- oder Telegram-Ausgaben** gedacht, da sie eine schnelle Übersicht über den aktuellen Poolstatus bieten.
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
### 0.0.9
|
|
118
|
+
- Laufzeit-, Umwälz-, Verbrauch-/Kosten- und Temperatur-Min/Max-States sind jetzt persistent
|
|
119
|
+
(Werte bleiben nach Adapter-Neustart oder Stromausfall erhalten)
|
|
120
|
+
|
|
93
121
|
### 0.0.8
|
|
94
122
|
- Hilfetab in der Instanzkonfiguration hinzugefügt (mit Link zur GitHub-Dokumentation)
|
|
95
123
|
|
|
@@ -128,6 +156,7 @@ Der Nutzer ist für die **sichere Installation und den Betrieb seiner Hardware**
|
|
|
128
156
|
|
|
129
157
|
---
|
|
130
158
|
|
|
131
|
-
##
|
|
132
|
-
|
|
133
|
-
|
|
159
|
+
## License
|
|
160
|
+
Copyright (c) 2025 DasBo1975 <dasbo1975@outlook.de>
|
|
161
|
+
|
|
162
|
+
MIT License
|
package/admin/jsonConfig.json
CHANGED
|
@@ -137,7 +137,12 @@
|
|
|
137
137
|
"pump_mode_hint": {
|
|
138
138
|
"type": "staticText",
|
|
139
139
|
"text": "Pumpenmodus (Automatik/Manuell/Aus/Zeit) kann über den Datenpunkt 'pump.mode' gesteuert werden.",
|
|
140
|
-
"newLine": true
|
|
140
|
+
"newLine": true,
|
|
141
|
+
"xs": 12,
|
|
142
|
+
"sm": 12,
|
|
143
|
+
"md": 12,
|
|
144
|
+
"lg": 12,
|
|
145
|
+
"xl": 12
|
|
141
146
|
},
|
|
142
147
|
"divider10": {
|
|
143
148
|
"type": "divider",
|
|
@@ -157,7 +162,12 @@
|
|
|
157
162
|
"manual_safety_enabled_hint": {
|
|
158
163
|
"type": "staticText",
|
|
159
164
|
"text": "Wenn aktiviert, werden die Sicherheitsfunktionen wie Frostschutz und Überhitzungsschutz (Solar) weiterhin ausgeführt.",
|
|
160
|
-
"newLine": true
|
|
165
|
+
"newLine": true,
|
|
166
|
+
"xs": 12,
|
|
167
|
+
"sm": 12,
|
|
168
|
+
"md": 12,
|
|
169
|
+
"lg": 12,
|
|
170
|
+
"xl": 12
|
|
161
171
|
}
|
|
162
172
|
}
|
|
163
173
|
},
|
|
@@ -390,7 +400,12 @@
|
|
|
390
400
|
"solar_collector_warn_hint": {
|
|
391
401
|
"type": "staticText",
|
|
392
402
|
"text": "Hinweis: Die Warnung wird automatisch zurückgesetzt, sobald die Temperatur 10 % unter die eingestellte Schwelle fällt.",
|
|
393
|
-
"newLine": true
|
|
403
|
+
"newLine": true,
|
|
404
|
+
"xs": 12,
|
|
405
|
+
"sm": 12,
|
|
406
|
+
"md": 12,
|
|
407
|
+
"lg": 12,
|
|
408
|
+
"xl": 12
|
|
394
409
|
}
|
|
395
410
|
}
|
|
396
411
|
},
|
|
@@ -893,7 +908,12 @@
|
|
|
893
908
|
"consumption_hint": {
|
|
894
909
|
"type": "staticText",
|
|
895
910
|
"text": "Hinweis: Für die Verbrauchsberechnung wird ein externer kWh-Zähler benötigt (z. B. Messsteckdose).",
|
|
896
|
-
"newLine": true
|
|
911
|
+
"newLine": true,
|
|
912
|
+
"xs": 12,
|
|
913
|
+
"sm": 12,
|
|
914
|
+
"md": 12,
|
|
915
|
+
"lg": 12,
|
|
916
|
+
"xl": 12
|
|
897
917
|
}
|
|
898
918
|
}
|
|
899
919
|
},
|
|
@@ -909,11 +929,21 @@
|
|
|
909
929
|
"type": "staticLink",
|
|
910
930
|
"label": "Öffne die ausführliche Dokumentation auf GitHub",
|
|
911
931
|
"href": "https://github.com/DasBo1975/iobroker.poolcontrol/blob/main/admin/help.md",
|
|
912
|
-
"newLine": true
|
|
932
|
+
"newLine": true,
|
|
933
|
+
"xs": 12,
|
|
934
|
+
"sm": 12,
|
|
935
|
+
"md": 12,
|
|
936
|
+
"lg": 12,
|
|
937
|
+
"xl": 12
|
|
913
938
|
},
|
|
914
939
|
"helpText": {
|
|
915
940
|
"type": "staticText",
|
|
916
|
-
"text": "Hier finden Sie die vollständige Dokumentation und Hinweise zu allen Einstellungen. Weitere Hinweise zu künftigen Versionen folgen."
|
|
941
|
+
"text": "Hier finden Sie die vollständige Dokumentation und Hinweise zu allen Einstellungen. Weitere Hinweise zu künftigen Versionen folgen.",
|
|
942
|
+
"xs": 12,
|
|
943
|
+
"sm": 12,
|
|
944
|
+
"md": 12,
|
|
945
|
+
"lg": 12,
|
|
946
|
+
"xl": 12
|
|
917
947
|
}
|
|
918
948
|
}
|
|
919
949
|
}
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "poolcontrol",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.10",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.0.10": {
|
|
7
|
+
"en": "Added extended status overview with pump statistics, system flags and JSON summary",
|
|
8
|
+
"de": "Erweiterte Statusübersicht mit Pumpenstatistiken, Systemanzeigen und JSON-Zusammenfassung hinzugefügt",
|
|
9
|
+
"ru": "Добавлен расширенный обзор состояния с насосной статистикой, системными флагами и JSON-резюме",
|
|
10
|
+
"pt": "Adicionada visão geral de status estendida com estatísticas da bomba, sinalizadores do sistema e resumo em JSON",
|
|
11
|
+
"nl": "Uitgebreide statusoverzicht toegevoegd met pompstatistieken, systeemindicatoren en JSON-samenvatting",
|
|
12
|
+
"fr": "Aperçu du statut étendu ajouté avec statistiques de la pompe, indicateurs système et résumé JSON",
|
|
13
|
+
"it": "Aggiunta panoramica dello stato estesa con statistiche della pompa, indicatori di sistema e riepilogo JSON",
|
|
14
|
+
"es": "Añadida vista general de estado extendida con estadísticas de la bomba, indicadores del sistema y resumen en JSON",
|
|
15
|
+
"pl": "Dodano rozszerzony przegląd statusu ze statystykami pompy, flagami systemowymi i podsumowaniem JSON",
|
|
16
|
+
"uk": "Додано розширений огляд статусу зі статистикою насоса, системними прапорцями та зведенням JSON",
|
|
17
|
+
"zh-cn": "新增扩展状态概览,包括泵统计、系统标志和 JSON 摘要"
|
|
18
|
+
},
|
|
19
|
+
"0.0.9": {
|
|
20
|
+
"en": "Made runtime, circulation, consumption/costs and temperature min/max states persistent across restarts",
|
|
21
|
+
"de": "Laufzeit-, Umwälz-, Verbrauch-/Kosten- und Temperatur-Min/Max-States bleiben jetzt über Neustarts erhalten",
|
|
22
|
+
"ru": "Состояния времени работы, циркуляции, потребления/стоимости и мин/макс температуры теперь сохраняются при перезапуске",
|
|
23
|
+
"pt": "Estados de tempo de execução, circulação, consumo/custos e temperatura min/máx agora persistem após reinicializações",
|
|
24
|
+
"nl": "Runtime-, circulatie-, verbruiks-/kosten- en temperatuur min/max-states blijven nu behouden bij herstart",
|
|
25
|
+
"fr": "Les états de durée, de circulation, de consommation/coûts et de température min/max persistent désormais après redémarrage",
|
|
26
|
+
"it": "Gli stati di runtime, circolazione, consumo/costi e temperatura min/max ora persistono ai riavvii",
|
|
27
|
+
"es": "Los estados de tiempo de ejecución, circulación, consumo/costos y temperatura min/máx ahora persisten tras reinicios",
|
|
28
|
+
"pl": "Stany czasu pracy, cyrkulacji, zużycia/kosztów i temp. min/max są teraz zachowane po restartach",
|
|
29
|
+
"uk": "Стан часу роботи, циркуляції, споживання/вартості та мін/макс температури тепер зберігаються після перезапусків",
|
|
30
|
+
"zh-cn": "运行时间、循环、消耗/成本和温度最小/最大状态现在在重启后保持"
|
|
31
|
+
},
|
|
6
32
|
"0.0.8": {
|
|
7
33
|
"en": "Added Help tab in instance configuration with link to GitHub documentation",
|
|
8
34
|
"de": "Hilfetab in der Instanzkonfiguration hinzugefügt mit Link zur GitHub-Dokumentation",
|
|
@@ -16,97 +42,6 @@
|
|
|
16
42
|
"uk": "Додано вкладку довідки в конфігурацію екземпляра з посиланням на документацію GitHub",
|
|
17
43
|
"zh-cn": "在实例配置中添加了帮助选项卡,并链接到 документацию GitHub"
|
|
18
44
|
}
|
|
19
|
-
"0.0.7": {
|
|
20
|
-
"en": "Added help file (help.md) and first README version",
|
|
21
|
-
"de": "Hilfedatei (help.md) und erste README-Version hinzugefügt",
|
|
22
|
-
"ru": "Добавлен файл справки (help.md) и первая версия README",
|
|
23
|
-
"pt": "Adicionado arquivo de ajuda (help.md) e primeira versão do README",
|
|
24
|
-
"nl": "Helpbestand (help.md) en eerste README-versie toegevoegd",
|
|
25
|
-
"fr": "Ajout du fichier d'aide (help.md) et première version du README",
|
|
26
|
-
"it": "Aggiunto file di aiuto (help.md) e prima versione di README",
|
|
27
|
-
"es": "Se agregó archivo de ayuda (help.md) y primera versión de README",
|
|
28
|
-
"pl": "Dodano plik pomocy (help.md) i pierwszą wersję README",
|
|
29
|
-
"uk": "Додано файл довідки (help.md) та першу версію README",
|
|
30
|
-
"zh-cn": "添加了帮助文件 (help.md) 和第一个 README 版本"
|
|
31
|
-
},
|
|
32
|
-
"0.0.6": {
|
|
33
|
-
"en": "Added consumption & cost calculation with external kWh meter",
|
|
34
|
-
"de": "Verbrauchs- und Kostenberechnung mit externem kWh-Zähler hinzugefügt",
|
|
35
|
-
"ru": "Добавлен расчет потребления и затрат с внешним счетчиком кВт·ч",
|
|
36
|
-
"pt": "Adicionado cálculo de consumo e custo com medidor externo de kWh",
|
|
37
|
-
"nl": "Verbruik- en kostenberekening toegevoegd met externe kWh-meter",
|
|
38
|
-
"fr": "Ajout du calcul de consommation et de coût avec compteur kWh externe",
|
|
39
|
-
"it": "Aggiunto calcolo di consumo e costi con contatore kWh esterno",
|
|
40
|
-
"es": "Se agregó cálculo de consumo y costos con medidor externo de kWh",
|
|
41
|
-
"pl": "Dodano obliczanie zużycia i kosztów z zewnętrznym licznikiem kWh",
|
|
42
|
-
"uk": "Додано розрахунок споживання та витрат із зовнішнім лічильником кВт·год",
|
|
43
|
-
"zh-cn": "新增使用外部千瓦时电表的消耗和成本计算"
|
|
44
|
-
},
|
|
45
|
-
"0.0.5": {
|
|
46
|
-
"en": "Added speech output via Alexa and Telegram",
|
|
47
|
-
"de": "Sprachausgaben über Alexa und Telegram hinzugefügt",
|
|
48
|
-
"ru": "Добавлен голосовой вывод через Alexa и Telegram",
|
|
49
|
-
"pt": "Adicionada saída de voz via Alexa e Telegram",
|
|
50
|
-
"nl": "Spraakuitvoer toegevoegd via Alexa en Telegram",
|
|
51
|
-
"fr": "Ajout de la sortie vocale via Alexa et Telegram",
|
|
52
|
-
"it": "Aggiunta uscita vocale tramite Alexa e Telegram",
|
|
53
|
-
"es": "Se agregó salida de voz a través de Alexa y Telegram",
|
|
54
|
-
"pl": "Dodano wyjście głosowe przez Alexa i Telegram",
|
|
55
|
-
"uk": "Додано голосовий вивід через Alexa та Telegram",
|
|
56
|
-
"zh-cn": "新增通过 Alexa 和 Telegram 的语音输出"
|
|
57
|
-
},
|
|
58
|
-
"0.0.4": {
|
|
59
|
-
"en": "Added runtime & circulation logic including new datapoint 'circulation.daily_required'",
|
|
60
|
-
"de": "Laufzeit- und Umwälzlogik hinzugefügt, einschließlich neuem Datenpunkt 'circulation.daily_required'",
|
|
61
|
-
"ru": "Добавлена логика времени работы и циркуляции, включая новую точку данных 'circulation.daily_required'",
|
|
62
|
-
"pt": "Adicionada lógica de tempo de execução e circulação, incluindo novo datapoint 'circulation.daily_required'",
|
|
63
|
-
"nl": "Runtime- en circulatielogica toegevoegd, inclusief nieuw datapoint 'circulation.daily_required'",
|
|
64
|
-
"fr": "Ajout de la logique de temps d'exécution et de circulation, y compris le nouveau point de données 'circulation.daily_required'",
|
|
65
|
-
"it": "Aggiunta logica di runtime e circolazione, incluso nuovo datapoint 'circulation.daily_required'",
|
|
66
|
-
"es": "Se agregó lógica de tiempo de ejecución y circulación, incluido nuevo datapoint 'circulation.daily_required'",
|
|
67
|
-
"pl": "Dodano logikę czasu pracy i cyrkulacji, w tym nowy punkt danych 'circulation.daily_required'",
|
|
68
|
-
"uk": "Додано логіку часу роботи та циркуляції, включаючи нову точку даних 'circulation.daily_required'",
|
|
69
|
-
"zh-cn": "新增运行时间和循环逻辑,包括新数据点 'circulation.daily_required'"
|
|
70
|
-
},
|
|
71
|
-
"0.0.3": {
|
|
72
|
-
"en": "Added time control with up to 3 configurable time windows",
|
|
73
|
-
"de": "Zeitsteuerung mit bis zu 3 konfigurierbaren Zeitfenstern hinzugefügt",
|
|
74
|
-
"ru": "Добавлено управление временем с до 3 настраиваемыми временными окнами",
|
|
75
|
-
"pt": "Adicionado controle de tempo com até 3 janelas de tempo configuráveis",
|
|
76
|
-
"nl": "Tijdregeling toegevoegd met maximaal 3 configureerbare tijdvensters",
|
|
77
|
-
"fr": "Ajout du contrôle du temps avec jusqu'à 3 fenêtres de temps configurables",
|
|
78
|
-
"it": "Aggiunto controllo del tempo con fino a 3 finestre temporali configurabili",
|
|
79
|
-
"es": "Se agregó control de tiempo con hasta 3 ventanas de tiempo configurables",
|
|
80
|
-
"pl": "Dodano kontrolę czasu z maksymalnie 3 konfigurowalnymi oknami czasowymi",
|
|
81
|
-
"uk": "Додано керування часом з до 3 налаштовуваними часовими вікнами",
|
|
82
|
-
"zh-cn": "新增时间控制,最多可配置 3 个时间窗口"
|
|
83
|
-
},
|
|
84
|
-
"0.0.2": {
|
|
85
|
-
"en": "Extended pump logic with error detection and safety functions",
|
|
86
|
-
"de": "Pumpenlogik erweitert mit Fehlererkennung und Sicherheitsfunktionen",
|
|
87
|
-
"ru": "Расширена логика насоса с обнаружением ошибок и функциями безопасности",
|
|
88
|
-
"pt": "Lógica da bomba estendida com detecção de erros e funções de segurança",
|
|
89
|
-
"nl": "Pomplogica uitgebreid met foutdetectie en veiligheidsfuncties",
|
|
90
|
-
"fr": "Logique de pompe étendue avec détection d'erreurs et fonctions de sécurité",
|
|
91
|
-
"it": "Logica della pompa estesa con rilevamento errori e funzioni di sicurezza",
|
|
92
|
-
"es": "Lógica de la bomba ampliada con detección de errores y funciones de seguridad",
|
|
93
|
-
"pl": "Rozszerzona logika pompy z wykrywaniem błędów i funkcjami bezpieczeństwa",
|
|
94
|
-
"uk": "Розширена логіка насоса з виявленням помилок та функціями безпеки",
|
|
95
|
-
"zh-cn": "扩展泵逻辑,具有错误检测和安全功能"
|
|
96
|
-
},
|
|
97
|
-
"0.0.1": {
|
|
98
|
-
"en": "initial release",
|
|
99
|
-
"de": "Erstveröffentlichung",
|
|
100
|
-
"ru": "Начальная версия",
|
|
101
|
-
"pt": "lançamento inicial",
|
|
102
|
-
"nl": "Eerste uitgave",
|
|
103
|
-
"fr": "Première version",
|
|
104
|
-
"it": "Versione iniziale",
|
|
105
|
-
"es": "Versión inicial",
|
|
106
|
-
"pl": "Pierwsze wydanie",
|
|
107
|
-
"uk": "Початкова версія",
|
|
108
|
-
"zh-cn": "首次出版"
|
|
109
|
-
}
|
|
110
45
|
},
|
|
111
46
|
"titleLang": {
|
|
112
47
|
"en": "PoolControl",
|
|
@@ -168,9 +103,9 @@
|
|
|
168
103
|
"js-controller": ">=6.0.11"
|
|
169
104
|
}
|
|
170
105
|
],
|
|
171
|
-
|
|
106
|
+
"globalDependencies": [
|
|
172
107
|
{
|
|
173
|
-
"admin": ">=7.
|
|
108
|
+
"admin": ">=7.6.17"
|
|
174
109
|
}
|
|
175
110
|
]
|
|
176
111
|
},
|
|
@@ -179,11 +114,6 @@
|
|
|
179
114
|
"option2": "42"
|
|
180
115
|
},
|
|
181
116
|
"objects": [],
|
|
182
|
-
"instanceObjects": []
|
|
183
|
-
"support": {
|
|
184
|
-
"donate": {
|
|
185
|
-
"paypal": "https://www.paypal.com/donate?business=dirk.bertin%40t-online.de"
|
|
186
|
-
}
|
|
117
|
+
"instanceObjects": []
|
|
187
118
|
}
|
|
188
|
-
}
|
|
189
119
|
|
|
@@ -51,6 +51,20 @@ const pumpHelper = {
|
|
|
51
51
|
if (this.deviceId) {
|
|
52
52
|
this.adapter.subscribeForeignStates(this.deviceId);
|
|
53
53
|
this.adapter.log.info(`[pumpHelper] Überwache Steckdose: ${this.deviceId}`);
|
|
54
|
+
|
|
55
|
+
// NEU: Initialwert übernehmen
|
|
56
|
+
this.adapter
|
|
57
|
+
.getForeignStateAsync(this.deviceId)
|
|
58
|
+
.then(s => {
|
|
59
|
+
if (s) {
|
|
60
|
+
const val = !!s.val;
|
|
61
|
+
this.adapter.setStateAsync('pump.pump_switch', { val, ack: true });
|
|
62
|
+
this.adapter.log.info(`[pumpHelper] Initialer Pumpenstatus von Steckdose übernommen: ${val}`);
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
.catch(err =>
|
|
66
|
+
this.adapter.log.warn(`[pumpHelper] Konnte initialen Pumpenstatus nicht laden: ${err.message}`),
|
|
67
|
+
);
|
|
54
68
|
} else {
|
|
55
69
|
this.adapter.log.info('[pumpHelper] Keine Objekt-ID für Pumpen-Steckdose konfiguriert');
|
|
56
70
|
}
|
|
@@ -23,13 +23,43 @@ const runtimeHelper = {
|
|
|
23
23
|
// Pumpenschalter überwachen
|
|
24
24
|
this.adapter.subscribeStates('pump.pump_switch');
|
|
25
25
|
|
|
26
|
-
//
|
|
27
|
-
this.
|
|
26
|
+
// >>> NEU: Alte Werte aus States laden
|
|
27
|
+
this._restoreFromStates()
|
|
28
|
+
.then(() => {
|
|
29
|
+
// Tagesreset einplanen
|
|
30
|
+
this._scheduleDailyReset();
|
|
31
|
+
|
|
32
|
+
// Erst nach Restore einmal berechnen
|
|
33
|
+
this._updateStates();
|
|
34
|
+
|
|
35
|
+
this.adapter.log.info('[runtimeHelper] initialisiert (mit Restore)');
|
|
36
|
+
})
|
|
37
|
+
.catch(err => {
|
|
38
|
+
this.adapter.log.warn(`[runtimeHelper] Restore fehlgeschlagen: ${err.message}`);
|
|
39
|
+
this._scheduleDailyReset();
|
|
40
|
+
this._updateStates();
|
|
41
|
+
this.adapter.log.info('[runtimeHelper] initialisiert (ohne Restore)');
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
async _restoreFromStates() {
|
|
46
|
+
const total = Number((await this.adapter.getStateAsync('runtime.total'))?.val);
|
|
47
|
+
const today = Number((await this.adapter.getStateAsync('runtime.today'))?.val);
|
|
28
48
|
|
|
29
|
-
|
|
30
|
-
|
|
49
|
+
if (Number.isFinite(total)) {
|
|
50
|
+
this.runtimeTotal = total;
|
|
51
|
+
}
|
|
52
|
+
if (Number.isFinite(today)) {
|
|
53
|
+
this.runtimeToday = today;
|
|
54
|
+
}
|
|
31
55
|
|
|
32
|
-
|
|
56
|
+
// Falls Pumpe gerade läuft → Status wiederherstellen
|
|
57
|
+
const active = !!(await this.adapter.getStateAsync('pump.pump_switch'))?.val;
|
|
58
|
+
if (active) {
|
|
59
|
+
this.isRunning = true;
|
|
60
|
+
this.lastOn = Date.now();
|
|
61
|
+
this._startLiveTimer();
|
|
62
|
+
}
|
|
33
63
|
},
|
|
34
64
|
|
|
35
65
|
async handleStateChange(id, state) {
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* statusHelper
|
|
5
|
+
* - Erstellt Text- und JSON-Zusammenfassungen
|
|
6
|
+
* - Schreibt Pumpenstart/Stop-Zeiten, Zähler, Indikatoren
|
|
7
|
+
* - Hält systemweite OK/Warning-Flags aktuell
|
|
8
|
+
* - Führt Tagesreset um Mitternacht durch
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const statusHelper = {
|
|
12
|
+
adapter: null,
|
|
13
|
+
midnightTimer: null,
|
|
14
|
+
pumpOn: null, // interner Merker für Pumpenstatus
|
|
15
|
+
|
|
16
|
+
init(adapter) {
|
|
17
|
+
this.adapter = adapter;
|
|
18
|
+
|
|
19
|
+
// Relevante States überwachen
|
|
20
|
+
this.adapter.subscribeStates('pump.status');
|
|
21
|
+
this.adapter.subscribeStates('pump.mode');
|
|
22
|
+
this.adapter.subscribeStates('pump.pump_switch'); // wichtig für Start/Stop
|
|
23
|
+
this.adapter.subscribeStates('temperature.surface.current');
|
|
24
|
+
this.adapter.subscribeStates('temperature.collector.current');
|
|
25
|
+
this.adapter.subscribeStates('temperature.outside.current');
|
|
26
|
+
this.adapter.subscribeStates('runtime.today');
|
|
27
|
+
this.adapter.subscribeStates('circulation.daily_total');
|
|
28
|
+
this.adapter.subscribeStates('circulation.daily_required');
|
|
29
|
+
|
|
30
|
+
// System-Warnungen überwachen
|
|
31
|
+
this.adapter.subscribeStates('solar.collector_warning');
|
|
32
|
+
this.adapter.subscribeStates('pump.error');
|
|
33
|
+
|
|
34
|
+
// Aktuellen Pumpenstatus laden
|
|
35
|
+
this.adapter
|
|
36
|
+
.getStateAsync('pump.pump_switch')
|
|
37
|
+
.then(s => {
|
|
38
|
+
this.pumpOn = !!s?.val;
|
|
39
|
+
})
|
|
40
|
+
.catch(() => {
|
|
41
|
+
this.pumpOn = false;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Beim Start initiale Updates
|
|
45
|
+
this.updateSummary().catch(err =>
|
|
46
|
+
this.adapter.log.warn(`[statusHelper] Initial-Update fehlgeschlagen: ${err.message}`),
|
|
47
|
+
);
|
|
48
|
+
this.updateSystemStatus().catch(err =>
|
|
49
|
+
this.adapter.log.warn(`[statusHelper] Initial-Systemstatus fehlgeschlagen: ${err.message}`),
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
// Mitternacht-Reset einplanen
|
|
53
|
+
this.scheduleMidnightReset();
|
|
54
|
+
|
|
55
|
+
this.adapter.log.info('[statusHelper] initialisiert');
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
async handleStateChange(id, state) {
|
|
59
|
+
if (!state || state.ack !== true) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Pumpenstart/-stop
|
|
64
|
+
if (id.endsWith('pump.pump_switch')) {
|
|
65
|
+
const nowOn = !!state.val;
|
|
66
|
+
|
|
67
|
+
// steigende Flanke
|
|
68
|
+
if (nowOn && this.pumpOn !== true) {
|
|
69
|
+
await this.adapter.setStateAsync('status.pump_last_start', {
|
|
70
|
+
val: new Date().toISOString(),
|
|
71
|
+
ack: true,
|
|
72
|
+
});
|
|
73
|
+
const currentCount = (await this.adapter.getStateAsync('status.pump_today_count'))?.val || 0;
|
|
74
|
+
await this.adapter.setStateAsync('status.pump_today_count', { val: currentCount + 1, ack: true });
|
|
75
|
+
await this.adapter.setStateAsync('status.pump_was_on_today', { val: true, ack: true });
|
|
76
|
+
this.pumpOn = true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// fallende Flanke
|
|
80
|
+
if (!nowOn && this.pumpOn !== false) {
|
|
81
|
+
await this.adapter.setStateAsync('status.pump_last_stop', {
|
|
82
|
+
val: new Date().toISOString(),
|
|
83
|
+
ack: true,
|
|
84
|
+
});
|
|
85
|
+
this.pumpOn = false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// System-Warnungen
|
|
90
|
+
if (id.endsWith('solar.collector_warning') || id.endsWith('pump.error')) {
|
|
91
|
+
await this.updateSystemStatus();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Allgemeines Update
|
|
95
|
+
await this.updateSummary();
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
async updateSummary() {
|
|
99
|
+
try {
|
|
100
|
+
// Werte laden
|
|
101
|
+
const pumpStatus = (await this.adapter.getStateAsync('pump.status'))?.val || 'unbekannt';
|
|
102
|
+
const pumpMode = (await this.adapter.getStateAsync('pump.mode'))?.val || 'unknown';
|
|
103
|
+
|
|
104
|
+
const poolTemp = (await this.adapter.getStateAsync('temperature.surface.current'))?.val;
|
|
105
|
+
const collectorTemp = (await this.adapter.getStateAsync('temperature.collector.current'))?.val;
|
|
106
|
+
const outsideTemp = (await this.adapter.getStateAsync('temperature.outside.current'))?.val;
|
|
107
|
+
|
|
108
|
+
const runtimeToday = (await this.adapter.getStateAsync('runtime.today'))?.val || 0;
|
|
109
|
+
const dailyTotal = (await this.adapter.getStateAsync('circulation.daily_total'))?.val || 0;
|
|
110
|
+
const dailyRequired = (await this.adapter.getStateAsync('circulation.daily_required'))?.val || 0;
|
|
111
|
+
|
|
112
|
+
// Laufzeit formatieren
|
|
113
|
+
const h = Math.floor(runtimeToday / 3600);
|
|
114
|
+
const m = Math.floor((runtimeToday % 3600) / 60);
|
|
115
|
+
const runtimeFormatted = `${h}h ${m}m`;
|
|
116
|
+
|
|
117
|
+
// Umwälzungsquote
|
|
118
|
+
let circulationPct = 0;
|
|
119
|
+
if (dailyRequired > 0) {
|
|
120
|
+
circulationPct = Math.round((dailyTotal / dailyRequired) * 100);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Text bauen
|
|
124
|
+
let text = `Pumpe: ${pumpStatus}`;
|
|
125
|
+
if (pumpMode && pumpMode !== 'unknown') {
|
|
126
|
+
text += ` (Modus: ${pumpMode})`;
|
|
127
|
+
}
|
|
128
|
+
if (poolTemp != null) {
|
|
129
|
+
text += `. Pool: ${poolTemp.toFixed(1)} °C`;
|
|
130
|
+
}
|
|
131
|
+
if (collectorTemp != null) {
|
|
132
|
+
text += `, Kollektor: ${collectorTemp.toFixed(1)} °C`;
|
|
133
|
+
}
|
|
134
|
+
if (outsideTemp != null) {
|
|
135
|
+
text += `, Außentemperatur: ${outsideTemp.toFixed(1)} °C`;
|
|
136
|
+
}
|
|
137
|
+
text += `. Tageslaufzeit: ${runtimeFormatted} (${circulationPct}% der Soll-Umwälzung).`;
|
|
138
|
+
|
|
139
|
+
// In States schreiben
|
|
140
|
+
await this.adapter.setStateAsync('status.summary', { val: text, ack: true });
|
|
141
|
+
await this.adapter.setStateAsync('status.last_summary_update', {
|
|
142
|
+
val: new Date().toISOString(),
|
|
143
|
+
ack: true,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// JSON-Übersicht bauen
|
|
147
|
+
const json = {
|
|
148
|
+
pump: pumpStatus,
|
|
149
|
+
mode: pumpMode,
|
|
150
|
+
pool: poolTemp,
|
|
151
|
+
collector: collectorTemp,
|
|
152
|
+
outside: outsideTemp,
|
|
153
|
+
runtime_today: runtimeToday,
|
|
154
|
+
runtime_formatted: runtimeFormatted,
|
|
155
|
+
circulation_pct: circulationPct,
|
|
156
|
+
};
|
|
157
|
+
await this.adapter.setStateAsync('status.overview_json', {
|
|
158
|
+
val: JSON.stringify(json),
|
|
159
|
+
ack: true,
|
|
160
|
+
});
|
|
161
|
+
} catch (err) {
|
|
162
|
+
this.adapter.log.warn(`[statusHelper] Fehler beim Update: ${err.message}`);
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
async updateSystemStatus() {
|
|
167
|
+
try {
|
|
168
|
+
const pumpError = (await this.adapter.getStateAsync('pump.error'))?.val;
|
|
169
|
+
const collectorWarning = (await this.adapter.getStateAsync('solar.collector_warning'))?.val;
|
|
170
|
+
|
|
171
|
+
let warningActive = false;
|
|
172
|
+
let warningText = '';
|
|
173
|
+
|
|
174
|
+
if (pumpError) {
|
|
175
|
+
warningActive = true;
|
|
176
|
+
warningText += 'Pumpenfehler ';
|
|
177
|
+
}
|
|
178
|
+
if (collectorWarning) {
|
|
179
|
+
warningActive = true;
|
|
180
|
+
warningText += 'Kollektorwarnung ';
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
await this.adapter.setStateAsync('status.system_warning', { val: warningActive, ack: true });
|
|
184
|
+
await this.adapter.setStateAsync('status.system_warning_text', { val: warningText.trim(), ack: true });
|
|
185
|
+
await this.adapter.setStateAsync('status.system_ok', { val: !warningActive, ack: true });
|
|
186
|
+
} catch (err) {
|
|
187
|
+
this.adapter.log.warn(`[statusHelper] Fehler beim Systemstatus: ${err.message}`);
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
scheduleMidnightReset() {
|
|
192
|
+
if (this.midnightTimer) {
|
|
193
|
+
clearTimeout(this.midnightTimer);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const now = new Date();
|
|
197
|
+
const nextMidnight = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 5, 0);
|
|
198
|
+
const msToMidnight = nextMidnight.getTime() - now.getTime();
|
|
199
|
+
|
|
200
|
+
this.midnightTimer = setTimeout(async () => {
|
|
201
|
+
await this.doMidnightReset();
|
|
202
|
+
this.scheduleMidnightReset(); // neu einplanen
|
|
203
|
+
}, msToMidnight);
|
|
204
|
+
|
|
205
|
+
this.adapter.log.debug(`[statusHelper] Tagesreset geplant in ${Math.round(msToMidnight / 1000)}s`);
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
async doMidnightReset() {
|
|
209
|
+
try {
|
|
210
|
+
await this.adapter.setStateAsync('status.pump_today_count', { val: 0, ack: true });
|
|
211
|
+
await this.adapter.setStateAsync('status.pump_was_on_today', { val: false, ack: true });
|
|
212
|
+
this.adapter.log.info('[statusHelper] Tagesreset durchgeführt');
|
|
213
|
+
} catch (err) {
|
|
214
|
+
this.adapter.log.warn(`[statusHelper] Fehler beim Tagesreset: ${err.message}`);
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
cleanup() {
|
|
219
|
+
if (this.midnightTimer) {
|
|
220
|
+
clearTimeout(this.midnightTimer);
|
|
221
|
+
this.midnightTimer = null;
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
module.exports = statusHelper;
|
|
@@ -30,6 +30,11 @@ const temperatureHelper = {
|
|
|
30
30
|
adapter.subscribeForeignStates(id);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
// >>> NEU: Alte Min/Max-Werte wiederherstellen
|
|
34
|
+
this._restoreMinMaxFromStates().catch(err =>
|
|
35
|
+
this.adapter.log.warn(`[temperatureHelper] Restore Min/Max fehlgeschlagen: ${err.message}`),
|
|
36
|
+
);
|
|
37
|
+
|
|
33
38
|
// Reset um Mitternacht
|
|
34
39
|
this._scheduleDailyReset();
|
|
35
40
|
|
|
@@ -216,6 +221,20 @@ const temperatureHelper = {
|
|
|
216
221
|
}
|
|
217
222
|
},
|
|
218
223
|
|
|
224
|
+
// >>> NEU: Restore von min/max beim Start
|
|
225
|
+
async _restoreMinMaxFromStates() {
|
|
226
|
+
for (const key of Object.keys(this.sensors)) {
|
|
227
|
+
const min = Number((await this.adapter.getStateAsync(`temperature.${key}.min_today`))?.val);
|
|
228
|
+
const max = Number((await this.adapter.getStateAsync(`temperature.${key}.max_today`))?.val);
|
|
229
|
+
if (Number.isFinite(min) || Number.isFinite(max)) {
|
|
230
|
+
this.minMax[key] = {
|
|
231
|
+
min: Number.isFinite(min) ? min : undefined,
|
|
232
|
+
max: Number.isFinite(max) ? max : undefined,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
|
|
219
238
|
cleanup() {
|
|
220
239
|
if (this.resetTimer) {
|
|
221
240
|
clearTimeout(this.resetTimer);
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* - costs.total_eur
|
|
10
10
|
* - costs.day_eur, week_eur, month_eur, year_eur
|
|
11
11
|
*
|
|
12
|
+
* States sind persistent - Werte bleiben erhalten nach Neustart
|
|
13
|
+
*
|
|
12
14
|
* @param {import("iobroker").Adapter} adapter - ioBroker Adapter-Instanz
|
|
13
15
|
*/
|
|
14
16
|
async function createConsumptionStates(adapter) {
|
|
@@ -39,10 +41,15 @@ async function createConsumptionStates(adapter) {
|
|
|
39
41
|
unit: cfg.unit,
|
|
40
42
|
read: true,
|
|
41
43
|
write: false,
|
|
44
|
+
persist: true,
|
|
42
45
|
},
|
|
43
46
|
native: {},
|
|
44
47
|
});
|
|
45
|
-
|
|
48
|
+
// NUR falls noch kein Wert existiert (erste Installation)
|
|
49
|
+
const cur = await adapter.getStateAsync(`consumption.${id}`);
|
|
50
|
+
if (cur == null) {
|
|
51
|
+
await adapter.setStateAsync(`consumption.${id}`, { val: 0, ack: true });
|
|
52
|
+
}
|
|
46
53
|
}
|
|
47
54
|
|
|
48
55
|
// --- Kanal costs ---
|
|
@@ -70,10 +77,14 @@ async function createConsumptionStates(adapter) {
|
|
|
70
77
|
unit: cfg.unit,
|
|
71
78
|
read: true,
|
|
72
79
|
write: false,
|
|
80
|
+
persist: true,
|
|
73
81
|
},
|
|
74
82
|
native: {},
|
|
75
83
|
});
|
|
76
|
-
await adapter.
|
|
84
|
+
const cur = await adapter.getStateAsync(`costs.${id}`);
|
|
85
|
+
if (cur == null) {
|
|
86
|
+
await adapter.setStateAsync(`costs.${id}`, { val: 0, ack: true });
|
|
87
|
+
}
|
|
77
88
|
}
|
|
78
89
|
}
|
|
79
90
|
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* - circulation.daily_required
|
|
10
10
|
* - circulation.daily_remaining
|
|
11
11
|
*
|
|
12
|
+
* States sind persistent - behalten Werte über Neustart
|
|
13
|
+
*
|
|
12
14
|
* @param {import("iobroker").Adapter} adapter - ioBroker Adapter-Instanz
|
|
13
15
|
*/
|
|
14
16
|
async function createRuntimeStates(adapter) {
|
|
@@ -28,6 +30,7 @@ async function createRuntimeStates(adapter) {
|
|
|
28
30
|
unit: 's',
|
|
29
31
|
read: true,
|
|
30
32
|
write: false,
|
|
33
|
+
persist: true,
|
|
31
34
|
},
|
|
32
35
|
native: {},
|
|
33
36
|
});
|
|
@@ -41,6 +44,7 @@ async function createRuntimeStates(adapter) {
|
|
|
41
44
|
unit: 's',
|
|
42
45
|
read: true,
|
|
43
46
|
write: false,
|
|
47
|
+
persist: true,
|
|
44
48
|
},
|
|
45
49
|
native: {},
|
|
46
50
|
});
|
|
@@ -53,6 +57,7 @@ async function createRuntimeStates(adapter) {
|
|
|
53
57
|
role: 'text',
|
|
54
58
|
read: true,
|
|
55
59
|
write: false,
|
|
60
|
+
persist: true,
|
|
56
61
|
},
|
|
57
62
|
native: {},
|
|
58
63
|
});
|
|
@@ -73,6 +78,7 @@ async function createRuntimeStates(adapter) {
|
|
|
73
78
|
unit: 'l',
|
|
74
79
|
read: true,
|
|
75
80
|
write: false,
|
|
81
|
+
persist: true,
|
|
76
82
|
},
|
|
77
83
|
native: {},
|
|
78
84
|
});
|
|
@@ -86,6 +92,7 @@ async function createRuntimeStates(adapter) {
|
|
|
86
92
|
unit: 'l',
|
|
87
93
|
read: true,
|
|
88
94
|
write: false,
|
|
95
|
+
persist: true,
|
|
89
96
|
},
|
|
90
97
|
native: {},
|
|
91
98
|
});
|
|
@@ -103,6 +110,7 @@ async function createRuntimeStates(adapter) {
|
|
|
103
110
|
unit: 'l',
|
|
104
111
|
read: true,
|
|
105
112
|
write: false,
|
|
113
|
+
persist: true,
|
|
106
114
|
},
|
|
107
115
|
native: {},
|
|
108
116
|
});
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Legt alle States für Status-Übersichten an:
|
|
5
|
+
* - status.summary (string, Textzusammenfassung)
|
|
6
|
+
* - status.overview_json (string, JSON-Zusammenfassung)
|
|
7
|
+
* - status.last_summary_update (string, Zeitstempel)
|
|
8
|
+
* - status.pump_last_start (string, Zeitstempel)
|
|
9
|
+
* - status.pump_last_stop (string, Zeitstempel)
|
|
10
|
+
* - status.pump_was_on_today (boolean)
|
|
11
|
+
* - status.pump_today_count (number)
|
|
12
|
+
* - status.system_ok (boolean)
|
|
13
|
+
* - status.system_warning (boolean)
|
|
14
|
+
* - status.system_warning_text (string)
|
|
15
|
+
* - status.season_active (boolean)
|
|
16
|
+
*
|
|
17
|
+
* @param {import("iobroker").Adapter} adapter - ioBroker Adapter-Instanz
|
|
18
|
+
*/
|
|
19
|
+
async function createStatusStates(adapter) {
|
|
20
|
+
// Root-Kanal "status"
|
|
21
|
+
await adapter.setObjectNotExistsAsync('status', {
|
|
22
|
+
type: 'channel',
|
|
23
|
+
common: { name: 'Statusübersicht' },
|
|
24
|
+
native: {},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Zusammenfassung als Text
|
|
28
|
+
await adapter.setObjectNotExistsAsync('status.summary', {
|
|
29
|
+
type: 'state',
|
|
30
|
+
common: {
|
|
31
|
+
name: 'Zusammenfassung als Text',
|
|
32
|
+
type: 'string',
|
|
33
|
+
role: 'text',
|
|
34
|
+
read: true,
|
|
35
|
+
write: false,
|
|
36
|
+
// bewusst kein persist: true, da nur Live-Daten
|
|
37
|
+
},
|
|
38
|
+
native: {},
|
|
39
|
+
});
|
|
40
|
+
await adapter.setStateAsync('status.summary', { val: '', ack: true });
|
|
41
|
+
|
|
42
|
+
// JSON-Zusammenfassung
|
|
43
|
+
await adapter.setObjectNotExistsAsync('status.overview_json', {
|
|
44
|
+
type: 'state',
|
|
45
|
+
common: {
|
|
46
|
+
name: 'Übersicht als JSON',
|
|
47
|
+
type: 'string',
|
|
48
|
+
role: 'json',
|
|
49
|
+
read: true,
|
|
50
|
+
write: false,
|
|
51
|
+
},
|
|
52
|
+
native: {},
|
|
53
|
+
});
|
|
54
|
+
await adapter.setStateAsync('status.overview_json', { val: '{}', ack: true });
|
|
55
|
+
|
|
56
|
+
// Letzte Aktualisierung der Summary
|
|
57
|
+
await adapter.setObjectNotExistsAsync('status.last_summary_update', {
|
|
58
|
+
type: 'state',
|
|
59
|
+
common: {
|
|
60
|
+
name: 'Letzte Aktualisierung der Zusammenfassung',
|
|
61
|
+
type: 'string',
|
|
62
|
+
role: 'date',
|
|
63
|
+
read: true,
|
|
64
|
+
write: false,
|
|
65
|
+
},
|
|
66
|
+
native: {},
|
|
67
|
+
});
|
|
68
|
+
await adapter.setStateAsync('status.last_summary_update', { val: '', ack: true });
|
|
69
|
+
|
|
70
|
+
// Pumpen-Status: letzter Start
|
|
71
|
+
await adapter.setObjectNotExistsAsync('status.pump_last_start', {
|
|
72
|
+
type: 'state',
|
|
73
|
+
common: {
|
|
74
|
+
name: 'Letzter Pumpenstart',
|
|
75
|
+
type: 'string',
|
|
76
|
+
role: 'date',
|
|
77
|
+
read: true,
|
|
78
|
+
write: false,
|
|
79
|
+
},
|
|
80
|
+
native: {},
|
|
81
|
+
});
|
|
82
|
+
await adapter.setStateAsync('status.pump_last_start', { val: '', ack: true });
|
|
83
|
+
|
|
84
|
+
// Pumpen-Status: letzter Stopp
|
|
85
|
+
await adapter.setObjectNotExistsAsync('status.pump_last_stop', {
|
|
86
|
+
type: 'state',
|
|
87
|
+
common: {
|
|
88
|
+
name: 'Letztes Pumpenende',
|
|
89
|
+
type: 'string',
|
|
90
|
+
role: 'date',
|
|
91
|
+
read: true,
|
|
92
|
+
write: false,
|
|
93
|
+
},
|
|
94
|
+
native: {},
|
|
95
|
+
});
|
|
96
|
+
await adapter.setStateAsync('status.pump_last_stop', { val: '', ack: true });
|
|
97
|
+
|
|
98
|
+
// Pumpen-Status: heute eingeschaltet
|
|
99
|
+
await adapter.setObjectNotExistsAsync('status.pump_was_on_today', {
|
|
100
|
+
type: 'state',
|
|
101
|
+
common: {
|
|
102
|
+
name: 'Pumpe war heute eingeschaltet',
|
|
103
|
+
type: 'boolean',
|
|
104
|
+
role: 'indicator',
|
|
105
|
+
read: true,
|
|
106
|
+
write: false,
|
|
107
|
+
},
|
|
108
|
+
native: {},
|
|
109
|
+
});
|
|
110
|
+
await adapter.setStateAsync('status.pump_was_on_today', { val: false, ack: true });
|
|
111
|
+
|
|
112
|
+
// Pumpen-Status: Anzahl Starts heute
|
|
113
|
+
await adapter.setObjectNotExistsAsync('status.pump_today_count', {
|
|
114
|
+
type: 'state',
|
|
115
|
+
common: {
|
|
116
|
+
name: 'Pumpenstarts heute',
|
|
117
|
+
type: 'number',
|
|
118
|
+
role: 'value',
|
|
119
|
+
read: true,
|
|
120
|
+
write: false,
|
|
121
|
+
},
|
|
122
|
+
native: {},
|
|
123
|
+
});
|
|
124
|
+
await adapter.setStateAsync('status.pump_today_count', { val: 0, ack: true });
|
|
125
|
+
|
|
126
|
+
// Systemstatus: OK
|
|
127
|
+
await adapter.setObjectNotExistsAsync('status.system_ok', {
|
|
128
|
+
type: 'state',
|
|
129
|
+
common: {
|
|
130
|
+
name: 'System OK',
|
|
131
|
+
type: 'boolean',
|
|
132
|
+
role: 'indicator',
|
|
133
|
+
read: true,
|
|
134
|
+
write: false,
|
|
135
|
+
},
|
|
136
|
+
native: {},
|
|
137
|
+
});
|
|
138
|
+
await adapter.setStateAsync('status.system_ok', { val: true, ack: true });
|
|
139
|
+
|
|
140
|
+
// Systemstatus: Warnung aktiv
|
|
141
|
+
await adapter.setObjectNotExistsAsync('status.system_warning', {
|
|
142
|
+
type: 'state',
|
|
143
|
+
common: {
|
|
144
|
+
name: 'System-Warnung aktiv',
|
|
145
|
+
type: 'boolean',
|
|
146
|
+
role: 'indicator',
|
|
147
|
+
read: true,
|
|
148
|
+
write: false,
|
|
149
|
+
},
|
|
150
|
+
native: {},
|
|
151
|
+
});
|
|
152
|
+
await adapter.setStateAsync('status.system_warning', { val: false, ack: true });
|
|
153
|
+
|
|
154
|
+
// Systemstatus: Warnungstext
|
|
155
|
+
await adapter.setObjectNotExistsAsync('status.system_warning_text', {
|
|
156
|
+
type: 'state',
|
|
157
|
+
common: {
|
|
158
|
+
name: 'Beschreibung der Systemwarnung',
|
|
159
|
+
type: 'string',
|
|
160
|
+
role: 'text',
|
|
161
|
+
read: true,
|
|
162
|
+
write: false,
|
|
163
|
+
},
|
|
164
|
+
native: {},
|
|
165
|
+
});
|
|
166
|
+
await adapter.setStateAsync('status.system_warning_text', { val: '', ack: true });
|
|
167
|
+
|
|
168
|
+
// Saisonstatus
|
|
169
|
+
await adapter.setObjectNotExistsAsync('status.season_active', {
|
|
170
|
+
type: 'state',
|
|
171
|
+
common: {
|
|
172
|
+
name: 'Poolsaison aktiv',
|
|
173
|
+
type: 'boolean',
|
|
174
|
+
role: 'indicator',
|
|
175
|
+
read: true,
|
|
176
|
+
write: false,
|
|
177
|
+
},
|
|
178
|
+
native: {},
|
|
179
|
+
});
|
|
180
|
+
await adapter.setStateAsync('status.season_active', { val: false, ack: true });
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
module.exports = {
|
|
184
|
+
createStatusStates,
|
|
185
|
+
};
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
* - temperature.delta.surface_ground
|
|
17
17
|
* - temperature.delta.flow_return
|
|
18
18
|
*
|
|
19
|
+
* States mit Persistenz - bleiben erhalten bei Neustart
|
|
20
|
+
*
|
|
19
21
|
* @param {import("iobroker").Adapter} adapter - ioBroker Adapter-Instanz
|
|
20
22
|
*/
|
|
21
23
|
async function createTemperatureStates(adapter) {
|
|
@@ -97,6 +99,7 @@ async function createTemperatureStates(adapter) {
|
|
|
97
99
|
unit: '°C',
|
|
98
100
|
read: true,
|
|
99
101
|
write: false,
|
|
102
|
+
persist: true,
|
|
100
103
|
},
|
|
101
104
|
native: {},
|
|
102
105
|
});
|
|
@@ -110,6 +113,7 @@ async function createTemperatureStates(adapter) {
|
|
|
110
113
|
unit: '°C',
|
|
111
114
|
read: true,
|
|
112
115
|
write: false,
|
|
116
|
+
persist: true,
|
|
113
117
|
},
|
|
114
118
|
native: {},
|
|
115
119
|
});
|
package/main.js
CHANGED
|
@@ -13,6 +13,7 @@ const speechHelper = require('./lib/helpers/speechHelper');
|
|
|
13
13
|
const consumptionHelper = require('./lib/helpers/consumptionHelper');
|
|
14
14
|
const solarHelper = require('./lib/helpers/solarHelper');
|
|
15
15
|
const frostHelper = require('./lib/helpers/frostHelper');
|
|
16
|
+
const statusHelper = require('./lib/helpers/statusHelper');
|
|
16
17
|
const { createTemperatureStates } = require('./lib/stateDefinitions/temperatureStates');
|
|
17
18
|
const { createPumpStates } = require('./lib/stateDefinitions/pumpStates');
|
|
18
19
|
const { createSolarStates } = require('./lib/stateDefinitions/solarStates');
|
|
@@ -21,6 +22,7 @@ const { createTimeStates } = require('./lib/stateDefinitions/timeStates');
|
|
|
21
22
|
const { createRuntimeStates } = require('./lib/stateDefinitions/runtimeStates');
|
|
22
23
|
const { createSpeechStates } = require('./lib/stateDefinitions/speechStates');
|
|
23
24
|
const { createConsumptionStates } = require('./lib/stateDefinitions/consumptionStates');
|
|
25
|
+
const { createStatusStates } = require('./lib/stateDefinitions/statusStates');
|
|
24
26
|
|
|
25
27
|
class Poolcontrol extends utils.Adapter {
|
|
26
28
|
constructor(options) {
|
|
@@ -60,6 +62,9 @@ class Poolcontrol extends utils.Adapter {
|
|
|
60
62
|
// --- Verbrauch & Kosten ---
|
|
61
63
|
await createConsumptionStates(this);
|
|
62
64
|
|
|
65
|
+
// --- Statusübersicht ---
|
|
66
|
+
await createStatusStates(this);
|
|
67
|
+
|
|
63
68
|
// --- Helper starten ---
|
|
64
69
|
temperatureHelper.init(this);
|
|
65
70
|
timeHelper.init(this);
|
|
@@ -69,6 +74,7 @@ class Poolcontrol extends utils.Adapter {
|
|
|
69
74
|
consumptionHelper.init(this);
|
|
70
75
|
solarHelper.init(this);
|
|
71
76
|
frostHelper.init(this);
|
|
77
|
+
statusHelper.init(this);
|
|
72
78
|
}
|
|
73
79
|
|
|
74
80
|
onUnload(callback) {
|
|
@@ -97,6 +103,9 @@ class Poolcontrol extends utils.Adapter {
|
|
|
97
103
|
if (frostHelper.cleanup) {
|
|
98
104
|
frostHelper.cleanup();
|
|
99
105
|
}
|
|
106
|
+
if (statusHelper.cleanup) {
|
|
107
|
+
statusHelper.cleanup();
|
|
108
|
+
}
|
|
100
109
|
} catch (e) {
|
|
101
110
|
this.log.warn(`[onUnload] Fehler beim Cleanup: ${e.message}`);
|
|
102
111
|
} finally {
|
|
@@ -135,6 +144,11 @@ class Poolcontrol extends utils.Adapter {
|
|
|
135
144
|
} catch (e) {
|
|
136
145
|
this.log.warn(`[consumptionHelper] Fehler in handleStateChange: ${e.message}`);
|
|
137
146
|
}
|
|
147
|
+
try {
|
|
148
|
+
statusHelper.handleStateChange(id, state);
|
|
149
|
+
} catch (e) {
|
|
150
|
+
this.log.warn(`[statusHelper] Fehler in handleStateChange: ${e.message}`);
|
|
151
|
+
}
|
|
138
152
|
}
|
|
139
153
|
}
|
|
140
154
|
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.poolcontrol",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"description": "Steuerung & Automatisierung für den Pool (Pumpe, Heizung, Ventile, Sensoren).",
|
|
5
5
|
"author": "DasBo1975 <dasbo1975@outlook.de>",
|
|
6
|
-
"homepage": "https://github.com/DasBo1975/
|
|
6
|
+
"homepage": "https://github.com/DasBo1975/ioBroker.poolcontrol",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"keywords": [
|
|
9
|
+
"ioBroker",
|
|
9
10
|
"pool",
|
|
10
11
|
"pumpe",
|
|
11
12
|
"solar",
|
|
@@ -14,7 +15,7 @@
|
|
|
14
15
|
],
|
|
15
16
|
"repository": {
|
|
16
17
|
"type": "git",
|
|
17
|
-
"url": "https://github.com/DasBo1975/
|
|
18
|
+
"url": "https://github.com/DasBo1975/ioBroker.poolcontrol.git"
|
|
18
19
|
},
|
|
19
20
|
"engines": {
|
|
20
21
|
"node": ">= 20"
|
|
@@ -26,14 +27,9 @@
|
|
|
26
27
|
"@iobroker/adapter-dev": "^1.5.0",
|
|
27
28
|
"@iobroker/eslint-config": "^2.2.0",
|
|
28
29
|
"@iobroker/testing": "^5.1.1",
|
|
29
|
-
"chai": "^4.5.0",
|
|
30
|
-
"chai-as-promised": "^7.1.2",
|
|
31
30
|
"eslint": "^9.36.0",
|
|
32
|
-
"mocha": "^11.7.2",
|
|
33
31
|
"prettier": "^3.6.2",
|
|
34
|
-
"proxyquire": "^2.1.3"
|
|
35
|
-
"sinon": "^21.0.0",
|
|
36
|
-
"sinon-chai": "^3.7.0"
|
|
32
|
+
"proxyquire": "^2.1.3"
|
|
37
33
|
},
|
|
38
34
|
"main": "main.js",
|
|
39
35
|
"files": [
|
|
@@ -54,7 +50,7 @@
|
|
|
54
50
|
"translate": "translate-adapter"
|
|
55
51
|
},
|
|
56
52
|
"bugs": {
|
|
57
|
-
"url": "https://github.com/DasBo1975/
|
|
53
|
+
"url": "https://github.com/DasBo1975/ioBroker.poolcontrol/issues"
|
|
58
54
|
},
|
|
59
55
|
"readmeFilename": "README.md"
|
|
60
56
|
}
|