iobroker.poolcontrol 0.7.2 → 0.8.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 +54 -3
- package/admin/jsonConfig.json +96 -2
- package/io-package.json +40 -39
- package/lib/helpers/aiForecastHelper.js +448 -0
- package/lib/helpers/aiHelper.js +1116 -0
- package/lib/helpers/infoHelper.js +1 -1
- package/lib/stateDefinitions/aiStates.js +199 -0
- package/lib/stateDefinitions/controlStates.js +10 -1
- package/main.js +25 -0
- package/package.json +2 -1
|
@@ -56,7 +56,7 @@ const infoHelper = {
|
|
|
56
56
|
let greeting = '';
|
|
57
57
|
|
|
58
58
|
// Weihnachten: 20.12. – 27.12.
|
|
59
|
-
if (
|
|
59
|
+
if (month === 12 && day >= 20 && day <= 27) {
|
|
60
60
|
greeting = '🎄 PoolControl wünscht frohe Weihnachten! 🎄';
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aiStates.js
|
|
5
|
+
* ----------------------------------------------------------
|
|
6
|
+
* Definiert alle States für den KI-Bereich des PoolControl-Adapters.
|
|
7
|
+
*
|
|
8
|
+
* Neue Struktur:
|
|
9
|
+
* ai.enabled → globaler KI-Hauptschalter
|
|
10
|
+
*
|
|
11
|
+
* ai.weather.switches.* → Schalter für Wetter-KI
|
|
12
|
+
* ai.weather.schedule.* → Zeitpläne für Wetter-KI
|
|
13
|
+
* ai.weather.outputs.* → Textausgaben der Wetter-KI
|
|
14
|
+
* ----------------------------------------------------------
|
|
15
|
+
*
|
|
16
|
+
* @param {import('iobroker').Adapter} adapter - ioBroker Adapterinstanz
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Erstellt alle KI-bezogenen States (ai.*)
|
|
21
|
+
*
|
|
22
|
+
* @param {import('iobroker').Adapter} adapter - ioBroker Adapterinstanz
|
|
23
|
+
*/
|
|
24
|
+
async function createAiStates(adapter) {
|
|
25
|
+
adapter.log.debug('[aiStates] Initialisierung gestartet');
|
|
26
|
+
|
|
27
|
+
// ------------------------------------------------------
|
|
28
|
+
// Hauptordner: ai
|
|
29
|
+
// ------------------------------------------------------
|
|
30
|
+
await adapter.setObjectNotExistsAsync('ai', {
|
|
31
|
+
type: 'channel',
|
|
32
|
+
common: { name: 'KI / AI-Funktionen' },
|
|
33
|
+
native: {},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// ------------------------------------------------------
|
|
37
|
+
// NEU / GEÄNDERT:
|
|
38
|
+
// Globaler KI-Hauptschalter (anstatt ai.switches.enabled)
|
|
39
|
+
// ------------------------------------------------------
|
|
40
|
+
await adapter.setObjectNotExistsAsync('ai.enabled', {
|
|
41
|
+
type: 'state',
|
|
42
|
+
common: {
|
|
43
|
+
name: 'KI aktivieren',
|
|
44
|
+
desc: 'Globaler Hauptschalter für alle KI-Funktionen',
|
|
45
|
+
type: 'boolean',
|
|
46
|
+
role: 'switch',
|
|
47
|
+
read: true,
|
|
48
|
+
write: true,
|
|
49
|
+
def: false,
|
|
50
|
+
persist: true,
|
|
51
|
+
},
|
|
52
|
+
native: {},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// ------------------------------------------------------
|
|
56
|
+
// NEU: Wetter-Hauptordner
|
|
57
|
+
// ------------------------------------------------------
|
|
58
|
+
await adapter.setObjectNotExistsAsync('ai.weather', {
|
|
59
|
+
type: 'channel',
|
|
60
|
+
common: {
|
|
61
|
+
name: 'Wetterbezogene KI-Funktionen',
|
|
62
|
+
desc: 'Alle KI-Funktionen rund um Wetter, Vorhersagen und Pooltipps',
|
|
63
|
+
},
|
|
64
|
+
native: {},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// ------------------------------------------------------
|
|
68
|
+
// NEU: Unterordner Wetter-Switches
|
|
69
|
+
// ------------------------------------------------------
|
|
70
|
+
await adapter.setObjectNotExistsAsync('ai.weather.switches', {
|
|
71
|
+
type: 'channel',
|
|
72
|
+
common: {
|
|
73
|
+
name: 'Schalter (Wetter-KI)',
|
|
74
|
+
desc: 'Einzelne Schalter für wetterbezogene KI-Funktionen',
|
|
75
|
+
},
|
|
76
|
+
native: {},
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// NEU / GEÄNDERT:
|
|
80
|
+
// Alle bisherigen wetterbezogenen Switches liegen jetzt unter ai.weather.switches.*
|
|
81
|
+
const weatherSwitches = [
|
|
82
|
+
// Steuerung & Debug für Wetter-KI
|
|
83
|
+
{ id: 'allow_speech', name: 'Sprachausgabe für Wetter-KI erlauben', def: false }, // GEÄNDERT: von ai.switches → ai.weather.switches
|
|
84
|
+
{ id: 'debug_mode', name: 'Debugmodus für Wetter-KI', def: false }, // GEÄNDERT: von ai.switches → ai.weather.switches
|
|
85
|
+
|
|
86
|
+
// Modulspezifische Schalter
|
|
87
|
+
{ id: 'daily_summary_enabled', name: 'Tägliche Zusammenfassung aktiv', def: false },
|
|
88
|
+
{ id: 'daily_pool_tips_enabled', name: 'Tägliche Pool-Tipps aktiv', def: false },
|
|
89
|
+
{ id: 'weather_advice_enabled', name: 'Wetterhinweise aktiv', def: false },
|
|
90
|
+
{ id: 'weekend_summary_enabled', name: 'Wochenende-Zusammenfassung aktiv', def: false },
|
|
91
|
+
|
|
92
|
+
// NEU: Schalter für "Vorhersage für morgen"
|
|
93
|
+
{ id: 'tomorrow_forecast_enabled', name: 'Vorhersage für morgen aktiv', def: false }, // NEU
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
for (const s of weatherSwitches) {
|
|
97
|
+
await adapter.setObjectNotExistsAsync(`ai.weather.switches.${s.id}`, {
|
|
98
|
+
type: 'state',
|
|
99
|
+
common: {
|
|
100
|
+
name: s.name,
|
|
101
|
+
type: 'boolean',
|
|
102
|
+
role: 'switch',
|
|
103
|
+
read: true,
|
|
104
|
+
write: true,
|
|
105
|
+
def: s.def,
|
|
106
|
+
persist: true,
|
|
107
|
+
},
|
|
108
|
+
native: {},
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ------------------------------------------------------
|
|
113
|
+
// NEU: Unterordner Wetter-Schedule
|
|
114
|
+
// ------------------------------------------------------
|
|
115
|
+
await adapter.setObjectNotExistsAsync('ai.weather.schedule', {
|
|
116
|
+
type: 'channel',
|
|
117
|
+
common: {
|
|
118
|
+
name: 'Zeitpläne (Wetter-KI)',
|
|
119
|
+
desc: 'Zeitsteuerung für wetterbezogene KI-Ausgaben',
|
|
120
|
+
},
|
|
121
|
+
native: {},
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// NEU / GEÄNDERT:
|
|
125
|
+
// Alle Zeitpläne liegen jetzt unter ai.weather.schedule.*
|
|
126
|
+
const weatherSchedule = [
|
|
127
|
+
{ id: 'daily_summary_time', name: 'Zeit für tägliche Zusammenfassung', def: '09:00' },
|
|
128
|
+
{ id: 'daily_pool_tips_time', name: 'Zeit für tägliche Pool-Tipps', def: '10:00' },
|
|
129
|
+
{ id: 'weather_advice_time', name: 'Zeit für Wetterhinweise', def: '08:00' },
|
|
130
|
+
{ id: 'weekend_summary_time', name: 'Zeit für Wochenend-Zusammenfassung', def: '18:00' },
|
|
131
|
+
|
|
132
|
+
// NEU: Zeitplan für "Vorhersage für morgen"
|
|
133
|
+
{ id: 'tomorrow_forecast_time', name: 'Zeit für morgige Vorhersage', def: '19:00' }, // NEU
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
for (const t of weatherSchedule) {
|
|
137
|
+
await adapter.setObjectNotExistsAsync(`ai.weather.schedule.${t.id}`, {
|
|
138
|
+
type: 'state',
|
|
139
|
+
common: {
|
|
140
|
+
name: t.name,
|
|
141
|
+
type: 'string',
|
|
142
|
+
role: 'text',
|
|
143
|
+
read: true,
|
|
144
|
+
write: true,
|
|
145
|
+
def: t.def,
|
|
146
|
+
persist: true,
|
|
147
|
+
},
|
|
148
|
+
native: {},
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ------------------------------------------------------
|
|
153
|
+
// NEU: Unterordner Wetter-Outputs
|
|
154
|
+
// ------------------------------------------------------
|
|
155
|
+
await adapter.setObjectNotExistsAsync('ai.weather.outputs', {
|
|
156
|
+
type: 'channel',
|
|
157
|
+
common: {
|
|
158
|
+
name: 'KI-Ausgaben (Wetter-Texte)',
|
|
159
|
+
desc: 'Textausgaben der Wetter-KI (Hinweise, Tipps, Zusammenfassungen)',
|
|
160
|
+
},
|
|
161
|
+
native: {},
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// NEU / GEÄNDERT:
|
|
165
|
+
// Alle bisherigen Ausgaben + neue Vorhersage + last_message unter ai.weather.outputs.*
|
|
166
|
+
const weatherOutputs = [
|
|
167
|
+
{ id: 'daily_summary', name: 'Tägliche Zusammenfassung' },
|
|
168
|
+
{ id: 'pool_tips', name: 'Pool-Tipps' },
|
|
169
|
+
{ id: 'weather_advice', name: 'Wetterhinweise' },
|
|
170
|
+
{ id: 'weekend_summary', name: 'Wochenende-Zusammenfassung' },
|
|
171
|
+
|
|
172
|
+
// NEU: Ausgabefeld für die Vorhersage für morgen
|
|
173
|
+
{ id: 'tomorrow_forecast', name: 'Vorhersage für morgen' }, // NEU
|
|
174
|
+
|
|
175
|
+
// GEÄNDERT: last_message gehört aktuell zur Wetter-KI
|
|
176
|
+
{ id: 'last_message', name: 'Letzte Wetter-KI-Meldung' }, // GEÄNDERT: von ai.outputs → ai.weather.outputs
|
|
177
|
+
];
|
|
178
|
+
|
|
179
|
+
for (const o of weatherOutputs) {
|
|
180
|
+
await adapter.setObjectNotExistsAsync(`ai.weather.outputs.${o.id}`, {
|
|
181
|
+
type: 'state',
|
|
182
|
+
common: {
|
|
183
|
+
name: o.name,
|
|
184
|
+
type: 'string',
|
|
185
|
+
role: 'text',
|
|
186
|
+
read: true,
|
|
187
|
+
write: false,
|
|
188
|
+
persist: false,
|
|
189
|
+
},
|
|
190
|
+
native: {},
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
adapter.log.debug('[aiStates] Initialisierung abgeschlossen');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
module.exports = {
|
|
198
|
+
createAiStates,
|
|
199
|
+
};
|
|
@@ -277,7 +277,16 @@ async function createControlStates(adapter) {
|
|
|
277
277
|
} catch (err) {
|
|
278
278
|
adapter.log.warn(`[controlStates] persist-Flag für control.circulation.mode nicht gesetzt: ${err.message}`);
|
|
279
279
|
}
|
|
280
|
-
|
|
280
|
+
|
|
281
|
+
// FIX: Default nur setzen, wenn noch kein Wert existiert (Überinstall-Schutz)
|
|
282
|
+
const existingCirculationMode = await adapter.getStateAsync('control.circulation.mode');
|
|
283
|
+
if (
|
|
284
|
+
existingCirculationMode === null ||
|
|
285
|
+
existingCirculationMode.val === null ||
|
|
286
|
+
existingCirculationMode.val === undefined
|
|
287
|
+
) {
|
|
288
|
+
await adapter.setStateAsync('control.circulation.mode', { val: 'notify', ack: true });
|
|
289
|
+
}
|
|
281
290
|
|
|
282
291
|
// Prüfzeitpunkt (mit Persist-Schutz)
|
|
283
292
|
await adapter.setObjectNotExistsAsync('control.circulation.check_time', {
|
package/main.js
CHANGED
|
@@ -21,6 +21,8 @@ const solarHelper = require('./lib/helpers/solarHelper');
|
|
|
21
21
|
const frostHelper = require('./lib/helpers/frostHelper');
|
|
22
22
|
const statusHelper = require('./lib/helpers/statusHelper');
|
|
23
23
|
const photovoltaicHelper = require('./lib/helpers/photovoltaicHelper');
|
|
24
|
+
const aiHelper = require('./lib/helpers/aiHelper');
|
|
25
|
+
const aiForecastHelper = require('./lib/helpers/aiForecastHelper');
|
|
24
26
|
const controlHelper = require('./lib/helpers/controlHelper');
|
|
25
27
|
const controlHelper2 = require('./lib/helpers/controlHelper2');
|
|
26
28
|
const debugLogHelper = require('./lib/helpers/debugLogHelper');
|
|
@@ -44,6 +46,7 @@ const { createStatusStates } = require('./lib/stateDefinitions/statusStates');
|
|
|
44
46
|
const { createControlStates } = require('./lib/stateDefinitions/controlStates');
|
|
45
47
|
const { createDebugLogStates } = require('./lib/stateDefinitions/debugLogStates');
|
|
46
48
|
const { createInfoStates } = require('./lib/stateDefinitions/infoStates');
|
|
49
|
+
const { createAiStates } = require('./lib/stateDefinitions/aiStates'); // NEU: KI-States
|
|
47
50
|
|
|
48
51
|
class Poolcontrol extends utils.Adapter {
|
|
49
52
|
constructor(options) {
|
|
@@ -110,6 +113,9 @@ class Poolcontrol extends utils.Adapter {
|
|
|
110
113
|
// --- Info States ---
|
|
111
114
|
await createInfoStates(this);
|
|
112
115
|
|
|
116
|
+
// --- AI States ---
|
|
117
|
+
await createAiStates(this); // NEU: KI-States anlegen
|
|
118
|
+
|
|
113
119
|
// --- Migration Helper zuletzt starten ---
|
|
114
120
|
await migrationHelper.init(this);
|
|
115
121
|
|
|
@@ -128,6 +134,8 @@ class Poolcontrol extends utils.Adapter {
|
|
|
128
134
|
consumptionHelper.init(this);
|
|
129
135
|
solarHelper.init(this);
|
|
130
136
|
photovoltaicHelper.init(this);
|
|
137
|
+
aiHelper.init(this);
|
|
138
|
+
aiForecastHelper.init(this);
|
|
131
139
|
frostHelper.init(this);
|
|
132
140
|
statusHelper.init(this);
|
|
133
141
|
infoHelper.init(this);
|
|
@@ -187,6 +195,12 @@ class Poolcontrol extends utils.Adapter {
|
|
|
187
195
|
if (speechTextHelper.cleanup) {
|
|
188
196
|
speechTextHelper.cleanup();
|
|
189
197
|
}
|
|
198
|
+
if (aiHelper.cleanup) {
|
|
199
|
+
aiHelper.cleanup();
|
|
200
|
+
}
|
|
201
|
+
if (aiForecastHelper.cleanup) {
|
|
202
|
+
aiForecastHelper.cleanup();
|
|
203
|
+
}
|
|
190
204
|
if (infoHelper.cleanup) {
|
|
191
205
|
infoHelper.cleanup();
|
|
192
206
|
}
|
|
@@ -258,6 +272,17 @@ class Poolcontrol extends utils.Adapter {
|
|
|
258
272
|
} catch (e) {
|
|
259
273
|
this.log.warn(`[photovoltaicHelper] Fehler in handleStateChange: ${e.message}`);
|
|
260
274
|
}
|
|
275
|
+
// --- AI-Helper ---
|
|
276
|
+
try {
|
|
277
|
+
aiHelper.handleStateChange(id, state);
|
|
278
|
+
} catch (e) {
|
|
279
|
+
this.log.warn(`[main] Fehler in aiHelper.handleStateChange: ${e.message}`);
|
|
280
|
+
}
|
|
281
|
+
try {
|
|
282
|
+
aiForecastHelper.handleStateChange(id, state);
|
|
283
|
+
} catch (e) {
|
|
284
|
+
this.log.warn(`[main] Fehler in aiForecastHelper.handleStateChange: ${e.message}`);
|
|
285
|
+
}
|
|
261
286
|
try {
|
|
262
287
|
statusHelper.handleStateChange(id, state);
|
|
263
288
|
} catch (e) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.poolcontrol",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"@iobroker/adapter-dev": "^1.5.0",
|
|
29
29
|
"@iobroker/eslint-config": "^2.2.0",
|
|
30
30
|
"@iobroker/testing": "^5.1.1",
|
|
31
|
+
"baseline-browser-mapping": "^2.8.32",
|
|
31
32
|
"eslint": "^9.36.0",
|
|
32
33
|
"prettier": "^3.6.2",
|
|
33
34
|
"proxyquire": "^2.1.3",
|