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.
@@ -56,7 +56,7 @@ const infoHelper = {
56
56
  let greeting = '';
57
57
 
58
58
  // Weihnachten: 20.12. – 27.12.
59
- if ((month === 12 && day >= 20) || (month === 12 && day <= 27)) {
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
- await adapter.setStateAsync('control.circulation.mode', { val: 'notify', ack: true });
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.7.2",
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",