iobroker.poolcontrol 0.8.1 → 0.9.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 +62 -11
- package/admin/jsonConfig.json +86 -2
- package/io-package.json +27 -27
- package/lib/helpers/aiChemistryHelpHelper.js +392 -0
- package/lib/helpers/heatHelper.js +450 -0
- package/lib/helpers/pumpHelper.js +9 -0
- package/lib/stateDefinitions/aiChemistryHelpStates.js +122 -0
- package/lib/stateDefinitions/heatStates.js +261 -0
- package/main.js +26 -0
- package/package.json +1 -1
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Legt alle States für die Heizungs- / Wärmepumpensteuerung an
|
|
5
|
+
*
|
|
6
|
+
* @param {import("iobroker").Adapter} adapter - ioBroker Adapter-Instanz
|
|
7
|
+
*/
|
|
8
|
+
async function createHeatStates(adapter) {
|
|
9
|
+
const channelId = 'heat';
|
|
10
|
+
|
|
11
|
+
// ---------------------------------------------------------
|
|
12
|
+
// Channel
|
|
13
|
+
// ---------------------------------------------------------
|
|
14
|
+
await adapter.setObjectNotExistsAsync(channelId, {
|
|
15
|
+
type: 'channel',
|
|
16
|
+
common: {
|
|
17
|
+
name: 'Heizung / Wärmepumpe',
|
|
18
|
+
},
|
|
19
|
+
native: {},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// ---------------------------------------------------------
|
|
23
|
+
// Steuerung / Konfiguration (write = true, persistent)
|
|
24
|
+
// ---------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
await adapter.setObjectNotExistsAsync(`${channelId}.control_active`, {
|
|
27
|
+
type: 'state',
|
|
28
|
+
common: {
|
|
29
|
+
name: 'Heizungssteuerung aktiv',
|
|
30
|
+
type: 'boolean',
|
|
31
|
+
role: 'switch',
|
|
32
|
+
read: true,
|
|
33
|
+
write: true,
|
|
34
|
+
persist: true,
|
|
35
|
+
},
|
|
36
|
+
native: {},
|
|
37
|
+
});
|
|
38
|
+
const existingControlActive = await adapter.getStateAsync(`${channelId}.control_active`);
|
|
39
|
+
if (
|
|
40
|
+
existingControlActive === null ||
|
|
41
|
+
existingControlActive.val === null ||
|
|
42
|
+
existingControlActive.val === undefined
|
|
43
|
+
) {
|
|
44
|
+
await adapter.setStateAsync(`${channelId}.control_active`, {
|
|
45
|
+
val: adapter.config.heat_control_active ?? false,
|
|
46
|
+
ack: true,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
await adapter.setObjectNotExistsAsync(`${channelId}.control_type`, {
|
|
51
|
+
type: 'state',
|
|
52
|
+
common: {
|
|
53
|
+
name: 'Art der Heizungssteuerung',
|
|
54
|
+
type: 'string',
|
|
55
|
+
role: 'text',
|
|
56
|
+
read: true,
|
|
57
|
+
write: true,
|
|
58
|
+
persist: true,
|
|
59
|
+
},
|
|
60
|
+
native: {},
|
|
61
|
+
});
|
|
62
|
+
const existingControlType = await adapter.getStateAsync(`${channelId}.control_type`);
|
|
63
|
+
if (existingControlType === null || existingControlType.val === null || existingControlType.val === undefined) {
|
|
64
|
+
await adapter.setStateAsync(`${channelId}.control_type`, {
|
|
65
|
+
val: adapter.config.heat_control_type ?? 'socket',
|
|
66
|
+
ack: true,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
await adapter.setObjectNotExistsAsync(`${channelId}.control_object_id`, {
|
|
71
|
+
type: 'state',
|
|
72
|
+
common: {
|
|
73
|
+
name: 'Steuer-Objekt-ID Heizung',
|
|
74
|
+
type: 'string',
|
|
75
|
+
role: 'text',
|
|
76
|
+
read: true,
|
|
77
|
+
write: true,
|
|
78
|
+
persist: true,
|
|
79
|
+
},
|
|
80
|
+
native: {},
|
|
81
|
+
});
|
|
82
|
+
const existingObjectId = await adapter.getStateAsync(`${channelId}.control_object_id`);
|
|
83
|
+
if (existingObjectId === null || existingObjectId.val === null || existingObjectId.val === undefined) {
|
|
84
|
+
await adapter.setStateAsync(`${channelId}.control_object_id`, {
|
|
85
|
+
val: adapter.config.heat_control_object_id ?? '',
|
|
86
|
+
ack: true,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
await adapter.setObjectNotExistsAsync(`${channelId}.target_temperature`, {
|
|
91
|
+
type: 'state',
|
|
92
|
+
common: {
|
|
93
|
+
name: 'Zieltemperatur Pool',
|
|
94
|
+
type: 'number',
|
|
95
|
+
role: 'value.temperature',
|
|
96
|
+
unit: '°C',
|
|
97
|
+
read: true,
|
|
98
|
+
write: true,
|
|
99
|
+
persist: true,
|
|
100
|
+
},
|
|
101
|
+
native: {},
|
|
102
|
+
});
|
|
103
|
+
const existingTargetTemp = await adapter.getStateAsync(`${channelId}.target_temperature`);
|
|
104
|
+
if (existingTargetTemp === null || existingTargetTemp.val === null || existingTargetTemp.val === undefined) {
|
|
105
|
+
await adapter.setStateAsync(`${channelId}.target_temperature`, {
|
|
106
|
+
val: adapter.config.heat_temp_target ?? 26,
|
|
107
|
+
ack: true,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
await adapter.setObjectNotExistsAsync(`${channelId}.max_temperature`, {
|
|
112
|
+
type: 'state',
|
|
113
|
+
common: {
|
|
114
|
+
name: 'Maximale Pooltemperatur (Sicherheit)',
|
|
115
|
+
type: 'number',
|
|
116
|
+
role: 'value.temperature',
|
|
117
|
+
unit: '°C',
|
|
118
|
+
read: true,
|
|
119
|
+
write: true,
|
|
120
|
+
persist: true,
|
|
121
|
+
},
|
|
122
|
+
native: {},
|
|
123
|
+
});
|
|
124
|
+
const existingMaxTemp = await adapter.getStateAsync(`${channelId}.max_temperature`);
|
|
125
|
+
if (existingMaxTemp === null || existingMaxTemp.val === null || existingMaxTemp.val === undefined) {
|
|
126
|
+
await adapter.setStateAsync(`${channelId}.max_temperature`, {
|
|
127
|
+
val: adapter.config.heat_temp_max ?? 30,
|
|
128
|
+
ack: true,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
await adapter.setObjectNotExistsAsync(`${channelId}.pump_afterrun_minutes`, {
|
|
133
|
+
type: 'state',
|
|
134
|
+
common: {
|
|
135
|
+
name: 'Pumpen-Nachlaufzeit nach Heizung',
|
|
136
|
+
type: 'number',
|
|
137
|
+
role: 'value.interval',
|
|
138
|
+
unit: 'min',
|
|
139
|
+
read: true,
|
|
140
|
+
write: true,
|
|
141
|
+
persist: true,
|
|
142
|
+
},
|
|
143
|
+
native: {},
|
|
144
|
+
});
|
|
145
|
+
const existingAfterrun = await adapter.getStateAsync(`${channelId}.pump_afterrun_minutes`);
|
|
146
|
+
if (existingAfterrun === null || existingAfterrun.val === null || existingAfterrun.val === undefined) {
|
|
147
|
+
await adapter.setStateAsync(`${channelId}.pump_afterrun_minutes`, {
|
|
148
|
+
val: 5,
|
|
149
|
+
ack: true,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ---------------------------------------------------------
|
|
154
|
+
// Betriebsstatus (write = false)
|
|
155
|
+
// ---------------------------------------------------------
|
|
156
|
+
|
|
157
|
+
await adapter.setObjectNotExistsAsync(`${channelId}.active`, {
|
|
158
|
+
type: 'state',
|
|
159
|
+
common: {
|
|
160
|
+
name: 'Heizung aktiv',
|
|
161
|
+
type: 'boolean',
|
|
162
|
+
role: 'indicator.working',
|
|
163
|
+
read: true,
|
|
164
|
+
write: false,
|
|
165
|
+
},
|
|
166
|
+
native: {},
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
await adapter.setObjectNotExistsAsync(`${channelId}.mode`, {
|
|
170
|
+
type: 'state',
|
|
171
|
+
common: {
|
|
172
|
+
name: 'Heizungsmodus',
|
|
173
|
+
type: 'string',
|
|
174
|
+
role: 'text',
|
|
175
|
+
read: true,
|
|
176
|
+
write: false,
|
|
177
|
+
},
|
|
178
|
+
native: {},
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
await adapter.setObjectNotExistsAsync(`${channelId}.blocked`, {
|
|
182
|
+
type: 'state',
|
|
183
|
+
common: {
|
|
184
|
+
name: 'Heizung blockiert',
|
|
185
|
+
type: 'boolean',
|
|
186
|
+
role: 'indicator.blocked',
|
|
187
|
+
read: true,
|
|
188
|
+
write: false,
|
|
189
|
+
},
|
|
190
|
+
native: {},
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
await adapter.setObjectNotExistsAsync(`${channelId}.afterrun_active`, {
|
|
194
|
+
type: 'state',
|
|
195
|
+
common: {
|
|
196
|
+
name: 'Pumpen-Nachlauf aktiv',
|
|
197
|
+
type: 'boolean',
|
|
198
|
+
role: 'indicator.working',
|
|
199
|
+
read: true,
|
|
200
|
+
write: false,
|
|
201
|
+
},
|
|
202
|
+
native: {},
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
await adapter.setObjectNotExistsAsync(`${channelId}.last_change`, {
|
|
206
|
+
type: 'state',
|
|
207
|
+
common: {
|
|
208
|
+
name: 'Letzte Statusänderung Heizung',
|
|
209
|
+
type: 'number',
|
|
210
|
+
role: 'value.time',
|
|
211
|
+
read: true,
|
|
212
|
+
write: false,
|
|
213
|
+
},
|
|
214
|
+
native: {},
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
await adapter.setObjectNotExistsAsync(`${channelId}.heating_request`, {
|
|
218
|
+
type: 'state',
|
|
219
|
+
common: {
|
|
220
|
+
name: 'Heizanforderung (PoolControl)',
|
|
221
|
+
type: 'boolean',
|
|
222
|
+
role: 'indicator.request',
|
|
223
|
+
read: true,
|
|
224
|
+
write: false,
|
|
225
|
+
def: false,
|
|
226
|
+
},
|
|
227
|
+
native: {},
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// ---------------------------------------------------------
|
|
231
|
+
// Transparenz / Diagnose
|
|
232
|
+
// ---------------------------------------------------------
|
|
233
|
+
|
|
234
|
+
await adapter.setObjectNotExistsAsync(`${channelId}.reason`, {
|
|
235
|
+
type: 'state',
|
|
236
|
+
common: {
|
|
237
|
+
name: 'Grund für Heizungsstatus',
|
|
238
|
+
type: 'string',
|
|
239
|
+
role: 'text',
|
|
240
|
+
read: true,
|
|
241
|
+
write: false,
|
|
242
|
+
},
|
|
243
|
+
native: {},
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
await adapter.setObjectNotExistsAsync(`${channelId}.info`, {
|
|
247
|
+
type: 'state',
|
|
248
|
+
common: {
|
|
249
|
+
name: 'Heizungs-Info',
|
|
250
|
+
type: 'string',
|
|
251
|
+
role: 'text',
|
|
252
|
+
read: true,
|
|
253
|
+
write: false,
|
|
254
|
+
},
|
|
255
|
+
native: {},
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
module.exports = {
|
|
260
|
+
createHeatStates,
|
|
261
|
+
};
|
package/main.js
CHANGED
|
@@ -23,12 +23,14 @@ const statusHelper = require('./lib/helpers/statusHelper');
|
|
|
23
23
|
const photovoltaicHelper = require('./lib/helpers/photovoltaicHelper');
|
|
24
24
|
const aiHelper = require('./lib/helpers/aiHelper');
|
|
25
25
|
const aiForecastHelper = require('./lib/helpers/aiForecastHelper');
|
|
26
|
+
const aiChemistryHelpHelper = require('./lib/helpers/aiChemistryHelpHelper');
|
|
26
27
|
const controlHelper = require('./lib/helpers/controlHelper');
|
|
27
28
|
const controlHelper2 = require('./lib/helpers/controlHelper2');
|
|
28
29
|
const debugLogHelper = require('./lib/helpers/debugLogHelper');
|
|
29
30
|
const speechTextHelper = require('./lib/helpers/speechTextHelper');
|
|
30
31
|
const migrationHelper = require('./lib/helpers/migrationHelper');
|
|
31
32
|
const infoHelper = require('./lib/helpers/infoHelper');
|
|
33
|
+
const heatHelper = require('./lib/helpers/heatHelper');
|
|
32
34
|
const { createTemperatureStates } = require('./lib/stateDefinitions/temperatureStates');
|
|
33
35
|
const { createPumpStates } = require('./lib/stateDefinitions/pumpStates');
|
|
34
36
|
const { createPumpStates2 } = require('./lib/stateDefinitions/pumpStates2');
|
|
@@ -47,6 +49,8 @@ const { createControlStates } = require('./lib/stateDefinitions/controlStates');
|
|
|
47
49
|
const { createDebugLogStates } = require('./lib/stateDefinitions/debugLogStates');
|
|
48
50
|
const { createInfoStates } = require('./lib/stateDefinitions/infoStates');
|
|
49
51
|
const { createAiStates } = require('./lib/stateDefinitions/aiStates'); // NEU: KI-States
|
|
52
|
+
const { createAiChemistryHelpStates } = require('./lib/stateDefinitions/aiChemistryHelpStates'); // NEU: KI-Chemie-Hilfe
|
|
53
|
+
const { createHeatStates } = require('./lib/stateDefinitions/heatStates');
|
|
50
54
|
|
|
51
55
|
class Poolcontrol extends utils.Adapter {
|
|
52
56
|
constructor(options) {
|
|
@@ -77,6 +81,9 @@ class Poolcontrol extends utils.Adapter {
|
|
|
77
81
|
// --- Solarverwaltung ---
|
|
78
82
|
await createSolarStates(this);
|
|
79
83
|
|
|
84
|
+
// --- Heizung / Wärmepumpe ---
|
|
85
|
+
await createHeatStates(this);
|
|
86
|
+
|
|
80
87
|
// --- Photovoltaik ---
|
|
81
88
|
await createPhotovoltaicStates(this);
|
|
82
89
|
|
|
@@ -115,6 +122,7 @@ class Poolcontrol extends utils.Adapter {
|
|
|
115
122
|
|
|
116
123
|
// --- AI States ---
|
|
117
124
|
await createAiStates(this); // NEU: KI-States anlegen
|
|
125
|
+
await createAiChemistryHelpStates(this); // NEU: KI-Chemie-Hilfe-States
|
|
118
126
|
|
|
119
127
|
// --- Migration Helper zuletzt starten ---
|
|
120
128
|
await migrationHelper.init(this);
|
|
@@ -133,9 +141,11 @@ class Poolcontrol extends utils.Adapter {
|
|
|
133
141
|
speechHelper.init(this);
|
|
134
142
|
consumptionHelper.init(this);
|
|
135
143
|
solarHelper.init(this);
|
|
144
|
+
heatHelper.init(this); // ← NEU
|
|
136
145
|
photovoltaicHelper.init(this);
|
|
137
146
|
aiHelper.init(this);
|
|
138
147
|
aiForecastHelper.init(this);
|
|
148
|
+
aiChemistryHelpHelper.init(this);
|
|
139
149
|
frostHelper.init(this);
|
|
140
150
|
statusHelper.init(this);
|
|
141
151
|
infoHelper.init(this);
|
|
@@ -192,6 +202,9 @@ class Poolcontrol extends utils.Adapter {
|
|
|
192
202
|
if (controlHelper2.cleanup) {
|
|
193
203
|
controlHelper2.cleanup();
|
|
194
204
|
}
|
|
205
|
+
if (heatHelper.cleanup) {
|
|
206
|
+
heatHelper.cleanup();
|
|
207
|
+
}
|
|
195
208
|
if (speechTextHelper.cleanup) {
|
|
196
209
|
speechTextHelper.cleanup();
|
|
197
210
|
}
|
|
@@ -201,6 +214,9 @@ class Poolcontrol extends utils.Adapter {
|
|
|
201
214
|
if (aiForecastHelper.cleanup) {
|
|
202
215
|
aiForecastHelper.cleanup();
|
|
203
216
|
}
|
|
217
|
+
if (aiChemistryHelpHelper.cleanup) {
|
|
218
|
+
aiChemistryHelpHelper.cleanup();
|
|
219
|
+
}
|
|
204
220
|
if (infoHelper.cleanup) {
|
|
205
221
|
infoHelper.cleanup();
|
|
206
222
|
}
|
|
@@ -272,6 +288,11 @@ class Poolcontrol extends utils.Adapter {
|
|
|
272
288
|
} catch (e) {
|
|
273
289
|
this.log.warn(`[photovoltaicHelper] Fehler in handleStateChange: ${e.message}`);
|
|
274
290
|
}
|
|
291
|
+
try {
|
|
292
|
+
heatHelper.handleStateChange(id, state);
|
|
293
|
+
} catch (e) {
|
|
294
|
+
this.log.warn(`[heatHelper] Fehler in handleStateChange: ${e.message}`);
|
|
295
|
+
}
|
|
275
296
|
// --- AI-Helper ---
|
|
276
297
|
try {
|
|
277
298
|
aiHelper.handleStateChange(id, state);
|
|
@@ -283,6 +304,11 @@ class Poolcontrol extends utils.Adapter {
|
|
|
283
304
|
} catch (e) {
|
|
284
305
|
this.log.warn(`[main] Fehler in aiForecastHelper.handleStateChange: ${e.message}`);
|
|
285
306
|
}
|
|
307
|
+
try {
|
|
308
|
+
aiChemistryHelpHelper.handleStateChange(id, state);
|
|
309
|
+
} catch (e) {
|
|
310
|
+
this.log.warn(`[main] Fehler in aiChemistryHelpHelper.handleStateChange: ${e.message}`);
|
|
311
|
+
}
|
|
286
312
|
try {
|
|
287
313
|
statusHelper.handleStateChange(id, state);
|
|
288
314
|
} catch (e) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.poolcontrol",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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",
|