iobroker.poolcontrol 0.0.7

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.
Files changed (35) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +129 -0
  3. package/admin/i18n/de/translations.json +5 -0
  4. package/admin/i18n/en/translations.json +5 -0
  5. package/admin/i18n/es/translations.json +5 -0
  6. package/admin/i18n/fr/translations.json +5 -0
  7. package/admin/i18n/it/translations.json +5 -0
  8. package/admin/i18n/nl/translations.json +5 -0
  9. package/admin/i18n/pl/translations.json +5 -0
  10. package/admin/i18n/pt/translations.json +5 -0
  11. package/admin/i18n/ru/translations.json +5 -0
  12. package/admin/i18n/uk/translations.json +5 -0
  13. package/admin/i18n/zh-cn/translations.json +5 -0
  14. package/admin/jsonConfig.json +901 -0
  15. package/admin/poolcontrol.png +0 -0
  16. package/io-package.json +176 -0
  17. package/lib/adapter-config.d.ts +19 -0
  18. package/lib/helpers/consumptionHelper.js +185 -0
  19. package/lib/helpers/frostHelper.js +94 -0
  20. package/lib/helpers/pumpHelper.js +224 -0
  21. package/lib/helpers/runtimeHelper.js +159 -0
  22. package/lib/helpers/solarHelper.js +138 -0
  23. package/lib/helpers/speechHelper.js +108 -0
  24. package/lib/helpers/temperatureHelper.js +227 -0
  25. package/lib/helpers/timeHelper.js +88 -0
  26. package/lib/stateDefinitions/consumptionStates.js +82 -0
  27. package/lib/stateDefinitions/generalStates.js +68 -0
  28. package/lib/stateDefinitions/pumpStates.js +184 -0
  29. package/lib/stateDefinitions/runtimeStates.js +113 -0
  30. package/lib/stateDefinitions/solarStates.js +150 -0
  31. package/lib/stateDefinitions/speechStates.js +104 -0
  32. package/lib/stateDefinitions/temperatureStates.js +182 -0
  33. package/lib/stateDefinitions/timeStates.js +102 -0
  34. package/main.js +145 -0
  35. package/package.json +60 -0
@@ -0,0 +1,227 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * temperatureHelper
5
+ * - Abonniert konfigurierte Temperatursensoren (Foreign States)
6
+ * - Schreibt aktuelle Werte:
7
+ * - temperature.<sensor>.current
8
+ * - Berechnet Differenzen:
9
+ * - temperature.delta.collector_outside = collector - outside
10
+ * - temperature.delta.surface_ground = surface - ground
11
+ * - temperature.delta.flow_return = flow - return
12
+ * - Tages-Min/Max je Sensor
13
+ * - Änderung pro Stunde (delta_per_hour)
14
+ */
15
+
16
+ const temperatureHelper = {
17
+ adapter: null,
18
+ sensors: {}, // { collector: 'id', outside: 'id', surface: 'id', ground: 'id', flow: 'id', return: 'id' }
19
+ values: {}, // aktuelle Werte { collector: number, outside: number, ... }
20
+ minMax: {}, // { collector: { min, max }, ... }
21
+ history: {}, // { sensorKey: [{ ts, val }, ...] }
22
+ resetTimer: null,
23
+
24
+ init(adapter) {
25
+ this.adapter = adapter;
26
+ this.sensors = this._collectActiveSensors(adapter);
27
+
28
+ // Foreign-States abonnieren
29
+ for (const id of Object.values(this.sensors)) {
30
+ adapter.subscribeForeignStates(id);
31
+ }
32
+
33
+ // Reset um Mitternacht
34
+ this._scheduleDailyReset();
35
+
36
+ adapter.log.info(
37
+ `[temperatureHelper] Aktiv: ${
38
+ Object.keys(this.sensors).length
39
+ ? Object.entries(this.sensors)
40
+ .map(([k, v]) => `${k}=${v}`)
41
+ .join(', ')
42
+ : 'keine Sensoren konfiguriert'
43
+ }`,
44
+ );
45
+ },
46
+
47
+ _collectActiveSensors(adapter) {
48
+ const c = adapter.config || {};
49
+ const map = {};
50
+ if (c.collector_temp_active && c.collector_temp_sensor) {
51
+ map.collector = c.collector_temp_sensor;
52
+ }
53
+ if (c.outside_temp_active && c.outside_temp_sensor) {
54
+ map.outside = c.outside_temp_sensor;
55
+ }
56
+ if (c.surface_temp_active && c.surface_temp_sensor) {
57
+ map.surface = c.surface_temp_sensor;
58
+ }
59
+ if (c.ground_temp_active && c.ground_temp_sensor) {
60
+ map.ground = c.ground_temp_sensor;
61
+ }
62
+ if (c.flow_temp_active && c.flow_temp_sensor) {
63
+ map.flow = c.flow_temp_sensor;
64
+ }
65
+ if (c.return_temp_active && c.return_temp_sensor) {
66
+ map.return = c.return_temp_sensor;
67
+ }
68
+ return map;
69
+ },
70
+
71
+ async handleStateChange(id, state) {
72
+ if (!state || state.val === null || state.val === undefined) {
73
+ return;
74
+ }
75
+ const key = Object.keys(this.sensors).find(k => this.sensors[k] === id);
76
+ if (!key) {
77
+ return;
78
+ }
79
+
80
+ const num = Number(state.val);
81
+ if (!Number.isFinite(num)) {
82
+ return;
83
+ }
84
+
85
+ this.values[key] = num;
86
+
87
+ // Aktuellen Wert setzen
88
+ await this._setCurrentValue(key, num);
89
+
90
+ // Deltas berechnen
91
+ await this._maybeWriteDelta('temperature.delta.collector_outside', this.values.collector, this.values.outside);
92
+ await this._maybeWriteDelta('temperature.delta.surface_ground', this.values.surface, this.values.ground);
93
+ await this._maybeWriteDelta('temperature.delta.flow_return', this.values.flow, this.values.return);
94
+
95
+ // Min/Max aktualisieren
96
+ await this._updateMinMax(key, num);
97
+
98
+ // Verlauf speichern und Delta pro Stunde berechnen
99
+ await this._updateHistoryAndDelta(key, num);
100
+ },
101
+
102
+ async _setCurrentValue(key, value) {
103
+ try {
104
+ await this.adapter.setStateAsync(`temperature.${key}.current`, {
105
+ val: value,
106
+ ack: true,
107
+ });
108
+ } catch (err) {
109
+ this.adapter.log.warn(`[temperatureHelper] setState current ${key} fehlgeschlagen: ${err.message}`);
110
+ }
111
+ },
112
+
113
+ async _maybeWriteDelta(stateId, a, b) {
114
+ if (a === undefined || b === undefined) {
115
+ return;
116
+ }
117
+ const delta = Number((a - b).toFixed(2));
118
+ try {
119
+ await this.adapter.setStateAsync(stateId, { val: delta, ack: true });
120
+ } catch (err) {
121
+ this.adapter.log.warn(`[temperatureHelper] setState ${stateId} fehlgeschlagen: ${err.message}`);
122
+ }
123
+ },
124
+
125
+ async _updateMinMax(key, value) {
126
+ if (!this.minMax[key]) {
127
+ this.minMax[key] = { min: value, max: value };
128
+ await this.adapter.setStateAsync(`temperature.${key}.min_today`, {
129
+ val: value,
130
+ ack: true,
131
+ });
132
+ await this.adapter.setStateAsync(`temperature.${key}.max_today`, {
133
+ val: value,
134
+ ack: true,
135
+ });
136
+ return;
137
+ }
138
+
139
+ if (value < this.minMax[key].min) {
140
+ this.minMax[key].min = value;
141
+ await this.adapter.setStateAsync(`temperature.${key}.min_today`, {
142
+ val: value,
143
+ ack: true,
144
+ });
145
+ }
146
+ if (value > this.minMax[key].max) {
147
+ this.minMax[key].max = value;
148
+ await this.adapter.setStateAsync(`temperature.${key}.max_today`, {
149
+ val: value,
150
+ ack: true,
151
+ });
152
+ }
153
+ },
154
+
155
+ async _updateHistoryAndDelta(key, value) {
156
+ const now = Date.now();
157
+ if (!this.history[key]) {
158
+ this.history[key] = [];
159
+ }
160
+
161
+ // Wert speichern
162
+ this.history[key].push({ ts: now, val: value });
163
+
164
+ // Nur letzte 2 Stunden behalten
165
+ this.history[key] = this.history[key].filter(p => now - p.ts <= 2 * 3600 * 1000);
166
+
167
+ // Referenzwert von vor ~1 Stunde suchen
168
+ const oneHourAgo = now - 3600 * 1000;
169
+ const past = this.history[key].find(p => p.ts <= oneHourAgo);
170
+ if (past) {
171
+ const deltaPerHour = Number((value - past.val).toFixed(2));
172
+ try {
173
+ await this.adapter.setStateAsync(`temperature.${key}.delta_per_hour`, {
174
+ val: deltaPerHour,
175
+ ack: true,
176
+ });
177
+ } catch (err) {
178
+ this.adapter.log.warn(
179
+ `[temperatureHelper] setState delta_per_hour ${key} fehlgeschlagen: ${err.message}`,
180
+ );
181
+ }
182
+ }
183
+ },
184
+
185
+ _scheduleDailyReset() {
186
+ // Timer berechnen: Millisekunden bis Mitternacht
187
+ const now = new Date();
188
+ const nextMidnight = new Date(now);
189
+ nextMidnight.setHours(24, 0, 0, 0);
190
+ const msUntilMidnight = nextMidnight.getTime() - now.getTime();
191
+
192
+ this.resetTimer = setTimeout(() => {
193
+ this._resetMinMax();
194
+ this._scheduleDailyReset(); // neu für nächsten Tag
195
+ }, msUntilMidnight);
196
+ },
197
+
198
+ async _resetMinMax() {
199
+ this.adapter.log.info('[temperatureHelper] Setze Tages-Min/Max zurück');
200
+ for (const key of Object.keys(this.sensors)) {
201
+ // Bugfix: statt leeres Objekt → löschen, damit Neu-Init greift
202
+ delete this.minMax[key];
203
+
204
+ await this.adapter.setStateAsync(`temperature.${key}.min_today`, {
205
+ val: null,
206
+ ack: true,
207
+ });
208
+ await this.adapter.setStateAsync(`temperature.${key}.max_today`, {
209
+ val: null,
210
+ ack: true,
211
+ });
212
+ await this.adapter.setStateAsync(`temperature.${key}.delta_per_hour`, {
213
+ val: null,
214
+ ack: true,
215
+ });
216
+ }
217
+ },
218
+
219
+ cleanup() {
220
+ if (this.resetTimer) {
221
+ clearTimeout(this.resetTimer);
222
+ this.resetTimer = null;
223
+ }
224
+ },
225
+ };
226
+
227
+ module.exports = temperatureHelper;
@@ -0,0 +1,88 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * timeHelper
5
+ * - Überwacht Zeitfenster (time1, time2, time3)
6
+ * - Schaltet Pumpe, wenn Modus "time" aktiv ist
7
+ * - Schaltet über die reale Steckdosen-ID aus der Config
8
+ */
9
+
10
+ const timeHelper = {
11
+ adapter: null,
12
+ checkTimer: null,
13
+
14
+ init(adapter) {
15
+ this.adapter = adapter;
16
+
17
+ // Minütlicher Check
18
+ this._scheduleCheck();
19
+
20
+ this.adapter.log.info('[timeHelper] initialisiert (Prüfung alle 60s)');
21
+ },
22
+
23
+ _scheduleCheck() {
24
+ if (this.checkTimer) {
25
+ clearInterval(this.checkTimer);
26
+ }
27
+ this.checkTimer = setInterval(() => this._checkWindows(), 60 * 1000);
28
+ // Beim Start sofort prüfen
29
+ this._checkWindows();
30
+ },
31
+
32
+ async _checkWindows() {
33
+ try {
34
+ const mode = (await this.adapter.getStateAsync('pump.mode'))?.val;
35
+ if (mode !== 'time') {
36
+ return;
37
+ } // nur aktiv im Zeitmodus
38
+
39
+ const pumpSwitchId = this.adapter.config.pump_switch;
40
+ if (!pumpSwitchId) {
41
+ this.adapter.log.warn('[timeHelper] Keine pump_switch (Fremd-ID) konfiguriert!');
42
+ return;
43
+ }
44
+
45
+ const now = new Date();
46
+ const hhmm = now.toTimeString().slice(0, 5); // "HH:MM"
47
+ const weekday = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'][now.getDay()];
48
+
49
+ let shouldRun = false;
50
+ for (let i = 1; i <= 3; i++) {
51
+ const active = (await this.adapter.getStateAsync(`timecontrol.time${i}_active`))?.val;
52
+ const start = (await this.adapter.getStateAsync(`timecontrol.time${i}_start`))?.val;
53
+ const end = (await this.adapter.getStateAsync(`timecontrol.time${i}_end`))?.val;
54
+ const dayOk = (await this.adapter.getStateAsync(`timecontrol.time${i}_day_${weekday}`))?.val;
55
+
56
+ if (active && dayOk && this._inTimeRange(hhmm, start, end)) {
57
+ shouldRun = true;
58
+ break;
59
+ }
60
+ }
61
+
62
+ // Pumpe über die echte Steckdosen-ID schalten
63
+ await this.adapter.setForeignStateAsync(pumpSwitchId, {
64
+ val: shouldRun,
65
+ ack: false,
66
+ });
67
+ this.adapter.log.debug(`[timeHelper] Pumpe ${shouldRun ? 'EIN' : 'AUS'} (${hhmm})`);
68
+ } catch (err) {
69
+ this.adapter.log.warn(`[timeHelper] Fehler im Check: ${err.message}`);
70
+ }
71
+ },
72
+
73
+ _inTimeRange(now, start, end) {
74
+ if (!start || !end) {
75
+ return false;
76
+ }
77
+ return start <= now && now < end;
78
+ },
79
+
80
+ cleanup() {
81
+ if (this.checkTimer) {
82
+ clearInterval(this.checkTimer);
83
+ this.checkTimer = null;
84
+ }
85
+ },
86
+ };
87
+
88
+ module.exports = timeHelper;
@@ -0,0 +1,82 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Legt alle States für Verbrauch (kWh) und Kosten (€) an.
5
+ * - consumption.total_kwh
6
+ * - consumption.day_kwh, week_kwh, month_kwh, year_kwh
7
+ * - consumption.last_total_kwh (interner Baseline-Wert)
8
+ * - consumption.offset_kwh (interner Zählerausgleich bei Reset/Wechsel)
9
+ * - costs.total_eur
10
+ * - costs.day_eur, week_eur, month_eur, year_eur
11
+ *
12
+ * @param {import("iobroker").Adapter} adapter - ioBroker Adapter-Instanz
13
+ */
14
+ async function createConsumptionStates(adapter) {
15
+ // --- Kanal consumption ---
16
+ await adapter.setObjectNotExistsAsync('consumption', {
17
+ type: 'channel',
18
+ common: { name: 'Stromverbrauch' },
19
+ native: {},
20
+ });
21
+
22
+ const consumptionStates = {
23
+ total_kwh: { name: 'Gesamtverbrauch', unit: 'kWh' },
24
+ day_kwh: { name: 'Verbrauch heute', unit: 'kWh' },
25
+ week_kwh: { name: 'Verbrauch diese Woche', unit: 'kWh' },
26
+ month_kwh: { name: 'Verbrauch dieser Monat', unit: 'kWh' },
27
+ year_kwh: { name: 'Verbrauch dieses Jahr', unit: 'kWh' },
28
+ last_total_kwh: { name: 'Letzter Zählerstand (Baseline)', unit: 'kWh' },
29
+ offset_kwh: { name: 'Offset kWh (interner Zählerausgleich)', unit: 'kWh' },
30
+ };
31
+
32
+ for (const [id, cfg] of Object.entries(consumptionStates)) {
33
+ await adapter.setObjectNotExistsAsync(`consumption.${id}`, {
34
+ type: 'state',
35
+ common: {
36
+ name: cfg.name,
37
+ type: 'number',
38
+ role: 'value.power.consumption',
39
+ unit: cfg.unit,
40
+ read: true,
41
+ write: false,
42
+ },
43
+ native: {},
44
+ });
45
+ await adapter.setStateAsync(`consumption.${id}`, { val: 0, ack: true });
46
+ }
47
+
48
+ // --- Kanal costs ---
49
+ await adapter.setObjectNotExistsAsync('costs', {
50
+ type: 'channel',
51
+ common: { name: 'Kosten' },
52
+ native: {},
53
+ });
54
+
55
+ const costStates = {
56
+ total_eur: { name: 'Gesamtkosten', unit: '€' },
57
+ day_eur: { name: 'Kosten heute', unit: '€' },
58
+ week_eur: { name: 'Kosten diese Woche', unit: '€' },
59
+ month_eur: { name: 'Kosten dieser Monat', unit: '€' },
60
+ year_eur: { name: 'Kosten dieses Jahr', unit: '€' },
61
+ };
62
+
63
+ for (const [id, cfg] of Object.entries(costStates)) {
64
+ await adapter.setObjectNotExistsAsync(`costs.${id}`, {
65
+ type: 'state',
66
+ common: {
67
+ name: cfg.name,
68
+ type: 'number',
69
+ role: 'value.cost',
70
+ unit: cfg.unit,
71
+ read: true,
72
+ write: false,
73
+ },
74
+ native: {},
75
+ });
76
+ await adapter.setStateAsync(`costs.${id}`, { val: 0, ack: true });
77
+ }
78
+ }
79
+
80
+ module.exports = {
81
+ createConsumptionStates,
82
+ };
@@ -0,0 +1,68 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Legt alle States für die allgemeinen Einstellungen an:
5
+ * - pool_name
6
+ * - pool_size
7
+ * - min_circulation_per_day
8
+ *
9
+ * @param {import("iobroker").Adapter} adapter - ioBroker Adapter-Instanz
10
+ */
11
+ async function createGeneralStates(adapter) {
12
+ // Poolname
13
+ await adapter.setObjectNotExistsAsync('general.pool_name', {
14
+ type: 'state',
15
+ common: {
16
+ name: 'Name deines Pools',
17
+ type: 'string',
18
+ role: 'text',
19
+ read: true,
20
+ write: false,
21
+ },
22
+ native: {},
23
+ });
24
+ await adapter.setStateAsync('general.pool_name', {
25
+ val: adapter.config.pool_name,
26
+ ack: true,
27
+ });
28
+
29
+ // Minimale Umwälzung pro Tag
30
+ await adapter.setObjectNotExistsAsync('general.min_circulation_per_day', {
31
+ type: 'state',
32
+ common: {
33
+ name: 'Min. Umwälzung pro Tag',
34
+ type: 'number',
35
+ role: 'value',
36
+ unit: 'x',
37
+ read: true,
38
+ write: false,
39
+ },
40
+ native: {},
41
+ });
42
+ await adapter.setStateAsync('general.min_circulation_per_day', {
43
+ val: adapter.config.min_circulation_per_day,
44
+ ack: true,
45
+ });
46
+
47
+ // Poolgröße (Liter)
48
+ await adapter.setObjectNotExistsAsync('general.pool_size', {
49
+ type: 'state',
50
+ common: {
51
+ name: 'Grösse deines Pools in Liter',
52
+ type: 'number',
53
+ role: 'value',
54
+ unit: 'l',
55
+ read: true,
56
+ write: false,
57
+ },
58
+ native: {},
59
+ });
60
+ await adapter.setStateAsync('general.pool_size', {
61
+ val: adapter.config.pool_size,
62
+ ack: true,
63
+ });
64
+ }
65
+
66
+ module.exports = {
67
+ createGeneralStates,
68
+ };
@@ -0,0 +1,184 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Legt alle States für die Pumpenverwaltung an:
5
+ * - pump.pump_max_watt, pump.pump_power_lph
6
+ * - pump.frost_protection_active, pump.frost_protection_temp
7
+ * - pump.pump_switch (JETZT: boolean Schalter)
8
+ * - pump.mode (auto/manual/off/time)
9
+ * - pump.manual_safety_enabled
10
+ * - pump.status, pump.error
11
+ * - pump.current_power
12
+ *
13
+ * @param {import("iobroker").Adapter} adapter - ioBroker Adapter-Instanz
14
+ */
15
+ async function createPumpStates(adapter) {
16
+ // Max. Pumpenleistung (W)
17
+ await adapter.setObjectNotExistsAsync('pump.pump_max_watt', {
18
+ type: 'state',
19
+ common: {
20
+ name: 'Max. Pumpenleistung',
21
+ type: 'number',
22
+ role: 'value.power',
23
+ unit: 'W',
24
+ read: true,
25
+ write: false,
26
+ },
27
+ native: {},
28
+ });
29
+ await adapter.setStateAsync('pump.pump_max_watt', {
30
+ val: adapter.config.pump_max_watt,
31
+ ack: true,
32
+ });
33
+
34
+ // Pumpenleistung (l/h)
35
+ await adapter.setObjectNotExistsAsync('pump.pump_power_lph', {
36
+ type: 'state',
37
+ common: {
38
+ name: 'Pumpenleistung (l/h)',
39
+ type: 'number',
40
+ role: 'value.flow',
41
+ unit: 'l/h',
42
+ read: true,
43
+ write: false,
44
+ },
45
+ native: {},
46
+ });
47
+ await adapter.setStateAsync('pump.pump_power_lph', {
48
+ val: adapter.config.pump_power_lph,
49
+ ack: true,
50
+ });
51
+
52
+ // Frostschutz aktiv
53
+ await adapter.setObjectNotExistsAsync('pump.frost_protection_active', {
54
+ type: 'state',
55
+ common: {
56
+ name: 'Frostschutz aktiv',
57
+ type: 'boolean',
58
+ role: 'switch',
59
+ read: true,
60
+ write: true,
61
+ },
62
+ native: {},
63
+ });
64
+ await adapter.setStateAsync('pump.frost_protection_active', {
65
+ val: adapter.config.frost_protection_active,
66
+ ack: true,
67
+ });
68
+
69
+ // Frostschutz-Temperatur
70
+ await adapter.setObjectNotExistsAsync('pump.frost_protection_temp', {
71
+ type: 'state',
72
+ common: {
73
+ name: 'Frostschutz-Temperatur',
74
+ type: 'number',
75
+ role: 'value.temperature',
76
+ unit: '°C',
77
+ read: true,
78
+ write: true,
79
+ },
80
+ native: {},
81
+ });
82
+ await adapter.setStateAsync('pump.frost_protection_temp', {
83
+ val: adapter.config.frost_protection_temp,
84
+ ack: true,
85
+ });
86
+
87
+ // **Zentraler Pumpen-Schalter (boolean)**
88
+ await adapter.setObjectNotExistsAsync('pump.pump_switch', {
89
+ type: 'state',
90
+ common: {
91
+ name: 'Pumpe EIN/AUS',
92
+ type: 'boolean',
93
+ role: 'switch',
94
+ read: true,
95
+ write: true,
96
+ },
97
+ native: {},
98
+ });
99
+ await adapter.setStateAsync('pump.pump_switch', { val: false, ack: true });
100
+
101
+ // Pumpenmodus
102
+ await adapter.setObjectNotExistsAsync('pump.mode', {
103
+ type: 'state',
104
+ common: {
105
+ name: 'Pumpenmodus',
106
+ type: 'string',
107
+ role: 'state',
108
+ read: true,
109
+ write: true,
110
+ states: {
111
+ auto: 'Automatik',
112
+ manual: 'Manuell',
113
+ off: 'Aus',
114
+ time: 'Zeit',
115
+ },
116
+ },
117
+ native: {},
118
+ });
119
+ await adapter.setStateAsync('pump.mode', { val: 'auto', ack: true });
120
+
121
+ // Sicherheitslogik im manuellen Modus
122
+ await adapter.setObjectNotExistsAsync('pump.manual_safety_enabled', {
123
+ type: 'state',
124
+ common: {
125
+ name: "Sicherheitsfunktionen im Modus 'Manuell' aktiv",
126
+ type: 'boolean',
127
+ role: 'switch',
128
+ read: true,
129
+ write: true,
130
+ },
131
+ native: {},
132
+ });
133
+ await adapter.setStateAsync('pump.manual_safety_enabled', {
134
+ val: adapter.config.manual_safety_enabled ?? true,
135
+ ack: true,
136
+ });
137
+
138
+ // Pumpenstatus (Text)
139
+ await adapter.setObjectNotExistsAsync('pump.status', {
140
+ type: 'state',
141
+ common: {
142
+ name: 'Pumpenstatus',
143
+ type: 'string',
144
+ role: 'text',
145
+ read: true,
146
+ write: false,
147
+ },
148
+ native: {},
149
+ });
150
+ await adapter.setStateAsync('pump.status', { val: 'AUS', ack: true });
151
+
152
+ // Pumpenfehler (bool)
153
+ await adapter.setObjectNotExistsAsync('pump.error', {
154
+ type: 'state',
155
+ common: {
156
+ name: 'Pumpenfehler',
157
+ type: 'boolean',
158
+ role: 'indicator.error',
159
+ read: true,
160
+ write: true, // manuell quittierbar
161
+ },
162
+ native: {},
163
+ });
164
+ await adapter.setStateAsync('pump.error', { val: false, ack: true });
165
+
166
+ // Aktuelle Leistung der Pumpe (W)
167
+ await adapter.setObjectNotExistsAsync('pump.current_power', {
168
+ type: 'state',
169
+ common: {
170
+ name: 'Aktuelle Leistung der Pumpe',
171
+ type: 'number',
172
+ role: 'value.power',
173
+ unit: 'W',
174
+ read: true,
175
+ write: false,
176
+ },
177
+ native: {},
178
+ });
179
+ await adapter.setStateAsync('pump.current_power', { val: 0, ack: true });
180
+ }
181
+
182
+ module.exports = {
183
+ createPumpStates,
184
+ };