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.
- package/LICENSE +22 -0
- package/README.md +129 -0
- package/admin/i18n/de/translations.json +5 -0
- package/admin/i18n/en/translations.json +5 -0
- package/admin/i18n/es/translations.json +5 -0
- package/admin/i18n/fr/translations.json +5 -0
- package/admin/i18n/it/translations.json +5 -0
- package/admin/i18n/nl/translations.json +5 -0
- package/admin/i18n/pl/translations.json +5 -0
- package/admin/i18n/pt/translations.json +5 -0
- package/admin/i18n/ru/translations.json +5 -0
- package/admin/i18n/uk/translations.json +5 -0
- package/admin/i18n/zh-cn/translations.json +5 -0
- package/admin/jsonConfig.json +901 -0
- package/admin/poolcontrol.png +0 -0
- package/io-package.json +176 -0
- package/lib/adapter-config.d.ts +19 -0
- package/lib/helpers/consumptionHelper.js +185 -0
- package/lib/helpers/frostHelper.js +94 -0
- package/lib/helpers/pumpHelper.js +224 -0
- package/lib/helpers/runtimeHelper.js +159 -0
- package/lib/helpers/solarHelper.js +138 -0
- package/lib/helpers/speechHelper.js +108 -0
- package/lib/helpers/temperatureHelper.js +227 -0
- package/lib/helpers/timeHelper.js +88 -0
- package/lib/stateDefinitions/consumptionStates.js +82 -0
- package/lib/stateDefinitions/generalStates.js +68 -0
- package/lib/stateDefinitions/pumpStates.js +184 -0
- package/lib/stateDefinitions/runtimeStates.js +113 -0
- package/lib/stateDefinitions/solarStates.js +150 -0
- package/lib/stateDefinitions/speechStates.js +104 -0
- package/lib/stateDefinitions/temperatureStates.js +182 -0
- package/lib/stateDefinitions/timeStates.js +102 -0
- package/main.js +145 -0
- 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
|
+
};
|