iobroker.poolcontrol 0.7.1 → 0.7.3

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.
@@ -0,0 +1,159 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * infoHelper.js
5
+ * ----------------------------------------------------------
6
+ * Verwaltet die Info-States:
7
+ * - info.developer_greeting
8
+ * - info.adapter_version
9
+ * ----------------------------------------------------------
10
+ */
11
+
12
+ const infoHelper = {
13
+ adapter: null,
14
+ dailyTimer: null,
15
+
16
+ /**
17
+ * Initialisierung des Info-Helpers
18
+ *
19
+ * @param {import('iobroker').Adapter} adapter - Die ioBroker-Adapterinstanz
20
+ */
21
+ init(adapter) {
22
+ this.adapter = adapter;
23
+ this.adapter.log.debug('[infoHelper] Initialisiert');
24
+
25
+ // Adapterversion setzen
26
+ this._updateAdapterVersion();
27
+
28
+ // Entwicklergruß setzen
29
+ this._updateDeveloperGreeting();
30
+
31
+ // NEU: täglichen Timer starten
32
+ this._startDailyTimer();
33
+ },
34
+
35
+ /**
36
+ * Liest die Version aus io-package.json und schreibt sie in info.adapter_version
37
+ */
38
+ _updateAdapterVersion() {
39
+ try {
40
+ const ioPkg = require('../../io-package.json');
41
+ const version = ioPkg.common.version || '';
42
+
43
+ this.adapter.setState('info.adapter_version', version, true);
44
+ } catch (err) {
45
+ this.adapter.log.error(`[infoHelper] Fehler beim Lesen der Adapterversion: ${err}`);
46
+ }
47
+ },
48
+
49
+ /**
50
+ * Setzt saisonale Grüße in info.developer_greeting
51
+ */
52
+ _updateDeveloperGreeting() {
53
+ const now = new Date();
54
+ const month = now.getMonth() + 1;
55
+ const day = now.getDate();
56
+ let greeting = '';
57
+
58
+ // Weihnachten: 20.12. – 27.12.
59
+ if (month === 12 && day >= 20 && day <= 27) {
60
+ greeting = '🎄 PoolControl wünscht frohe Weihnachten! 🎄';
61
+ }
62
+
63
+ // Jahreswechsel
64
+ // 31.12.: Guten Rutsch
65
+ if (month === 12 && day === 31) {
66
+ greeting = '🎆 PoolControl wünscht einen guten Rutsch ins neue Jahr! 🎆';
67
+ }
68
+
69
+ // 01.01.: Frohes neues Jahr
70
+ if (month === 1 && day === 1) {
71
+ greeting = '🎆 Frohes neues Jahr wünscht PoolControl! 🎆';
72
+ }
73
+
74
+ // Dynamische Berechnung von Ostersonntag (Computus)
75
+ const easter = this._computeEaster(now.getFullYear());
76
+ const easterMonth = easter.getMonth() + 1;
77
+ const easterDay = easter.getDate();
78
+
79
+ const easterMonday = new Date(easter);
80
+ easterMonday.setDate(easterDay + 1);
81
+
82
+ // Ostersonntag
83
+ if (month === easterMonth && day === easterDay) {
84
+ greeting = '🐣 Frohe Ostern wünscht PoolControl! 🐣';
85
+ }
86
+
87
+ // Ostermontag
88
+ if (month === easterMonday.getMonth() + 1 && day === easterMonday.getDate()) {
89
+ greeting = '🐣 PoolControl wünscht einen schönen Ostermontag! 🐣';
90
+ }
91
+
92
+ this.adapter.setState('info.developer_greeting', greeting, true);
93
+ },
94
+
95
+ /**
96
+ * Berechnet das Datum des Ostersonntags für ein bestimmtes Jahr.
97
+ * Algorithmus: Anonymous Gregorian Computus
98
+ *
99
+ * @param {number} year - Das Jahr, für das Ostern berechnet werden soll
100
+ * @returns {Date} Datum des Ostersonntags
101
+ */
102
+ _computeEaster(year) {
103
+ const a = year % 19;
104
+ const b = Math.floor(year / 100);
105
+ const c = year % 100;
106
+ const d = Math.floor(b / 4);
107
+ const e = b % 4;
108
+ const f = Math.floor((b + 8) / 25);
109
+ const g = Math.floor((b - f + 1) / 3);
110
+ const h = (19 * a + b - d - g + 15) % 30;
111
+ const i = Math.floor(c / 4);
112
+ const k = c % 4;
113
+ const l = (32 + 2 * e + 2 * i - h - k) % 7;
114
+ const m = Math.floor((a + 11 * h + 22 * l) / 451);
115
+ const month = Math.floor((h + l - 7 * m + 114) / 31);
116
+ const day = ((h + l - 7 * m + 114) % 31) + 1;
117
+ return new Date(year, month - 1, day);
118
+ },
119
+
120
+ /**
121
+ * Startet den täglichen Update-Intervall (Update 00:01 Uhr)
122
+ */
123
+ _startDailyTimer() {
124
+ // nächsten Trigger für morgen 00:01 berechnen
125
+ const now = new Date();
126
+ const next = new Date(now);
127
+
128
+ next.setDate(now.getDate() + 1);
129
+ next.setHours(0, 1, 0, 0);
130
+
131
+ const delay = next.getTime() - now.getTime();
132
+
133
+ // einmaliger Timer bis 00:01
134
+ this.dailyTimer = setTimeout(() => {
135
+ this._updateDeveloperGreeting();
136
+
137
+ // danach täglich um 24h
138
+ this.dailyTimer = setInterval(
139
+ () => {
140
+ this._updateDeveloperGreeting();
141
+ },
142
+ 24 * 60 * 60 * 1000,
143
+ );
144
+ }, delay);
145
+ },
146
+
147
+ /**
148
+ * Stoppt Timer (wichtig beim Adapter-Unload)
149
+ */
150
+ cleanup() {
151
+ if (this.dailyTimer) {
152
+ clearTimeout(this.dailyTimer);
153
+ clearInterval(this.dailyTimer);
154
+ this.dailyTimer = null;
155
+ }
156
+ },
157
+ };
158
+
159
+ module.exports = infoHelper;
@@ -0,0 +1,135 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * aiStates.js
5
+ * ----------------------------------------------------------
6
+ * Definiert alle States für den KI-Bereich des PoolControl-Adapters.
7
+ * Struktur:
8
+ * ai.switches.*
9
+ * ai.schedule.*
10
+ * ai.outputs.*
11
+ * ----------------------------------------------------------
12
+ *
13
+ * @param {import('iobroker').Adapter} adapter - ioBroker Adapterinstanz
14
+ */
15
+
16
+ /**
17
+ * Erstellt alle KI-bezogenen States (ai.*)
18
+ *
19
+ * @param {import('iobroker').Adapter} adapter - ioBroker Adapterinstanz
20
+ */
21
+ async function createAiStates(adapter) {
22
+ adapter.log.debug('[aiStates] Initialisierung gestartet');
23
+
24
+ // Hauptordner
25
+ await adapter.setObjectNotExistsAsync('ai', {
26
+ type: 'channel',
27
+ common: { name: 'KI / AI-Funktionen' },
28
+ native: {},
29
+ });
30
+
31
+ // ------------------------------------------------------
32
+ // Unterordner: switches
33
+ // ------------------------------------------------------
34
+ await adapter.setObjectNotExistsAsync('ai.switches', {
35
+ type: 'channel',
36
+ common: { name: 'Schalter (KI-Steuerung)' },
37
+ native: {},
38
+ });
39
+
40
+ const switches = [
41
+ { id: 'enabled', name: 'KI aktivieren', def: false },
42
+ { id: 'allow_speech', name: 'Sprachausgabe durch KI erlauben', def: false },
43
+ { id: 'daily_summary_enabled', name: 'Tägliche Zusammenfassung aktiv', def: false },
44
+ { id: 'daily_pool_tips_enabled', name: 'Tägliche Pool-Tipps aktiv', def: false },
45
+ { id: 'weather_advice_enabled', name: 'Wetterhinweise aktiv', def: false },
46
+ { id: 'weekend_summary_enabled', name: 'Wochenende-Zusammenfassung aktiv', def: false },
47
+ { id: 'debug_mode', name: 'KI-Debugmodus', def: false },
48
+ ];
49
+
50
+ for (const s of switches) {
51
+ await adapter.setObjectNotExistsAsync(`ai.switches.${s.id}`, {
52
+ type: 'state',
53
+ common: {
54
+ name: s.name,
55
+ type: 'boolean',
56
+ role: 'switch',
57
+ read: true,
58
+ write: true,
59
+ def: s.def,
60
+ persist: true,
61
+ },
62
+ native: {},
63
+ });
64
+ }
65
+
66
+ // ------------------------------------------------------
67
+ // Unterordner: schedule
68
+ // ------------------------------------------------------
69
+ await adapter.setObjectNotExistsAsync('ai.schedule', {
70
+ type: 'channel',
71
+ common: { name: 'Zeitpläne (KI-Ausgaben)' },
72
+ native: {},
73
+ });
74
+
75
+ const schedule = [
76
+ { id: 'daily_summary_time', name: 'Zeit für tägliche Zusammenfassung', def: '09:00' },
77
+ { id: 'daily_pool_tips_time', name: 'Zeit für tägliche Pool-Tipps', def: '10:00' },
78
+ { id: 'weather_advice_time', name: 'Zeit für Wetterhinweise', def: '08:00' },
79
+ { id: 'weekend_summary_time', name: 'Zeit für Wochenend-Zusammenfassung', def: '18:00' },
80
+ ];
81
+
82
+ for (const t of schedule) {
83
+ await adapter.setObjectNotExistsAsync(`ai.schedule.${t.id}`, {
84
+ type: 'state',
85
+ common: {
86
+ name: t.name,
87
+ type: 'string',
88
+ role: 'text',
89
+ read: true,
90
+ write: true,
91
+ def: t.def,
92
+ persist: true,
93
+ },
94
+ native: {},
95
+ });
96
+ }
97
+
98
+ // ------------------------------------------------------
99
+ // Unterordner: outputs
100
+ // ------------------------------------------------------
101
+ await adapter.setObjectNotExistsAsync('ai.outputs', {
102
+ type: 'channel',
103
+ common: { name: 'KI-Ausgaben (Texte)' },
104
+ native: {},
105
+ });
106
+
107
+ const outputs = [
108
+ { id: 'daily_summary', name: 'Tägliche Zusammenfassung' },
109
+ { id: 'pool_tips', name: 'Pool-Tipps' },
110
+ { id: 'weather_advice', name: 'Wetterhinweise' },
111
+ { id: 'weekend_summary', name: 'Wochenende-Zusammenfassung' },
112
+ { id: 'last_message', name: 'Letzte KI-Meldung' },
113
+ ];
114
+
115
+ for (const o of outputs) {
116
+ await adapter.setObjectNotExistsAsync(`ai.outputs.${o.id}`, {
117
+ type: 'state',
118
+ common: {
119
+ name: o.name,
120
+ type: 'string',
121
+ role: 'text',
122
+ read: true,
123
+ write: false,
124
+ persist: false,
125
+ },
126
+ native: {},
127
+ });
128
+ }
129
+
130
+ adapter.log.debug('[aiStates] Initialisierung abgeschlossen');
131
+ }
132
+
133
+ module.exports = {
134
+ createAiStates,
135
+ };
@@ -0,0 +1,63 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * infoStates.js
5
+ * ----------------------------------------------------------
6
+ * Legt allgemeine Informations-States an:
7
+ * - info.developer_greeting
8
+ * - info.adapter_version
9
+ *
10
+ * Struktur:
11
+ * info.*
12
+ * ----------------------------------------------------------
13
+ */
14
+
15
+ /**
16
+ * Erstellt alle States im Bereich info.
17
+ *
18
+ * @param {import("iobroker").Adapter} adapter - ioBroker Adapterinstanz
19
+ */
20
+ async function createInfoStates(adapter) {
21
+ // Hauptordner: info
22
+ await adapter.setObjectNotExistsAsync('info', {
23
+ type: 'channel',
24
+ common: {
25
+ name: 'Informationen (PoolControl Systeminfos)',
26
+ },
27
+ native: {},
28
+ });
29
+
30
+ // Entwickler-Grußtext
31
+ await adapter.setObjectNotExistsAsync('info.developer_greeting', {
32
+ type: 'state',
33
+ common: {
34
+ name: 'Entwickler-Grußtext',
35
+ desc: 'Saisonale Grüße und Informationen vom PoolControl-Entwickler',
36
+ type: 'string',
37
+ role: 'text',
38
+ read: true,
39
+ write: false,
40
+ def: '',
41
+ },
42
+ native: {},
43
+ });
44
+
45
+ // Adapterversion
46
+ await adapter.setObjectNotExistsAsync('info.adapter_version', {
47
+ type: 'state',
48
+ common: {
49
+ name: 'Installierte Adapterversion',
50
+ desc: 'Aktuell installierte Version von PoolControl',
51
+ type: 'string',
52
+ role: 'text',
53
+ read: true,
54
+ write: false,
55
+ def: '',
56
+ },
57
+ native: {},
58
+ });
59
+ }
60
+
61
+ module.exports = {
62
+ createInfoStates,
63
+ };
package/main.js CHANGED
@@ -21,11 +21,13 @@ 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');
24
25
  const controlHelper = require('./lib/helpers/controlHelper');
25
26
  const controlHelper2 = require('./lib/helpers/controlHelper2');
26
27
  const debugLogHelper = require('./lib/helpers/debugLogHelper');
27
28
  const speechTextHelper = require('./lib/helpers/speechTextHelper');
28
29
  const migrationHelper = require('./lib/helpers/migrationHelper');
30
+ const infoHelper = require('./lib/helpers/infoHelper');
29
31
  const { createTemperatureStates } = require('./lib/stateDefinitions/temperatureStates');
30
32
  const { createPumpStates } = require('./lib/stateDefinitions/pumpStates');
31
33
  const { createPumpStates2 } = require('./lib/stateDefinitions/pumpStates2');
@@ -42,6 +44,8 @@ const { createConsumptionStates } = require('./lib/stateDefinitions/consumptionS
42
44
  const { createStatusStates } = require('./lib/stateDefinitions/statusStates');
43
45
  const { createControlStates } = require('./lib/stateDefinitions/controlStates');
44
46
  const { createDebugLogStates } = require('./lib/stateDefinitions/debugLogStates');
47
+ const { createInfoStates } = require('./lib/stateDefinitions/infoStates');
48
+ const { createAiStates } = require('./lib/stateDefinitions/aiStates'); // NEU: KI-States
45
49
 
46
50
  class Poolcontrol extends utils.Adapter {
47
51
  constructor(options) {
@@ -105,6 +109,12 @@ class Poolcontrol extends utils.Adapter {
105
109
  // --- DebugLog States ---
106
110
  await createDebugLogStates(this);
107
111
 
112
+ // --- Info States ---
113
+ await createInfoStates(this);
114
+
115
+ // --- AI States ---
116
+ await createAiStates(this); // NEU: KI-States anlegen
117
+
108
118
  // --- Migration Helper zuletzt starten ---
109
119
  await migrationHelper.init(this);
110
120
 
@@ -123,8 +133,10 @@ class Poolcontrol extends utils.Adapter {
123
133
  consumptionHelper.init(this);
124
134
  solarHelper.init(this);
125
135
  photovoltaicHelper.init(this);
136
+ aiHelper.init(this);
126
137
  frostHelper.init(this);
127
138
  statusHelper.init(this);
139
+ infoHelper.init(this);
128
140
  controlHelper.init(this);
129
141
  controlHelper2.init(this);
130
142
  debugLogHelper.init(this);
@@ -180,6 +192,12 @@ class Poolcontrol extends utils.Adapter {
180
192
  }
181
193
  if (speechTextHelper.cleanup) {
182
194
  speechTextHelper.cleanup();
195
+ }
196
+ if (aiHelper.cleanup) {
197
+ aiHelper.cleanup();
198
+ }
199
+ if (infoHelper.cleanup) {
200
+ infoHelper.cleanup();
183
201
  }
184
202
  } catch (e) {
185
203
  this.log.warn(`[onUnload] Fehler beim Cleanup: ${e.message}`);
@@ -248,6 +266,12 @@ class Poolcontrol extends utils.Adapter {
248
266
  photovoltaicHelper.handleStateChange(id, state);
249
267
  } catch (e) {
250
268
  this.log.warn(`[photovoltaicHelper] Fehler in handleStateChange: ${e.message}`);
269
+ }
270
+ // --- AI-Helper ---
271
+ try {
272
+ aiHelper.handleStateChange(id, state);
273
+ } catch (e) {
274
+ this.log.warn(`[main] Fehler in aiHelper.handleStateChange: ${e.message}`);
251
275
  }
252
276
  try {
253
277
  statusHelper.handleStateChange(id, state);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.poolcontrol",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
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",