iobroker.smartloadmanager 0.0.6 → 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/README.md +17 -299
- package/admin/i18n/de/translations.json +85 -11
- package/admin/i18n/en/translations.json +75 -3
- package/admin/i18n/es/translations.json +75 -1
- package/admin/i18n/fr/translations.json +75 -1
- package/admin/i18n/it/translations.json +75 -1
- package/admin/i18n/nl/translations.json +75 -1
- package/admin/i18n/pl/translations.json +75 -1
- package/admin/i18n/pt/translations.json +75 -1
- package/admin/i18n/ru/translations.json +75 -1
- package/admin/i18n/uk/translations.json +75 -1
- package/admin/i18n/zh-cn/translations.json +75 -1
- package/admin/jsonConfig.json +46 -370
- package/io-package.json +28 -43
- package/main.js +235 -154
- package/package.json +5 -16
package/main.js
CHANGED
|
@@ -8,6 +8,9 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
8
8
|
...options,
|
|
9
9
|
name: 'smartloadmanager',
|
|
10
10
|
});
|
|
11
|
+
// Timeout-Limits definieren
|
|
12
|
+
this.MAX_TIMEOUT = 86400000; // 24h in ms
|
|
13
|
+
this.DEFAULT_TIMEOUT = 60000; // 60 Sekunden Fallback
|
|
11
14
|
this.consumerList = [];
|
|
12
15
|
this.feedInDatapoint = null;
|
|
13
16
|
this.batteryControlModeDatapoint = null;
|
|
@@ -19,15 +22,40 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
19
22
|
this.on('stateChange', this.onStateChange.bind(this));
|
|
20
23
|
this.on('unload', this.onUnload.bind(this));
|
|
21
24
|
}
|
|
25
|
+
name2id(pName) {
|
|
26
|
+
return (pName || '')
|
|
27
|
+
.replace(this.FORBIDDEN_CHARS, '_') // ioBroker verbotene Zeichen
|
|
28
|
+
.replace(/\s+/g, '_') // Leerzeichen → _
|
|
29
|
+
.replace(/\./g, '_') // Punkte → _
|
|
30
|
+
.replace(/[^a-zA-Z0-9\-_]/g, '_') // nur erlaubte Zeichen
|
|
31
|
+
.replace(/_+/g, '_') // mehrere Unterstriche zusammenfassen
|
|
32
|
+
.replace(/^_+|_+$/g, ''); // führende/trailing _ weg
|
|
33
|
+
}
|
|
34
|
+
// Wrapper für sichere Timer
|
|
35
|
+
safeSetTimeout(fn, ms, ...args) {
|
|
36
|
+
const safeMs = Math.min(Math.max(ms, 0), this.MAX_TIMEOUT);
|
|
37
|
+
if (ms > this.MAX_TIMEOUT) {
|
|
38
|
+
this.log.warn(`Timeout of ${ms} ms has been limited to ${this.MAX_TIMEOUT} ms!`);
|
|
39
|
+
}
|
|
40
|
+
return this.setTimeout(fn, safeMs, ...args);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
safeSetInterval(fn, ms, ...args) {
|
|
44
|
+
const safeMs = Math.min(Math.max(ms, 0), this.MAX_TIMEOUT);
|
|
45
|
+
if (ms > this.MAX_TIMEOUT) {
|
|
46
|
+
this.log.warn(`Interval of ${ms} ms has been limited to ${this.MAX_TIMEOUT} ms!`);
|
|
47
|
+
}
|
|
48
|
+
return this.setInterval(fn, safeMs, ...args);
|
|
49
|
+
}
|
|
22
50
|
|
|
23
51
|
async onReady() {
|
|
24
52
|
try {
|
|
25
|
-
this.log.info(
|
|
53
|
+
this.log.info(`Adapter started, PID: ${process.pid}`);
|
|
26
54
|
|
|
27
55
|
if (!this.config.FeedInDataPoint) {
|
|
28
56
|
this.log.error('No FeedInDataPoint configured!');
|
|
29
|
-
//
|
|
30
|
-
await this.sendNotification('smartloadmanager', 'alarm', '
|
|
57
|
+
// additionally send alert
|
|
58
|
+
await this.sendNotification('smartloadmanager', 'alarm', 'No FeedInDataPoint configured!');
|
|
31
59
|
return;
|
|
32
60
|
}
|
|
33
61
|
this.feedInDatapoint = this.config.FeedInDataPoint;
|
|
@@ -58,20 +86,10 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
58
86
|
}
|
|
59
87
|
|
|
60
88
|
await this.checkConsumers();
|
|
61
|
-
|
|
62
|
-
/* // Info beim erfolgreichen Start
|
|
63
|
-
if (!this.adapterStartedNotified) {
|
|
64
|
-
await this.sendNotification(
|
|
65
|
-
'smartloadmanager',
|
|
66
|
-
'info',
|
|
67
|
-
'ℹ️ SmartLoadManager Adapter erfolgreich gestartet.',
|
|
68
|
-
);
|
|
69
|
-
this.adapterStartedNotified = true;
|
|
70
|
-
} */
|
|
71
89
|
} catch (error) {
|
|
72
90
|
this.log.error(`Error in onReady: ${error.message}`);
|
|
73
|
-
//
|
|
74
|
-
await this.sendNotification('smartloadmanager', 'alert',
|
|
91
|
+
// additionally send alert
|
|
92
|
+
await this.sendNotification('smartloadmanager', 'alert', `Error in onReady: ${error.message}`);
|
|
75
93
|
}
|
|
76
94
|
}
|
|
77
95
|
|
|
@@ -93,20 +111,30 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
93
111
|
}
|
|
94
112
|
|
|
95
113
|
async createConsumerStates() {
|
|
114
|
+
// Übergeordnetes Device erstellen - löst "intermediate objects missing" Problem
|
|
115
|
+
await this.setObjectNotExistsAsync('consumer', {
|
|
116
|
+
type: 'device',
|
|
117
|
+
common: {
|
|
118
|
+
name: 'Consumer Management',
|
|
119
|
+
},
|
|
120
|
+
native: {},
|
|
121
|
+
});
|
|
122
|
+
|
|
96
123
|
for (let i = 0; i < this.consumerList.length; i++) {
|
|
97
124
|
const v = this.consumerList[i];
|
|
98
|
-
const
|
|
125
|
+
const safeName = this.name2id(v.name);
|
|
126
|
+
const channelId = `consumer.${i}_${safeName}`;
|
|
99
127
|
|
|
100
128
|
await this.setObjectNotExistsAsync(channelId, {
|
|
101
129
|
type: 'channel',
|
|
102
|
-
common: { name: v.name },
|
|
130
|
+
common: { name: v.name }, // Channel selbst darf Klartext-Nutzername behalten
|
|
103
131
|
native: {},
|
|
104
132
|
});
|
|
105
133
|
|
|
106
134
|
await this.setObjectNotExistsAsync(`${channelId}.controlMode`, {
|
|
107
135
|
type: 'state',
|
|
108
136
|
common: {
|
|
109
|
-
name:
|
|
137
|
+
name: 'controlMode',
|
|
110
138
|
type: 'number',
|
|
111
139
|
role: 'level.mode',
|
|
112
140
|
read: true,
|
|
@@ -117,12 +145,13 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
117
145
|
native: {},
|
|
118
146
|
});
|
|
119
147
|
|
|
148
|
+
// KORRIGIERT: switchOnTime und switchOffTime als text statt value.time
|
|
120
149
|
await this.setObjectNotExistsAsync(`${channelId}.switchOnTime`, {
|
|
121
150
|
type: 'state',
|
|
122
151
|
common: {
|
|
123
|
-
name:
|
|
152
|
+
name: 'switchOnTime',
|
|
124
153
|
type: 'string',
|
|
125
|
-
role: 'value.time'
|
|
154
|
+
role: 'text', // GEÄNDERT von 'value.time' zu 'text'
|
|
126
155
|
read: true,
|
|
127
156
|
write: true,
|
|
128
157
|
def: '',
|
|
@@ -133,9 +162,9 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
133
162
|
await this.setObjectNotExistsAsync(`${channelId}.switchOffTime`, {
|
|
134
163
|
type: 'state',
|
|
135
164
|
common: {
|
|
136
|
-
name:
|
|
165
|
+
name: 'switchOffTime',
|
|
137
166
|
type: 'string',
|
|
138
|
-
role: 'value.time'
|
|
167
|
+
role: 'text', // GEÄNDERT von 'value.time' zu 'text'
|
|
139
168
|
read: true,
|
|
140
169
|
write: true,
|
|
141
170
|
def: '',
|
|
@@ -146,7 +175,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
146
175
|
await this.setObjectNotExistsAsync(`${channelId}.alwaysOffAtTime`, {
|
|
147
176
|
type: 'state',
|
|
148
177
|
common: {
|
|
149
|
-
name:
|
|
178
|
+
name: 'alwaysOffAtTime',
|
|
150
179
|
type: 'boolean',
|
|
151
180
|
role: 'switch',
|
|
152
181
|
read: true,
|
|
@@ -159,9 +188,9 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
159
188
|
await this.setObjectNotExistsAsync(`${channelId}.performance`, {
|
|
160
189
|
type: 'state',
|
|
161
190
|
common: {
|
|
162
|
-
name:
|
|
191
|
+
name: 'performance',
|
|
163
192
|
type: 'number',
|
|
164
|
-
role: 'value.power.consumption'
|
|
193
|
+
role: 'value.power', // GEÄNDERT von 'value.power.consumption' zu 'value.power'
|
|
165
194
|
read: true,
|
|
166
195
|
write: false,
|
|
167
196
|
def: v.performance || 0,
|
|
@@ -173,7 +202,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
173
202
|
await this.setObjectNotExistsAsync(`${channelId}.switchOnPoint`, {
|
|
174
203
|
type: 'state',
|
|
175
204
|
common: {
|
|
176
|
-
name:
|
|
205
|
+
name: 'switchOnPoint',
|
|
177
206
|
type: 'number',
|
|
178
207
|
role: 'value.power',
|
|
179
208
|
read: true,
|
|
@@ -187,7 +216,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
187
216
|
await this.setObjectNotExistsAsync(`${channelId}.switchOffPoint`, {
|
|
188
217
|
type: 'state',
|
|
189
218
|
common: {
|
|
190
|
-
name:
|
|
219
|
+
name: 'switchOffPoint',
|
|
191
220
|
type: 'number',
|
|
192
221
|
role: 'value.power',
|
|
193
222
|
read: true,
|
|
@@ -202,9 +231,9 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
202
231
|
await this.setObjectNotExistsAsync(`${channelId}.batterySetpoint`, {
|
|
203
232
|
type: 'state',
|
|
204
233
|
common: {
|
|
205
|
-
name:
|
|
234
|
+
name: 'batterySetpoint',
|
|
206
235
|
type: 'string',
|
|
207
|
-
role: 'value'
|
|
236
|
+
role: 'text', // GEÄNDERT von 'value' zu 'text' (spezifischer)
|
|
208
237
|
read: true,
|
|
209
238
|
write: true,
|
|
210
239
|
def: v.batterySetpoint || '',
|
|
@@ -213,12 +242,13 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
213
242
|
});
|
|
214
243
|
}
|
|
215
244
|
|
|
245
|
+
// KORRIGIERT: value.duration ist korrekt für Timer
|
|
216
246
|
await this.setObjectNotExistsAsync(`${channelId}.onTimerRemaining`, {
|
|
217
247
|
type: 'state',
|
|
218
248
|
common: {
|
|
219
|
-
name:
|
|
249
|
+
name: 'onTimerRemaining',
|
|
220
250
|
type: 'number',
|
|
221
|
-
role: 'value.duration'
|
|
251
|
+
role: 'value.interval', // GEÄNDERT von 'value.duration' zu 'value.interval'
|
|
222
252
|
read: true,
|
|
223
253
|
write: false,
|
|
224
254
|
def: 0,
|
|
@@ -230,9 +260,9 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
230
260
|
await this.setObjectNotExistsAsync(`${channelId}.offTimerRemaining`, {
|
|
231
261
|
type: 'state',
|
|
232
262
|
common: {
|
|
233
|
-
name:
|
|
263
|
+
name: 'offTimerRemaining',
|
|
234
264
|
type: 'number',
|
|
235
|
-
role: 'value.duration'
|
|
265
|
+
role: 'value.interval', // GEÄNDERT von 'value.duration' zu 'value.interval'
|
|
236
266
|
read: true,
|
|
237
267
|
write: false,
|
|
238
268
|
def: 0,
|
|
@@ -241,11 +271,18 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
241
271
|
native: {},
|
|
242
272
|
});
|
|
243
273
|
|
|
274
|
+
// States initialisieren
|
|
244
275
|
const finalOnTime = v.switchOnTime || '';
|
|
245
276
|
const finalOffTime = v.switchOffTime || '';
|
|
246
277
|
|
|
247
|
-
await this.setStateAsync(`${this.namespace}.${channelId}.switchOnTime`, {
|
|
248
|
-
|
|
278
|
+
await this.setStateAsync(`${this.namespace}.${channelId}.switchOnTime`, {
|
|
279
|
+
val: finalOnTime,
|
|
280
|
+
ack: true,
|
|
281
|
+
});
|
|
282
|
+
await this.setStateAsync(`${this.namespace}.${channelId}.switchOffTime`, {
|
|
283
|
+
val: finalOffTime,
|
|
284
|
+
ack: true,
|
|
285
|
+
});
|
|
249
286
|
await this.setStateAsync(`${this.namespace}.${channelId}.alwaysOffAtTime`, {
|
|
250
287
|
val: v.alwaysOffAtTime || false,
|
|
251
288
|
ack: true,
|
|
@@ -285,7 +322,9 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
285
322
|
|
|
286
323
|
if (name) {
|
|
287
324
|
this.log.debug(
|
|
288
|
-
|
|
325
|
+
`${name}: Time window ${onTime}–${offTime}, current ${now
|
|
326
|
+
.toTimeString()
|
|
327
|
+
.slice(0, 5)} (${currentMinutes} min), within? ${within}`,
|
|
289
328
|
);
|
|
290
329
|
}
|
|
291
330
|
|
|
@@ -297,52 +336,58 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
297
336
|
return;
|
|
298
337
|
}
|
|
299
338
|
|
|
300
|
-
// FeedIn
|
|
339
|
+
// FeedIn Datapoint - fremder State, nur bei ack=true reagieren
|
|
301
340
|
if (id === this.feedInDatapoint) {
|
|
302
|
-
|
|
303
|
-
|
|
341
|
+
// Nur verarbeiten wenn der Wert vom anderen Adapter bestätigt wurde
|
|
342
|
+
if (state.ack === true) {
|
|
343
|
+
this.log.debug(`Feed-in value updated: ${state.val} (ack=${state.ack})`);
|
|
344
|
+
await this.checkConsumers();
|
|
304
345
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
346
|
+
if (this.percentTimer) {
|
|
347
|
+
clearTimeout(this.percentTimer);
|
|
348
|
+
}
|
|
349
|
+
this.percentTimer = this.safeSetTimeout(
|
|
350
|
+
async () => {
|
|
351
|
+
for (const v of this.consumerList.filter(v => v.ruletype === 'percent')) {
|
|
352
|
+
await this.controlPercentConsumer(v);
|
|
353
|
+
}
|
|
354
|
+
this.percentTimer = null;
|
|
355
|
+
},
|
|
356
|
+
(this.config.delaySecondsProzent || this.DEFAULT_TIMEOUT / 1000) * 1000,
|
|
357
|
+
);
|
|
317
358
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
359
|
+
if (this.batteryTimer) {
|
|
360
|
+
clearTimeout(this.batteryTimer);
|
|
361
|
+
}
|
|
362
|
+
this.batteryTimer = this.safeSetTimeout(
|
|
363
|
+
async () => {
|
|
364
|
+
if (!this.feedInDatapoint) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
const feedInState = await this.getForeignStateAsync(this.feedInDatapoint);
|
|
368
|
+
let feedIn = Number(feedInState?.val) || 0;
|
|
369
|
+
if (this.config.feedinNegativ) {
|
|
370
|
+
feedIn = -feedIn;
|
|
371
|
+
}
|
|
331
372
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
373
|
+
for (const v of this.consumerList.filter(v => v.ruletype === 'battery')) {
|
|
374
|
+
await this.controlBattery(v, feedIn);
|
|
375
|
+
}
|
|
376
|
+
this.batteryTimer = null;
|
|
377
|
+
},
|
|
378
|
+
(this.config.batteryDelaySeconds || this.DEFAULT_TIMEOUT / 1000) * 1000,
|
|
379
|
+
);
|
|
380
|
+
} else {
|
|
381
|
+
this.log.debug(`Feed-in value change ignored (ack=${state.ack}) - waiting for confirmed value`);
|
|
382
|
+
}
|
|
383
|
+
return;
|
|
340
384
|
}
|
|
341
385
|
|
|
342
|
-
//
|
|
386
|
+
// Eigene States - nur bei ack=false verarbeiten (Commands/Befehle)
|
|
343
387
|
if (state && !state.ack) {
|
|
344
388
|
this.log.debug(`State changed: ${id} => ${state.val}`);
|
|
345
389
|
|
|
390
|
+
// ControlMode Änderungen
|
|
346
391
|
const match = id.match(/consumer\.(\d+)_.*?\.controlMode/);
|
|
347
392
|
if (match) {
|
|
348
393
|
const index = parseInt(match[1]);
|
|
@@ -356,6 +401,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
356
401
|
}
|
|
357
402
|
}
|
|
358
403
|
|
|
404
|
+
// Time Änderungen
|
|
359
405
|
const timeMatch = id.match(/consumer\.(\d+)_.*?\.(switchOnTime|switchOffTime)/);
|
|
360
406
|
if (timeMatch) {
|
|
361
407
|
const index = parseInt(timeMatch[1]);
|
|
@@ -376,7 +422,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
376
422
|
|
|
377
423
|
try {
|
|
378
424
|
if (!this.feedInDatapoint) {
|
|
379
|
-
this.log.warn('
|
|
425
|
+
this.log.warn('No FeedIn datapoint set – skipping checkConsumers()');
|
|
380
426
|
await this.sendNotification(
|
|
381
427
|
'smartloadmanager',
|
|
382
428
|
'alert',
|
|
@@ -398,7 +444,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
398
444
|
const baseload = this.config.baseload || 0;
|
|
399
445
|
const gridUsage = feedIn <= baseload;
|
|
400
446
|
|
|
401
|
-
this.log.debug(
|
|
447
|
+
this.log.debug(`FeedIn: ${feedIn} W, Baseload: ${baseload} W, GridUsage: ${gridUsage}`);
|
|
402
448
|
|
|
403
449
|
// ----------------------------------
|
|
404
450
|
// Einschalten binary + heating
|
|
@@ -407,17 +453,18 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
407
453
|
.filter(v => v.ruletype === 'binary' || v.ruletype === 'heating')
|
|
408
454
|
.sort((a, b) => (a.priority || 1) - (b.priority || 1));
|
|
409
455
|
|
|
410
|
-
this.log.debug(
|
|
456
|
+
this.log.debug(`Switch-on check for ${sortedOn.length} binary/heating-consumers.`);
|
|
411
457
|
|
|
412
458
|
for (const v of sortedOn) {
|
|
413
459
|
const idx = this.consumerList.indexOf(v);
|
|
414
|
-
const
|
|
460
|
+
const safeName = this.name2id(v.name);
|
|
461
|
+
const id = `${this.namespace}.consumer.${idx}_${safeName}`;
|
|
415
462
|
const mode = await this.getStateAsync(`${id}.controlMode`);
|
|
416
463
|
|
|
417
|
-
this.log.debug(
|
|
464
|
+
this.log.debug(`Checking "${v.name}" (priority ${v.priority}, ${v.performance} W, Type=${v.ruletype})`);
|
|
418
465
|
|
|
419
466
|
if (!mode || mode.val !== 2) {
|
|
420
|
-
this.log.debug(
|
|
467
|
+
this.log.debug(`Manual mode active, skipping.`);
|
|
421
468
|
continue;
|
|
422
469
|
}
|
|
423
470
|
|
|
@@ -435,10 +482,10 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
435
482
|
if (numVal === 1) {
|
|
436
483
|
isOn = true;
|
|
437
484
|
}
|
|
438
|
-
this.log.debug(
|
|
485
|
+
this.log.debug(`NumericDatapoint für "${v.name}": ${v.numericDatapoint} = ${numVal}`);
|
|
439
486
|
}
|
|
440
487
|
|
|
441
|
-
this.log.debug(
|
|
488
|
+
this.log.debug(`"${v.name}" Status: isOn=${isOn}`);
|
|
442
489
|
|
|
443
490
|
// Zusatz-Checks heating
|
|
444
491
|
if (v.ruletype === 'heating' && withinWindow && !isOn) {
|
|
@@ -449,13 +496,13 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
449
496
|
|
|
450
497
|
if (currentTemp !== null && v.maxTemperature !== undefined && currentTemp >= v.maxTemperature) {
|
|
451
498
|
this.log.warn(
|
|
452
|
-
|
|
499
|
+
`"${v.name}" not switched on, temperature ${currentTemp}°C >= MaxTemp ${v.maxTemperature}°C`,
|
|
453
500
|
);
|
|
454
501
|
continue;
|
|
455
502
|
}
|
|
456
503
|
if (currentTemp !== null && v.minTemperature !== undefined && currentTemp < v.minTemperature) {
|
|
457
504
|
this.log.debug(
|
|
458
|
-
|
|
505
|
+
`"${v.name}" not switched on yet, temperature ${currentTemp}°C < MinTemp ${v.minTemperature}°C`,
|
|
459
506
|
);
|
|
460
507
|
continue;
|
|
461
508
|
}
|
|
@@ -463,7 +510,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
463
510
|
if (v.enableDatapoint) {
|
|
464
511
|
const enableState = await this.getForeignStateAsync(v.enableDatapoint);
|
|
465
512
|
if (!enableState?.val) {
|
|
466
|
-
this.log.debug(
|
|
513
|
+
this.log.debug(`"${v.name}" NICHT eingeschaltet – Hardware release missing.`);
|
|
467
514
|
continue;
|
|
468
515
|
}
|
|
469
516
|
}
|
|
@@ -471,7 +518,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
471
518
|
if (v.heartbeatDatapoint) {
|
|
472
519
|
const hbState = await this.getForeignStateAsync(v.heartbeatDatapoint);
|
|
473
520
|
if (!hbState?.val) {
|
|
474
|
-
this.log.warn(
|
|
521
|
+
this.log.warn(`"${v.name}" not switched on – hardware approval missing.`);
|
|
475
522
|
continue;
|
|
476
523
|
}
|
|
477
524
|
}
|
|
@@ -488,28 +535,30 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
488
535
|
v.timer = null;
|
|
489
536
|
v.timerEnd = null;
|
|
490
537
|
v.pendingAction = null;
|
|
491
|
-
const channelId = `consumer.${idx}_${
|
|
538
|
+
const channelId = `consumer.${idx}_${safeName}`;
|
|
492
539
|
await this.setStateAsync(`${this.namespace}.${channelId}.onTimerRemaining`, { val: 0, ack: true });
|
|
493
540
|
await this.setStateAsync(`${this.namespace}.${channelId}.offTimerRemaining`, { val: 0, ack: true });
|
|
494
|
-
this.log.debug(
|
|
541
|
+
this.log.debug(`Switch-on timer for "${v.name}" canceled (condition no longer valid).`);
|
|
495
542
|
}
|
|
496
543
|
|
|
497
544
|
if (withinWindow) {
|
|
498
545
|
if (!gridUsage && v.performance <= feedIn - baseload && !isOn) {
|
|
499
546
|
this.log.debug(
|
|
500
|
-
|
|
547
|
+
`Switch-on possible: surplus ${
|
|
548
|
+
feedIn - baseload
|
|
549
|
+
} W, within time window (onDelay ${v.switchOnDelay || 0}s).`,
|
|
501
550
|
);
|
|
502
551
|
await this.switchConsumerWithDelay(v, true, v.switchOnDelay || 0);
|
|
503
552
|
feedIn -= v.performance;
|
|
504
|
-
this.log.debug(
|
|
553
|
+
this.log.debug(`Remaining surplus after switch-on: ${feedIn - baseload} W`);
|
|
505
554
|
} else if (gridUsage && !isOn) {
|
|
506
|
-
this.log.debug(
|
|
555
|
+
this.log.debug(`Not switched on: grid usage active.`);
|
|
507
556
|
} else if (!isOn) {
|
|
508
557
|
this.log.debug(
|
|
509
|
-
|
|
558
|
+
`Not switched on: surplus too low (${feedIn - baseload} W < ${v.performance} W).`,
|
|
510
559
|
);
|
|
511
560
|
} else {
|
|
512
|
-
this.log.debug(
|
|
561
|
+
this.log.debug(`"${v.name}" is already switched on – no action needed.`);
|
|
513
562
|
}
|
|
514
563
|
}
|
|
515
564
|
}
|
|
@@ -521,11 +570,12 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
521
570
|
.filter(v => v.ruletype === 'binary' || v.ruletype === 'heating')
|
|
522
571
|
.sort((a, b) => (b.priority || 1) - (a.priority || 1));
|
|
523
572
|
|
|
524
|
-
this.log.debug(
|
|
573
|
+
this.log.debug(`Switch-off check for ${sortedOff.length} binary/heating-consumers.`);
|
|
525
574
|
|
|
526
575
|
for (const v of sortedOff) {
|
|
527
576
|
const idx = this.consumerList.indexOf(v);
|
|
528
|
-
const
|
|
577
|
+
const safeName = this.name2id(v.name);
|
|
578
|
+
const id = `${this.namespace}.consumer.${idx}_${safeName}`;
|
|
529
579
|
const mode = await this.getStateAsync(`${id}.controlMode`);
|
|
530
580
|
if (!mode || mode.val !== 2) {
|
|
531
581
|
continue;
|
|
@@ -552,13 +602,13 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
552
602
|
if (v.alwaysOffAtTime && !withinWindow && isOn) {
|
|
553
603
|
if (v.timer && v.timerEnd && v.pendingAction === false) {
|
|
554
604
|
const remaining = Math.max(0, Math.round((v.timerEnd - Date.now()) / 1000));
|
|
555
|
-
this.log.debug(
|
|
605
|
+
this.log.debug(`Active timer for ${v.name}: ${remaining}s remaining`);
|
|
556
606
|
} else if (v.timer && v.timerEnd && v.pendingAction === true) {
|
|
557
607
|
clearTimeout(v.timer);
|
|
558
608
|
v.timer = null;
|
|
559
609
|
v.timerEnd = null;
|
|
560
610
|
v.pendingAction = null;
|
|
561
|
-
const channelId = `consumer.${idx}_${
|
|
611
|
+
const channelId = `consumer.${idx}_${safeName}`;
|
|
562
612
|
await this.setStateAsync(`${this.namespace}.${channelId}.onTimerRemaining`, {
|
|
563
613
|
val: 0,
|
|
564
614
|
ack: true,
|
|
@@ -567,14 +617,14 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
567
617
|
val: 0,
|
|
568
618
|
ack: true,
|
|
569
619
|
});
|
|
570
|
-
this.log.debug(
|
|
620
|
+
this.log.debug(`Switch-on timer for "${v.name}" canceled (AlwaysOff active).`);
|
|
571
621
|
this.log.debug(
|
|
572
|
-
|
|
622
|
+
`AlwaysOff active: "${v.name}" - time window expired, offDelay ${v.switchOffDelay || 0}s.`,
|
|
573
623
|
);
|
|
574
624
|
await this.switchConsumerWithDelay(v, false, v.switchOffDelay || 0);
|
|
575
625
|
} else {
|
|
576
626
|
this.log.debug(
|
|
577
|
-
|
|
627
|
+
`AlwaysOff activ: "${v.name}" - time window expired, offDelay ${v.switchOffDelay || 0}s.`,
|
|
578
628
|
);
|
|
579
629
|
await this.switchConsumerWithDelay(v, false, v.switchOffDelay || 0);
|
|
580
630
|
}
|
|
@@ -585,7 +635,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
585
635
|
if (v.enableDatapoint) {
|
|
586
636
|
const enableState = await this.getForeignStateAsync(v.enableDatapoint);
|
|
587
637
|
if (!enableState?.val) {
|
|
588
|
-
this.log.warn(
|
|
638
|
+
this.log.warn(`"${v.name}" is being switched off - hardware approval missing.`);
|
|
589
639
|
await this.switchConsumerWithDelay(v, false, 0);
|
|
590
640
|
continue;
|
|
591
641
|
}
|
|
@@ -593,7 +643,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
593
643
|
if (v.heartbeatDatapoint) {
|
|
594
644
|
const hbState = await this.getForeignStateAsync(v.heartbeatDatapoint);
|
|
595
645
|
if (!hbState?.val) {
|
|
596
|
-
this.log.warn(
|
|
646
|
+
this.log.warn(`"${v.name}" is being switched off - heartbeat missing.`);
|
|
597
647
|
await this.switchConsumerWithDelay(v, false, 0);
|
|
598
648
|
continue;
|
|
599
649
|
}
|
|
@@ -610,18 +660,18 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
610
660
|
v.timer = null;
|
|
611
661
|
v.timerEnd = null;
|
|
612
662
|
v.pendingAction = null;
|
|
613
|
-
const channelId = `consumer.${idx}_${
|
|
663
|
+
const channelId = `consumer.${idx}_${safeName}`;
|
|
614
664
|
await this.setStateAsync(`${this.namespace}.${channelId}.onTimerRemaining`, { val: 0, ack: true });
|
|
615
665
|
await this.setStateAsync(`${this.namespace}.${channelId}.offTimerRemaining`, { val: 0, ack: true });
|
|
616
|
-
this.log.debug(
|
|
666
|
+
this.log.debug(`Switch-off timer for "${v.name}" canceled (condition no longer valid).`);
|
|
617
667
|
}
|
|
618
668
|
|
|
619
669
|
if (!v.alwaysOffAtTime && (!withinWindow || gridUsage)) {
|
|
620
670
|
if (v.timer && v.timerEnd && v.pendingAction === false) {
|
|
621
671
|
const remaining = Math.max(0, Math.round((v.timerEnd - Date.now()) / 1000));
|
|
622
|
-
this.log.debug(
|
|
672
|
+
this.log.debug(`Active timer for ${v.name}: ${remaining}s remaining`);
|
|
623
673
|
} else {
|
|
624
|
-
this.log.debug(
|
|
674
|
+
this.log.debug(`Switching off: "${v.name}" - offDelay ${v.switchOffDelay || 0}s.`);
|
|
625
675
|
await this.switchConsumerWithDelay(v, false, v.switchOffDelay || 0);
|
|
626
676
|
}
|
|
627
677
|
}
|
|
@@ -641,9 +691,9 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
641
691
|
});
|
|
642
692
|
|
|
643
693
|
if (runningTimers.length > 0) {
|
|
644
|
-
this.log.debug(
|
|
694
|
+
this.log.debug(`Active timers: ${runningTimers.join(' | ')}`);
|
|
645
695
|
} else {
|
|
646
|
-
this.log.debug('
|
|
696
|
+
this.log.debug('No active timers.');
|
|
647
697
|
}
|
|
648
698
|
} catch (err) {
|
|
649
699
|
this.log.error(`Error in checkConsumers: ${err.message}`);
|
|
@@ -660,13 +710,13 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
660
710
|
try {
|
|
661
711
|
const withinWindow = this.timeWithinWindow(v.switchOnTime, v.switchOffTime);
|
|
662
712
|
if (!withinWindow) {
|
|
663
|
-
this.log.debug(`[Percent] ${v.name}
|
|
713
|
+
this.log.debug(`[Percent] ${v.name} outside time window, set to 0%`);
|
|
664
714
|
await this.setForeignStateAsync(v.datapoint, 0);
|
|
665
715
|
return;
|
|
666
716
|
}
|
|
667
717
|
|
|
668
718
|
if (!this.feedInDatapoint) {
|
|
669
|
-
this.log.error('
|
|
719
|
+
this.log.error('feedInDatapoint not set!');
|
|
670
720
|
await this.sendNotification('smartloadmanager', 'alert', '❌ feedInDatapoint ist nicht gesetzt!');
|
|
671
721
|
return;
|
|
672
722
|
}
|
|
@@ -696,7 +746,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
696
746
|
|
|
697
747
|
if (newPercent !== currentPercent) {
|
|
698
748
|
await this.setForeignStateAsync(v.datapoint, newPercent);
|
|
699
|
-
this.log.info(
|
|
749
|
+
this.log.info(`${v.name} set to ${newPercent}%`);
|
|
700
750
|
|
|
701
751
|
if (this.config.notifyPercent) {
|
|
702
752
|
await this.sendNotification(
|
|
@@ -706,10 +756,10 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
706
756
|
);
|
|
707
757
|
}
|
|
708
758
|
} else {
|
|
709
|
-
this.log.debug(`[Percent] ${v.name}
|
|
759
|
+
this.log.debug(`[Percent] ${v.name} remains at ${currentPercent}%`);
|
|
710
760
|
}
|
|
711
761
|
} catch (error) {
|
|
712
|
-
this.log.error(
|
|
762
|
+
this.log.error(`Error in controlPercentConsumer: ${error.message}`);
|
|
713
763
|
await this.sendNotification(
|
|
714
764
|
'smartloadmanager',
|
|
715
765
|
'alert',
|
|
@@ -720,24 +770,33 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
720
770
|
|
|
721
771
|
async controlBattery(v, feedIn) {
|
|
722
772
|
try {
|
|
723
|
-
this.log.debug(`[Battery]
|
|
773
|
+
this.log.debug(`[Battery] Checking for ${v.name}`);
|
|
724
774
|
|
|
725
775
|
const withinWindow = this.timeWithinWindow(v.switchOnTime, v.switchOffTime);
|
|
726
776
|
if (!withinWindow) {
|
|
727
|
-
this.log.debug(`[Battery] ${v.name}
|
|
777
|
+
this.log.debug(`[Battery] ${v.name} outside time window, set to 0`);
|
|
728
778
|
if (v.batterySetpoint) {
|
|
729
|
-
await this.setForeignStateAsync(v.batterySetpoint, {
|
|
779
|
+
await this.setForeignStateAsync(v.batterySetpoint, {
|
|
780
|
+
val: 0,
|
|
781
|
+
ack: true,
|
|
782
|
+
});
|
|
730
783
|
}
|
|
731
|
-
if (
|
|
732
|
-
await this.setForeignStateAsync(
|
|
784
|
+
if (this.batteryControlModeDatapoint) {
|
|
785
|
+
await this.setForeignStateAsync(this.batteryControlModeDatapoint, {
|
|
786
|
+
val: 0,
|
|
787
|
+
ack: true,
|
|
788
|
+
});
|
|
733
789
|
}
|
|
734
790
|
return;
|
|
735
791
|
}
|
|
736
792
|
|
|
737
793
|
if (!v.batterySetpoint) {
|
|
738
|
-
this.log.warn(`[Battery] ${v.name}
|
|
739
|
-
if (
|
|
740
|
-
await this.setForeignStateAsync(
|
|
794
|
+
this.log.warn(`[Battery] ${v.name} has no batterySetpoint`);
|
|
795
|
+
if (this.batteryControlModeDatapoint) {
|
|
796
|
+
await this.setForeignStateAsync(this.batteryControlModeDatapoint, {
|
|
797
|
+
val: 0,
|
|
798
|
+
ack: true,
|
|
799
|
+
});
|
|
741
800
|
}
|
|
742
801
|
return;
|
|
743
802
|
}
|
|
@@ -750,7 +809,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
750
809
|
soc = Number(socState?.val);
|
|
751
810
|
targetSoc = Number(targetSocState?.val);
|
|
752
811
|
if (isNaN(soc) || isNaN(targetSoc)) {
|
|
753
|
-
this.log.warn(`[Battery] ${v.name}:
|
|
812
|
+
this.log.warn(`[Battery] ${v.name}: invalid SOC or targetSOC`);
|
|
754
813
|
soc = null;
|
|
755
814
|
targetSoc = null;
|
|
756
815
|
}
|
|
@@ -777,8 +836,11 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
777
836
|
: -1;
|
|
778
837
|
|
|
779
838
|
if (powerToSet !== oldPower) {
|
|
780
|
-
await this.setForeignStateAsync(v.batterySetpoint, {
|
|
781
|
-
|
|
839
|
+
await this.setForeignStateAsync(v.batterySetpoint, {
|
|
840
|
+
val: powerToSet,
|
|
841
|
+
ack: true,
|
|
842
|
+
});
|
|
843
|
+
this.log.info(`Battery ${v.name}: charging power set to ${powerToSet}W`);
|
|
782
844
|
if (this.config.notifyBattery) {
|
|
783
845
|
await this.sendNotification(
|
|
784
846
|
'smartloadmanager',
|
|
@@ -787,12 +849,15 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
787
849
|
);
|
|
788
850
|
}
|
|
789
851
|
} else {
|
|
790
|
-
this.log.debug(`[Battery] ${v.name}
|
|
852
|
+
this.log.debug(`[Battery] ${v.name} charging power remains at ${oldPower}W`);
|
|
791
853
|
}
|
|
792
854
|
|
|
793
855
|
if (this.batteryControlModeDatapoint && modeToSet !== oldMode) {
|
|
794
|
-
await this.setForeignStateAsync(this.batteryControlModeDatapoint, {
|
|
795
|
-
|
|
856
|
+
await this.setForeignStateAsync(this.batteryControlModeDatapoint, {
|
|
857
|
+
val: modeToSet,
|
|
858
|
+
ack: true,
|
|
859
|
+
});
|
|
860
|
+
this.log.debug(`[Battery] ${v.name} mode changed from ${oldMode} to ${modeToSet}`);
|
|
796
861
|
if (this.config.notifyBattery) {
|
|
797
862
|
await this.sendNotification(
|
|
798
863
|
'smartloadmanager',
|
|
@@ -802,7 +867,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
802
867
|
}
|
|
803
868
|
}
|
|
804
869
|
} catch (error) {
|
|
805
|
-
this.log.error(`[Battery]
|
|
870
|
+
this.log.error(`[Battery] Error for ${v.name}: ${error.message}`);
|
|
806
871
|
await this.sendNotification(
|
|
807
872
|
'smartloadmanager',
|
|
808
873
|
'alert',
|
|
@@ -822,16 +887,28 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
822
887
|
|
|
823
888
|
if (consumer.datapoint) {
|
|
824
889
|
// Erst setzen
|
|
825
|
-
await this.setForeignStateAsync(consumer.datapoint, {
|
|
890
|
+
await this.setForeignStateAsync(consumer.datapoint, {
|
|
891
|
+
val: targetState,
|
|
892
|
+
ack: false,
|
|
893
|
+
});
|
|
826
894
|
// Danach sofort bestätigen (falls keine Rückmeldung vom Gerät kommt)
|
|
827
|
-
await this.setForeignStateAsync(consumer.datapoint, {
|
|
895
|
+
await this.setForeignStateAsync(consumer.datapoint, {
|
|
896
|
+
val: targetState,
|
|
897
|
+
ack: true,
|
|
898
|
+
});
|
|
828
899
|
}
|
|
829
900
|
|
|
830
901
|
if (consumer.numericDatapoint) {
|
|
831
902
|
const numVal = targetState ? 1 : 0;
|
|
832
|
-
await this.setForeignStateAsync(consumer.numericDatapoint, {
|
|
833
|
-
|
|
834
|
-
|
|
903
|
+
await this.setForeignStateAsync(consumer.numericDatapoint, {
|
|
904
|
+
val: numVal,
|
|
905
|
+
ack: false,
|
|
906
|
+
});
|
|
907
|
+
await this.setForeignStateAsync(consumer.numericDatapoint, {
|
|
908
|
+
val: numVal,
|
|
909
|
+
ack: true,
|
|
910
|
+
});
|
|
911
|
+
this.log.debug(`Numeric datapoint for "${consumer.name}" set to ${numVal}`);
|
|
835
912
|
}
|
|
836
913
|
|
|
837
914
|
const msg = `${consumer.name} wurde ${targetState ? 'eingeschaltet' : 'ausgeschaltet'}`;
|
|
@@ -856,7 +933,8 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
856
933
|
: consumer.switchOffDelay || 0;
|
|
857
934
|
|
|
858
935
|
const idx = this.consumerList.indexOf(consumer);
|
|
859
|
-
const
|
|
936
|
+
const safeName = this.name2id(consumer.name);
|
|
937
|
+
const channelId = `consumer.${idx}_${safeName}`;
|
|
860
938
|
const onTimerState = `${this.namespace}.${channelId}.onTimerRemaining`;
|
|
861
939
|
const offTimerState = `${this.namespace}.${channelId}.offTimerRemaining`;
|
|
862
940
|
|
|
@@ -885,7 +963,10 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
885
963
|
await this.setStateAsync(onTimerState, { val: remaining, ack: true });
|
|
886
964
|
await this.setStateAsync(offTimerState, { val: 0, ack: true });
|
|
887
965
|
} else {
|
|
888
|
-
await this.setStateAsync(offTimerState, {
|
|
966
|
+
await this.setStateAsync(offTimerState, {
|
|
967
|
+
val: remaining,
|
|
968
|
+
ack: true,
|
|
969
|
+
});
|
|
889
970
|
await this.setStateAsync(onTimerState, { val: 0, ack: true });
|
|
890
971
|
}
|
|
891
972
|
};
|
|
@@ -894,7 +975,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
894
975
|
clearInterval(consumer.timerTick);
|
|
895
976
|
consumer.timerTick = null;
|
|
896
977
|
}
|
|
897
|
-
consumer.timerTick =
|
|
978
|
+
consumer.timerTick = this.safeSetInterval(tick, 1000);
|
|
898
979
|
};
|
|
899
980
|
|
|
900
981
|
const doSwitch = async () => {
|
|
@@ -962,8 +1043,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
962
1043
|
await stopTimerTicker();
|
|
963
1044
|
};
|
|
964
1045
|
|
|
965
|
-
//
|
|
966
|
-
// Falls Timer läuft, aber Bedingung sich geändert hat → Timer abbrechen
|
|
1046
|
+
// Falls Timer läuft, aber Bedingung sich geändert hat → Timer abbrechen / anpassen
|
|
967
1047
|
if (consumer.timer) {
|
|
968
1048
|
// wenn Einschalt-Timer läuft, aber turnOn nicht mehr gilt → abbrechen
|
|
969
1049
|
if (consumer.pendingAction === true && !turnOn) {
|
|
@@ -990,7 +1070,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
990
1070
|
return;
|
|
991
1071
|
}
|
|
992
1072
|
|
|
993
|
-
// ansonsten Timer neu setzen
|
|
1073
|
+
// ansonsten Timer neu setzen (älteren abbrechen)
|
|
994
1074
|
clearTimeout(consumer.timer);
|
|
995
1075
|
consumer.timer = null;
|
|
996
1076
|
consumer.timerEnd = null;
|
|
@@ -1001,7 +1081,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
1001
1081
|
if (delay > 0) {
|
|
1002
1082
|
consumer.timerEnd = Date.now() + delay * 1000;
|
|
1003
1083
|
consumer.pendingAction = turnOn;
|
|
1004
|
-
consumer.timer =
|
|
1084
|
+
consumer.timer = this.safeSetTimeout(doSwitch, delay * 1000);
|
|
1005
1085
|
await startTimerTicker();
|
|
1006
1086
|
} else {
|
|
1007
1087
|
await doSwitch();
|
|
@@ -1017,7 +1097,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
1017
1097
|
// 1) Controller-Notification (nur wenn Option aktiv ist)
|
|
1018
1098
|
if (cfg.enableNotificationManager) {
|
|
1019
1099
|
await this.registerNotification(scope, category, message);
|
|
1020
|
-
this.log.debug(
|
|
1100
|
+
this.log.debug(`Controller-Notification [${scope}/${category}]: ${message}`);
|
|
1021
1101
|
}
|
|
1022
1102
|
|
|
1023
1103
|
// 2) Messenger-Nachrichten
|
|
@@ -1031,11 +1111,11 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
1031
1111
|
if (recipients.length > 0) {
|
|
1032
1112
|
recipients.forEach(user => {
|
|
1033
1113
|
this.sendTo(cfg.telegramInstance, { text: message, user });
|
|
1034
|
-
this.log.debug(
|
|
1114
|
+
this.log.debug(`Telegram → ${cfg.telegramInstance}/${user}: ${message}`);
|
|
1035
1115
|
});
|
|
1036
1116
|
} else {
|
|
1037
1117
|
this.sendTo(cfg.telegramInstance, message);
|
|
1038
|
-
this.log.debug(
|
|
1118
|
+
this.log.debug(`Telegram → ${cfg.telegramInstance}: ${message}`);
|
|
1039
1119
|
}
|
|
1040
1120
|
}
|
|
1041
1121
|
|
|
@@ -1045,7 +1125,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
1045
1125
|
title: 'SmartLoadManager',
|
|
1046
1126
|
message: message,
|
|
1047
1127
|
});
|
|
1048
|
-
this.log.debug(
|
|
1128
|
+
this.log.debug(`Gotify → ${cfg.gotifyInstance}: ${message}`);
|
|
1049
1129
|
}
|
|
1050
1130
|
|
|
1051
1131
|
// E-Mail
|
|
@@ -1061,14 +1141,14 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
1061
1141
|
text: message,
|
|
1062
1142
|
subject: 'SmartLoadManager',
|
|
1063
1143
|
});
|
|
1064
|
-
this.log.debug(
|
|
1144
|
+
this.log.debug(`Email → ${cfg.emailInstance}/${to}: ${message}`);
|
|
1065
1145
|
});
|
|
1066
1146
|
} else {
|
|
1067
1147
|
this.sendTo(cfg.emailInstance, {
|
|
1068
1148
|
text: message,
|
|
1069
1149
|
subject: 'SmartLoadManager',
|
|
1070
1150
|
});
|
|
1071
|
-
this.log.debug(
|
|
1151
|
+
this.log.debug(`Email → ${cfg.emailInstance}: ${message}`);
|
|
1072
1152
|
}
|
|
1073
1153
|
}
|
|
1074
1154
|
|
|
@@ -1081,11 +1161,11 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
1081
1161
|
if (recipients.length > 0) {
|
|
1082
1162
|
recipients.forEach(user => {
|
|
1083
1163
|
this.sendTo(cfg.whatsappInstance, { text: message, user });
|
|
1084
|
-
this.log.debug(
|
|
1164
|
+
this.log.debug(`WhatsApp → ${cfg.whatsappInstance}/${user}: ${message}`);
|
|
1085
1165
|
});
|
|
1086
1166
|
} else {
|
|
1087
1167
|
this.sendTo(cfg.whatsappInstance, { text: message });
|
|
1088
|
-
this.log.debug(
|
|
1168
|
+
this.log.debug(`WhatsApp → ${cfg.whatsappInstance}: ${message}`);
|
|
1089
1169
|
}
|
|
1090
1170
|
}
|
|
1091
1171
|
|
|
@@ -1098,11 +1178,11 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
1098
1178
|
if (recipients.length > 0) {
|
|
1099
1179
|
recipients.forEach(user => {
|
|
1100
1180
|
this.sendTo(cfg.signalInstance, { text: message, user });
|
|
1101
|
-
this.log.debug(
|
|
1181
|
+
this.log.debug(`Signal → ${cfg.signalInstance}/${user}: ${message}`);
|
|
1102
1182
|
});
|
|
1103
1183
|
} else {
|
|
1104
1184
|
this.sendTo(cfg.signalInstance, { text: message });
|
|
1105
|
-
this.log.debug(
|
|
1185
|
+
this.log.debug(`Signal → ${cfg.signalInstance}: ${message}`);
|
|
1106
1186
|
}
|
|
1107
1187
|
}
|
|
1108
1188
|
|
|
@@ -1119,25 +1199,26 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
1119
1199
|
title: 'SmartLoadManager',
|
|
1120
1200
|
user,
|
|
1121
1201
|
});
|
|
1122
|
-
this.log.debug(
|
|
1202
|
+
this.log.debug(`Pushover → ${cfg.pushoverInstance}/${user}: ${message}`);
|
|
1123
1203
|
});
|
|
1124
1204
|
} else {
|
|
1125
1205
|
this.sendTo(cfg.pushoverInstance, {
|
|
1126
1206
|
message: message,
|
|
1127
1207
|
title: 'SmartLoadManager',
|
|
1128
1208
|
});
|
|
1129
|
-
this.log.debug(
|
|
1209
|
+
this.log.debug(`Pushover → ${cfg.pushoverInstance}: ${message}`);
|
|
1130
1210
|
}
|
|
1131
1211
|
}
|
|
1132
1212
|
} catch (e) {
|
|
1133
|
-
this.log.warn(
|
|
1213
|
+
this.log.warn(`Error sending notification: ${e.message}`);
|
|
1134
1214
|
}
|
|
1135
1215
|
}
|
|
1136
1216
|
|
|
1137
1217
|
async initializeConsumerStatus() {
|
|
1138
1218
|
// Initiale Status-Updates
|
|
1139
1219
|
for (const v of this.consumerList) {
|
|
1140
|
-
const
|
|
1220
|
+
const safeName = this.name2id(v.name);
|
|
1221
|
+
const channelId = `consumer.${this.consumerList.indexOf(v)}_${safeName}`;
|
|
1141
1222
|
const modeState = await this.getStateAsync(`${this.namespace}.${channelId}.controlMode`);
|
|
1142
1223
|
if (!modeState) {
|
|
1143
1224
|
await this.setStateAsync(`${this.namespace}.${channelId}.controlMode`, {
|
|
@@ -1149,7 +1230,7 @@ class ZeroFeedIn extends utils.Adapter {
|
|
|
1149
1230
|
}
|
|
1150
1231
|
|
|
1151
1232
|
sleep(ms) {
|
|
1152
|
-
return new Promise(resolve =>
|
|
1233
|
+
return new Promise(resolve => this.safeSetTimeout(resolve, ms, 'sleep'));
|
|
1153
1234
|
}
|
|
1154
1235
|
|
|
1155
1236
|
parseTimeToMinutes(timeStr) {
|