iobroker.poolcontrol 0.5.0 → 0.5.1
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/io-package.json
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "poolcontrol",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.1",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.5.1": {
|
|
7
|
+
"en": "Extended week and month statistics with persistent data, unified JSON format, and installation protection.",
|
|
8
|
+
"de": "Erweiterte Wochen- und Monatsstatistik mit persistenten Daten, einheitlichem JSON-Format und Überinstallationsschutz.",
|
|
9
|
+
"ru": "Расширенная недельная и месячная статистика с постоянными данными, унифицированным форматом JSON и защитой при переустановке.",
|
|
10
|
+
"pt": "Estatísticas semanais e mensais expandidas com dados persistentes, formato JSON unificado e proteção de reinstalação.",
|
|
11
|
+
"nl": "Uitgebreide week- en maandstatistieken met persistente gegevens, uniforme JSON-indeling en installatiebescherming.",
|
|
12
|
+
"fr": "Statistiques hebdomadaires et mensuelles étendues avec données persistantes, format JSON unifié et protection à la réinstallation.",
|
|
13
|
+
"it": "Statistiche settimanali e mensili estese con dati persistenti, formato JSON unificato e protezione dall'installazione.",
|
|
14
|
+
"es": "Estadísticas semanales y mensuales ampliadas con datos persistentes, formato JSON unificado y protección de reinstalación.",
|
|
15
|
+
"pl": "Rozszerzone statystyki tygodniowe i miesięczne z trwałymi danymi, ujednoliconym formatem JSON i ochroną przed ponowną instalacją.",
|
|
16
|
+
"uk": "Розширена тижнева та місячна статистика з постійними даними, уніфікованим форматом JSON і захистом під час перевстановлення.",
|
|
17
|
+
"zh-cn": "扩展的周和月统计,具有持久数据、统一的 JSON 格式和重新安装保护。"
|
|
18
|
+
},
|
|
6
19
|
"0.5.0": {
|
|
7
20
|
"en": "Added weekly and monthly temperature statistics under analytics.statistics.temperature.week and analytics.statistics.temperature.month with automatic summaries, independent helpers and persistent data points.",
|
|
8
21
|
"de": "Wöchentliche und monatliche Temperaturstatistiken unter analytics.statistics.temperature.week und analytics.statistics.temperature.month hinzugefügt – mit automatischen Zusammenfassungen, unabhängigen Helpern und persistenten Datenpunkten.",
|
|
@@ -52,18 +65,6 @@
|
|
|
52
65
|
"es": "Se añadió el cálculo del caudal real de la bomba, la monitorización en vivo y un sistema de rango normal autoaprendente para el análisis de la bomba.",
|
|
53
66
|
"pl": "Dodano obliczanie rzeczywistego przepływu pompy, monitorowanie na żywo i samouczący się system normalnego zakresu do analizy pompy.",
|
|
54
67
|
"zh-cn": "添加了实际泵流量计算、实时监控以及用于泵分析的自学习正常范围系统。"
|
|
55
|
-
},
|
|
56
|
-
"0.2.2": {
|
|
57
|
-
"en": "Added automatic backwash reminder with speech and log notifications.",
|
|
58
|
-
"de": "Automatische Rückspülerinnerung mit Sprach- und Log-Benachrichtigung hinzugefügt.",
|
|
59
|
-
"ru": "Добавлено автоматическое напоминание о обратной промывке с голосовыми и журнальными уведомлениями.",
|
|
60
|
-
"pt": "Adicionado lembrete automático de retrolavagem com notificações de voz e registro.",
|
|
61
|
-
"nl": "Automatische terugspoelherinnering toegevoegd met spraak- en logmeldingen.",
|
|
62
|
-
"fr": "Ajout d’un rappel automatique de contre-lavage avec notifications vocales et journaux.",
|
|
63
|
-
"it": "Aggiunto promemoria automatico di controlavaggio con notifiche vocali e log.",
|
|
64
|
-
"es": "Recordatorio automático de contralavado añadido con notificaciones de voz y registro.",
|
|
65
|
-
"pl": "Dodano automatyczne przypomnienie o płukaniu wstecznym z powiadomieniami głosowymi i dziennikiem.",
|
|
66
|
-
"zh-cn": "添加了带语音和日志通知的自动反冲洗提醒。"
|
|
67
68
|
}
|
|
68
69
|
},
|
|
69
70
|
"titleLang": {
|
|
@@ -33,6 +33,14 @@ const statisticsHelper = {
|
|
|
33
33
|
this.adapter = adapter;
|
|
34
34
|
adapter.log.debug('statisticsHelper: Initialisierung gestartet.');
|
|
35
35
|
|
|
36
|
+
// --- Überinstallationsschutz ---
|
|
37
|
+
try {
|
|
38
|
+
// Prüft, ob alle States vorhanden sind, und legt fehlende still neu an
|
|
39
|
+
await this._verifyStructure();
|
|
40
|
+
} catch {
|
|
41
|
+
// keine Log-Ausgabe – stiller Schutz
|
|
42
|
+
}
|
|
43
|
+
|
|
36
44
|
try {
|
|
37
45
|
await this._createTemperatureStatistics();
|
|
38
46
|
await this._subscribeActiveSensors();
|
|
@@ -227,12 +235,16 @@ const statisticsHelper = {
|
|
|
227
235
|
await adapter.setStateAsync(`${basePath}.data_points_count`, { val: newCount, ack: true });
|
|
228
236
|
await adapter.setStateAsync(`${basePath}.last_update`, { val: now, ack: true });
|
|
229
237
|
|
|
230
|
-
// Summary aktualisieren
|
|
231
|
-
// NEU: Zusammenfassung mit gerundeten Werten (1 Nachkommastelle)
|
|
238
|
+
// Summary aktualisieren – erweitert um Datum, Zeitpunkte, Messanzahl, Name
|
|
232
239
|
const summary = {
|
|
240
|
+
name: 'Tagesstatistik',
|
|
241
|
+
date: new Date().toISOString().slice(0, 10),
|
|
233
242
|
temp_min: newMin,
|
|
243
|
+
temp_min_time: (await adapter.getStateAsync(`${basePath}.temp_min_time`))?.val || '',
|
|
234
244
|
temp_max: newMax,
|
|
245
|
+
temp_max_time: (await adapter.getStateAsync(`${basePath}.temp_max_time`))?.val || '',
|
|
235
246
|
temp_avg: newAvg,
|
|
247
|
+
data_points_count: newCount,
|
|
236
248
|
updated: now,
|
|
237
249
|
};
|
|
238
250
|
await adapter.setStateAsync(`${basePath}.summary_json`, { val: JSON.stringify(summary), ack: true });
|
|
@@ -246,7 +258,7 @@ const statisticsHelper = {
|
|
|
246
258
|
},
|
|
247
259
|
|
|
248
260
|
/**
|
|
249
|
-
* Gesamt-HTML/JSON-Ausgabe aktualisieren (
|
|
261
|
+
* Gesamt-HTML/JSON-Ausgabe aktualisieren (erweiterte Version)
|
|
250
262
|
* Liest die fertigen summary_json-Werte aller aktiven Sensoren aus
|
|
251
263
|
* und erstellt daraus eine zusammengefasste HTML- und JSON-Ausgabe.
|
|
252
264
|
*/
|
|
@@ -257,10 +269,6 @@ const statisticsHelper = {
|
|
|
257
269
|
try {
|
|
258
270
|
// Alle Sensoren durchlaufen
|
|
259
271
|
for (const sensor of this.sensors) {
|
|
260
|
-
// const isActive = (await adapter.getStateAsync(`temperature.${sensor.id}.active`))?.val === true;
|
|
261
|
-
// if (!isActive) continue;
|
|
262
|
-
|
|
263
|
-
// Fertige Einzel-Summary des Sensors abrufen
|
|
264
272
|
const summaryState = await adapter.getStateAsync(
|
|
265
273
|
`analytics.statistics.temperature.today.${sensor.id}.summary_json`,
|
|
266
274
|
);
|
|
@@ -280,7 +288,12 @@ const statisticsHelper = {
|
|
|
280
288
|
const min = parsed.temp_min;
|
|
281
289
|
const max = parsed.temp_max;
|
|
282
290
|
const avg = parsed.temp_avg;
|
|
291
|
+
const date = parsed.date || '';
|
|
292
|
+
const minTime = parsed.temp_min_time || '';
|
|
293
|
+
const maxTime = parsed.temp_max_time || '';
|
|
294
|
+
const count = parsed.data_points_count || 0;
|
|
283
295
|
|
|
296
|
+
// Falls gar keine Werte vorhanden, überspringen
|
|
284
297
|
if (min == null && max == null && avg == null) {
|
|
285
298
|
continue;
|
|
286
299
|
}
|
|
@@ -290,11 +303,16 @@ const statisticsHelper = {
|
|
|
290
303
|
const rMax = typeof max === 'number' ? Math.round(max * 10) / 10 : max;
|
|
291
304
|
const rAvg = typeof avg === 'number' ? Math.round(avg * 10) / 10 : avg;
|
|
292
305
|
|
|
306
|
+
// Erweiterte Datensammlung
|
|
293
307
|
allData.push({
|
|
294
308
|
name: sensor.name,
|
|
309
|
+
date,
|
|
295
310
|
min: rMin,
|
|
311
|
+
min_time: minTime,
|
|
296
312
|
max: rMax,
|
|
313
|
+
max_time: maxTime,
|
|
297
314
|
avg: rAvg,
|
|
315
|
+
data_points_count: count,
|
|
298
316
|
});
|
|
299
317
|
}
|
|
300
318
|
|
|
@@ -311,14 +329,24 @@ const statisticsHelper = {
|
|
|
311
329
|
return;
|
|
312
330
|
}
|
|
313
331
|
|
|
314
|
-
// JSON-Ausgabe erstellen
|
|
315
|
-
const jsonOutput = JSON.stringify(allData);
|
|
332
|
+
// JSON-Ausgabe erstellen (komplett erweitert)
|
|
333
|
+
const jsonOutput = JSON.stringify(allData, null, 2);
|
|
316
334
|
|
|
317
|
-
// HTML-Ausgabe erstellen
|
|
335
|
+
// HTML-Ausgabe erstellen (mit Datum & Anzahl Messwerte)
|
|
318
336
|
let html = '<table style="width:100%;border-collapse:collapse;">';
|
|
319
|
-
html +=
|
|
337
|
+
html +=
|
|
338
|
+
'<tr><th style="text-align:left;">Sensor</th><th>Datum</th><th>Min</th><th>Zeit</th><th>Max</th><th>Zeit</th><th>Ø</th><th>Anz.</th></tr>';
|
|
320
339
|
for (const entry of allData) {
|
|
321
|
-
html += `<tr
|
|
340
|
+
html += `<tr>
|
|
341
|
+
<td>${entry.name}</td>
|
|
342
|
+
<td>${entry.date || '-'}</td>
|
|
343
|
+
<td>${entry.min ?? '-'}</td>
|
|
344
|
+
<td>${entry.min_time || '-'}</td>
|
|
345
|
+
<td>${entry.max ?? '-'}</td>
|
|
346
|
+
<td>${entry.max_time || '-'}</td>
|
|
347
|
+
<td>${entry.avg ?? '-'}</td>
|
|
348
|
+
<td>${entry.data_points_count ?? '-'}</td>
|
|
349
|
+
</tr>`;
|
|
322
350
|
}
|
|
323
351
|
html += '</table>';
|
|
324
352
|
|
|
@@ -331,10 +359,8 @@ const statisticsHelper = {
|
|
|
331
359
|
val: html,
|
|
332
360
|
ack: true,
|
|
333
361
|
});
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
} catch (err) {
|
|
337
|
-
adapter.log.warn(`statisticsHelper: Fehler bei Gesamtzusammenfassung: ${err.message}`);
|
|
362
|
+
} catch {
|
|
363
|
+
// bewusst kein Log hier – stiller Schutz
|
|
338
364
|
}
|
|
339
365
|
},
|
|
340
366
|
|
|
@@ -438,6 +464,18 @@ const statisticsHelper = {
|
|
|
438
464
|
adapter.log.debug('statisticsHelper: Tagesstatistik zurückgesetzt.');
|
|
439
465
|
},
|
|
440
466
|
|
|
467
|
+
/**
|
|
468
|
+
* Stiller Überinstallationsschutz:
|
|
469
|
+
* Prüft und legt fehlende States erneut an, ohne bestehende Werte zu überschreiben.
|
|
470
|
+
*/
|
|
471
|
+
async _verifyStructure() {
|
|
472
|
+
try {
|
|
473
|
+
await this._createTemperatureStatistics();
|
|
474
|
+
} catch {
|
|
475
|
+
// bewusst keine Logs – stiller Selbstschutz
|
|
476
|
+
}
|
|
477
|
+
},
|
|
478
|
+
|
|
441
479
|
cleanup() {
|
|
442
480
|
if (this.midnightTimer) {
|
|
443
481
|
clearTimeout(this.midnightTimer);
|
|
@@ -31,6 +31,13 @@ const statisticsHelperMonth = {
|
|
|
31
31
|
this.adapter = adapter;
|
|
32
32
|
adapter.log.debug('statisticsHelperMonth: Initialisierung gestartet.');
|
|
33
33
|
|
|
34
|
+
// --- Überinstallationsschutz ---
|
|
35
|
+
try {
|
|
36
|
+
await this._verifyStructure();
|
|
37
|
+
} catch {
|
|
38
|
+
// keine Log-Ausgabe – stiller Schutz
|
|
39
|
+
}
|
|
40
|
+
|
|
34
41
|
try {
|
|
35
42
|
await this._createTemperatureStatistics();
|
|
36
43
|
await this._subscribeActiveSensors();
|
|
@@ -224,9 +231,15 @@ const statisticsHelperMonth = {
|
|
|
224
231
|
await adapter.setStateAsync(`${basePath}.last_update`, { val: now, ack: true });
|
|
225
232
|
|
|
226
233
|
const summary = {
|
|
234
|
+
name: 'Monatsstatistik',
|
|
235
|
+
month_label: this._getCurrentMonthLabel(),
|
|
236
|
+
date: new Date().toISOString().slice(0, 10),
|
|
227
237
|
temp_min: newMin,
|
|
238
|
+
temp_min_time: (await adapter.getStateAsync(`${basePath}.temp_min_time`))?.val || '',
|
|
228
239
|
temp_max: newMax,
|
|
240
|
+
temp_max_time: (await adapter.getStateAsync(`${basePath}.temp_max_time`))?.val || '',
|
|
229
241
|
temp_avg: newAvg,
|
|
242
|
+
data_points_count: newCount,
|
|
230
243
|
updated: now,
|
|
231
244
|
};
|
|
232
245
|
await adapter.setStateAsync(`${basePath}.summary_json`, { val: JSON.stringify(summary), ack: true });
|
|
@@ -269,8 +282,22 @@ const statisticsHelperMonth = {
|
|
|
269
282
|
const rMin = typeof min === 'number' ? Math.round(min * 10) / 10 : min;
|
|
270
283
|
const rMax = typeof max === 'number' ? Math.round(max * 10) / 10 : max;
|
|
271
284
|
const rAvg = typeof avg === 'number' ? Math.round(avg * 10) / 10 : avg;
|
|
272
|
-
|
|
273
|
-
|
|
285
|
+
const date = parsed.date || '';
|
|
286
|
+
const minTime = parsed.temp_min_time || '';
|
|
287
|
+
const maxTime = parsed.temp_max_time || '';
|
|
288
|
+
const count = parsed.data_points_count || 0;
|
|
289
|
+
|
|
290
|
+
allData.push({
|
|
291
|
+
month_label: this._getCurrentMonthLabel(),
|
|
292
|
+
name: sensor.name,
|
|
293
|
+
date,
|
|
294
|
+
min: rMin,
|
|
295
|
+
min_time: minTime,
|
|
296
|
+
max: rMax,
|
|
297
|
+
max_time: maxTime,
|
|
298
|
+
avg: rAvg,
|
|
299
|
+
data_points_count: count,
|
|
300
|
+
});
|
|
274
301
|
}
|
|
275
302
|
|
|
276
303
|
if (allData.length === 0) {
|
|
@@ -407,6 +434,28 @@ const statisticsHelperMonth = {
|
|
|
407
434
|
adapter.log.debug('statisticsHelperMonth: Monatsstatistik zurückgesetzt.');
|
|
408
435
|
},
|
|
409
436
|
|
|
437
|
+
/**
|
|
438
|
+
* Stiller Überinstallationsschutz:
|
|
439
|
+
* Prüft und legt fehlende States erneut an, ohne bestehende Werte zu überschreiben.
|
|
440
|
+
*/
|
|
441
|
+
async _verifyStructure() {
|
|
442
|
+
try {
|
|
443
|
+
await this._createTemperatureStatistics();
|
|
444
|
+
} catch {
|
|
445
|
+
// bewusst keine Logs – stiller Selbstschutz
|
|
446
|
+
}
|
|
447
|
+
},
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Gibt den aktuellen Monat als lesbares Label zurück, z. B. "Oktober 2025".
|
|
451
|
+
*/
|
|
452
|
+
_getCurrentMonthLabel() {
|
|
453
|
+
const d = new Date();
|
|
454
|
+
const month = d.toLocaleString('de-DE', { month: 'long' });
|
|
455
|
+
const year = d.getFullYear();
|
|
456
|
+
return `${month.charAt(0).toUpperCase() + month.slice(1)} ${year}`;
|
|
457
|
+
},
|
|
458
|
+
|
|
410
459
|
cleanup() {
|
|
411
460
|
if (this.monthResetTimer) {
|
|
412
461
|
clearTimeout(this.monthResetTimer);
|
|
@@ -31,6 +31,14 @@ const statisticsHelperWeek = {
|
|
|
31
31
|
this.adapter = adapter;
|
|
32
32
|
adapter.log.debug('statisticsHelperWeek: Initialisierung gestartet.');
|
|
33
33
|
|
|
34
|
+
// --- Überinstallationsschutz ---
|
|
35
|
+
try {
|
|
36
|
+
// Prüft, ob alle States vorhanden sind, und legt fehlende still neu an
|
|
37
|
+
await this._verifyStructure();
|
|
38
|
+
} catch {
|
|
39
|
+
// keine Log-Ausgabe – stiller Schutz
|
|
40
|
+
}
|
|
41
|
+
|
|
34
42
|
try {
|
|
35
43
|
await this._createTemperatureStatistics();
|
|
36
44
|
await this._subscribeActiveSensors();
|
|
@@ -225,10 +233,17 @@ const statisticsHelperWeek = {
|
|
|
225
233
|
await adapter.setStateAsync(`${basePath}.data_points_count`, { val: newCount, ack: true });
|
|
226
234
|
await adapter.setStateAsync(`${basePath}.last_update`, { val: now, ack: true });
|
|
227
235
|
|
|
236
|
+
// Summary aktualisieren – erweitert um Datum, Zeitpunkte, Messanzahl, Name
|
|
228
237
|
const summary = {
|
|
238
|
+
name: 'Wochenstatistik',
|
|
239
|
+
week_range: this._getCurrentWeekRange(),
|
|
240
|
+
date: new Date().toISOString().slice(0, 10),
|
|
229
241
|
temp_min: newMin,
|
|
242
|
+
temp_min_time: (await adapter.getStateAsync(`${basePath}.temp_min_time`))?.val || '',
|
|
230
243
|
temp_max: newMax,
|
|
244
|
+
temp_max_time: (await adapter.getStateAsync(`${basePath}.temp_max_time`))?.val || '',
|
|
231
245
|
temp_avg: newAvg,
|
|
246
|
+
data_points_count: newCount,
|
|
232
247
|
updated: now,
|
|
233
248
|
};
|
|
234
249
|
await adapter.setStateAsync(`${basePath}.summary_json`, { val: JSON.stringify(summary), ack: true });
|
|
@@ -241,7 +256,7 @@ const statisticsHelperWeek = {
|
|
|
241
256
|
},
|
|
242
257
|
|
|
243
258
|
/**
|
|
244
|
-
*
|
|
259
|
+
* Gesamt-HTML/JSON-Ausgabe aktualisieren (erweiterte Version – Woche)
|
|
245
260
|
*/
|
|
246
261
|
async _updateOverallSummary() {
|
|
247
262
|
const adapter = this.adapter;
|
|
@@ -263,7 +278,14 @@ const statisticsHelperWeek = {
|
|
|
263
278
|
continue;
|
|
264
279
|
}
|
|
265
280
|
|
|
266
|
-
const
|
|
281
|
+
const min = parsed.temp_min;
|
|
282
|
+
const max = parsed.temp_max;
|
|
283
|
+
const avg = parsed.temp_avg;
|
|
284
|
+
const date = parsed.date || '';
|
|
285
|
+
const minTime = parsed.temp_min_time || '';
|
|
286
|
+
const maxTime = parsed.temp_max_time || '';
|
|
287
|
+
const count = parsed.data_points_count || 0;
|
|
288
|
+
|
|
267
289
|
if (min == null && max == null && avg == null) {
|
|
268
290
|
continue;
|
|
269
291
|
}
|
|
@@ -272,7 +294,17 @@ const statisticsHelperWeek = {
|
|
|
272
294
|
const rMax = typeof max === 'number' ? Math.round(max * 10) / 10 : max;
|
|
273
295
|
const rAvg = typeof avg === 'number' ? Math.round(avg * 10) / 10 : avg;
|
|
274
296
|
|
|
275
|
-
allData.push({
|
|
297
|
+
allData.push({
|
|
298
|
+
week_range: this._getCurrentWeekRange(),
|
|
299
|
+
name: sensor.name,
|
|
300
|
+
date,
|
|
301
|
+
min: rMin,
|
|
302
|
+
min_time: minTime,
|
|
303
|
+
max: rMax,
|
|
304
|
+
max_time: maxTime,
|
|
305
|
+
avg: rAvg,
|
|
306
|
+
data_points_count: count,
|
|
307
|
+
});
|
|
276
308
|
}
|
|
277
309
|
|
|
278
310
|
if (allData.length === 0) {
|
|
@@ -287,12 +319,22 @@ const statisticsHelperWeek = {
|
|
|
287
319
|
return;
|
|
288
320
|
}
|
|
289
321
|
|
|
290
|
-
const jsonOutput = JSON.stringify(allData);
|
|
322
|
+
const jsonOutput = JSON.stringify(allData, null, 2);
|
|
291
323
|
|
|
292
324
|
let html = '<table style="width:100%;border-collapse:collapse;">';
|
|
293
|
-
html +=
|
|
325
|
+
html +=
|
|
326
|
+
'<tr><th style="text-align:left;">Sensor</th><th>Datum</th><th>Min</th><th>Zeit</th><th>Max</th><th>Zeit</th><th>Ø</th><th>Anz.</th></tr>';
|
|
294
327
|
for (const entry of allData) {
|
|
295
|
-
html += `<tr
|
|
328
|
+
html += `<tr>
|
|
329
|
+
<td>${entry.name}</td>
|
|
330
|
+
<td>${entry.date || '-'}</td>
|
|
331
|
+
<td>${entry.min ?? '-'}</td>
|
|
332
|
+
<td>${entry.min_time || '-'}</td>
|
|
333
|
+
<td>${entry.max ?? '-'}</td>
|
|
334
|
+
<td>${entry.max_time || '-'}</td>
|
|
335
|
+
<td>${entry.avg ?? '-'}</td>
|
|
336
|
+
<td>${entry.data_points_count ?? '-'}</td>
|
|
337
|
+
</tr>`;
|
|
296
338
|
}
|
|
297
339
|
html += '</table>';
|
|
298
340
|
|
|
@@ -304,10 +346,8 @@ const statisticsHelperWeek = {
|
|
|
304
346
|
val: html,
|
|
305
347
|
ack: true,
|
|
306
348
|
});
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
} catch (err) {
|
|
310
|
-
adapter.log.warn(`statisticsHelperWeek: Fehler bei Gesamtzusammenfassung: ${err.message}`);
|
|
349
|
+
} catch {
|
|
350
|
+
// bewusst kein Log hier – stiller Schutz
|
|
311
351
|
}
|
|
312
352
|
},
|
|
313
353
|
|
|
@@ -412,6 +452,45 @@ const statisticsHelperWeek = {
|
|
|
412
452
|
adapter.log.debug('statisticsHelperWeek: Wochenstatistik zurückgesetzt.');
|
|
413
453
|
},
|
|
414
454
|
|
|
455
|
+
/**
|
|
456
|
+
* Stiller Überinstallationsschutz:
|
|
457
|
+
* Prüft und legt fehlende States erneut an, ohne bestehende Werte zu überschreiben.
|
|
458
|
+
*/
|
|
459
|
+
async _verifyStructure() {
|
|
460
|
+
try {
|
|
461
|
+
await this._createTemperatureStatistics();
|
|
462
|
+
} catch {
|
|
463
|
+
// bewusst keine Logs – stiller Selbstschutz
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Berechnet den Zeitraum (Start/Ende) der aktuellen Woche.
|
|
469
|
+
* Rückgabe: z. B. "27.10.2025 – 02.11.2025"
|
|
470
|
+
*/
|
|
471
|
+
_getCurrentWeekRange() {
|
|
472
|
+
const today = new Date();
|
|
473
|
+
|
|
474
|
+
// Aktuellen Sonntag (nächster Wochenreset) finden
|
|
475
|
+
const nextSunday = new Date(today);
|
|
476
|
+
const day = today.getDay(); // Sonntag=0, Montag=1 …
|
|
477
|
+
const daysUntilSunday = (7 - day) % 7;
|
|
478
|
+
nextSunday.setDate(today.getDate() + daysUntilSunday);
|
|
479
|
+
|
|
480
|
+
// Wochenstart ist der Montag vor diesem Sonntag
|
|
481
|
+
const monday = new Date(nextSunday);
|
|
482
|
+
monday.setDate(nextSunday.getDate() - 6);
|
|
483
|
+
|
|
484
|
+
const fmt = d =>
|
|
485
|
+
d.toLocaleDateString('de-DE', {
|
|
486
|
+
day: '2-digit',
|
|
487
|
+
month: '2-digit',
|
|
488
|
+
year: 'numeric',
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
return `${fmt(monday)} – ${fmt(nextSunday)}`;
|
|
492
|
+
},
|
|
493
|
+
|
|
415
494
|
cleanup() {
|
|
416
495
|
if (this.weekResetTimer) {
|
|
417
496
|
clearTimeout(this.weekResetTimer);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.poolcontrol",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
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",
|