iobroker.poolcontrol 0.6.0 → 0.6.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,20 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "poolcontrol",
4
- "version": "0.6.0",
4
+ "version": "0.6.1",
5
5
  "news": {
6
+ "0.6.1": {
7
+ "en": "Fixed false monthly reset when no last_reset date existed. Corrected real last_update timestamp in monthly statistics.",
8
+ "de": "Fehlerhaften Monatsreset ohne gültiges last_reset-Datum behoben. Korrigierter echter Zeitstempel last_update in der Monatsstatistik.",
9
+ "ru": "Исправлен неверный ежемесячный сброс без действительной даты last_reset. Исправлено обновление времени last_update в ежемесячной статистике.",
10
+ "pt": "Corrigido o reset mensal incorreto quando não havia data last_reset. Corrigido o timestamp real de last_update na estatística mensal.",
11
+ "nl": "Onjuiste maandelijkse reset opgelost wanneer er geen last_reset-datum was. Gecorrigeerde echte last_update-tijd in maandelijkse statistieken.",
12
+ "fr": "Correction du réinitialisation mensuelle erronée lorsqu'aucune date last_reset n'existait. Horodatage last_update réel corrigé dans les statistiques mensuelles.",
13
+ "it": "Corretto il reset mensile errato quando non esisteva una data last_reset. Corretto il timestamp reale last_update nelle statistiche mensili.",
14
+ "es": "Corregido el restablecimiento mensual erróneo cuando no existía una fecha last_reset. Corregida la marca de tiempo real last_update en las estadísticas mensuales.",
15
+ "pl": "Naprawiono błędny miesięczny reset, gdy nie istniała data last_reset. Poprawiono rzeczywisty znacznik czasu last_update w miesięcznych statystykach.",
16
+ "zh-cn": "修复了在不存在 last_reset 日期时错误的月度重置。修正了月度统计中的真实 last_update 时间戳。"
17
+ },
6
18
  "0.6.0": {
7
19
  "en": "Added complete photovoltaic control with automatic pump management (mode 'Automatik (PV)'). The adapter can now react to PV surplus based on configurable house consumption and generation values. Includes migration for existing installations. Improved system consistency and internal logging.",
8
20
  "de": "Vollständige Photovoltaik-Steuerung mit automatischer Pumpenlogik (Modus 'Automatik (PV)') hinzugefügt. Der Adapter reagiert nun auf PV-Überschuss anhand konfigurierbarer Hausverbrauchs- und Erzeugungswerte. Migration für bestehende Installationen integriert. Systemkonsistenz und interne Protokollierung verbessert.",
@@ -79,18 +91,6 @@
79
91
  "pl": "Rozszerzone statystyki tygodniowe i miesięczne z trwałymi danymi, ujednoliconym formatem JSON i ochroną przed ponowną instalacją.",
80
92
  "uk": "Розширена тижнева та місячна статистика з постійними даними, уніфікованим форматом JSON і захистом під час перевстановлення.",
81
93
  "zh-cn": "扩展的周和月统计,具有持久数据、统一的 JSON 格式和重新安装保护。"
82
- },
83
- "0.5.0": {
84
- "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.",
85
- "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.",
86
- "ru": "Добавлена еженедельная и ежемесячная статистика температуры в analytics.statistics.temperature.week и analytics.statistics.temperature.month с автоматическими сводками, независимыми помощниками и постоянными точками данных.",
87
- "fr": "Ajout des statistiques de température hebdomadaires et mensuelles sous analytics.statistics.temperature.week et analytics.statistics.temperature.month avec résumés automatiques, helpers indépendants et points de données persistants.",
88
- "it": "Aggiunte statistiche settimanali e mensili della temperatura in analytics.statistics.temperature.week e analytics.statistics.temperature.month con riepiloghi automatici, helper indipendenti e punti dati persistenti.",
89
- "es": "Se añadieron estadísticas semanales y mensuales de temperatura en analytics.statistics.temperature.week y analytics.statistics.temperature.month con resúmenes automáticos, ayudantes independientes y puntos de datos persistentes.",
90
- "nl": "Wekelijkse en maandelijkse temperatuurstatistieken toegevoegd onder analytics.statistics.temperature.week en analytics.statistics.temperature.month met automatische samenvattingen, onafhankelijke helpers en persistente gegevenspunten.",
91
- "pl": "Dodano tygodniowe i miesięczne statystyki temperatury w analytics.statistics.temperature.week i analytics.statistics.temperature.month z automatycznymi podsumowaniami, niezależnymi pomocnikami i trwałymi punktami danych.",
92
- "uk": "Додано щотижневу та щомісячну статистику температури в analytics.statistics.temperature.week та analytics.statistics.temperature.month з автоматичними зведеннями, незалежними помічниками та постійними точками даних.",
93
- "zh-cn": "在 analytics.statistics.temperature.week 和 analytics.statistics.temperature.month 中添加了每周和每月温度统计,具有自动摘要、独立助手和持久数据点。"
94
94
  }
95
95
  },
96
96
  "titleLang": {
@@ -9,7 +9,7 @@
9
9
  * - Wird beim Adapterstart einmalig ausgeführt.
10
10
  * - Korrigiert veraltete Definitionen (z. B. Schreibrechte, persist-Flags, etc.)
11
11
  *
12
- * Version: 1.0.2
12
+ * Version: 1.0.3
13
13
  */
14
14
 
15
15
  const migrationHelper = {
@@ -32,10 +32,7 @@ const migrationHelper = {
32
32
  await this._fixSpeechQueue();
33
33
  await this._fixSolarWarnActivePersist();
34
34
  await this._fixPumpModeStates(); // NEU: PV-Automatik hinzufügen
35
-
36
- // Weitere Routinen folgen hier später:
37
- // await this._ensurePumpReason();
38
- // await this._cleanupOldStates();
35
+ await this._removeInvalidResetButtons(); // NEU: Entfernt Week/Month-Reset-Buttons
39
36
 
40
37
  this.adapter.log.debug('[migrationHelper] Migration-Checks abgeschlossen.');
41
38
  } catch (err) {
@@ -48,17 +45,11 @@ const migrationHelper = {
48
45
  // ------------------------------------------------------
49
46
  // Migration: Schreibrecht für speech.queue korrigieren
50
47
  // ------------------------------------------------------
51
-
52
- /**
53
- * Prüft und korrigiert den State "speech.queue", falls er noch write:false gesetzt hat.
54
- * Dadurch verschwinden Warnungen beim Schreiben (Read-only state ... written without ack).
55
- */
56
48
  async _fixSpeechQueue() {
57
49
  const id = 'speech.queue';
58
50
  try {
59
51
  const obj = await this.adapter.getObjectAsync(id);
60
52
  if (!obj) {
61
- this.adapter.log.debug(`[migrationHelper] ${id} existiert nicht – keine Anpassung nötig.`);
62
53
  return;
63
54
  }
64
55
 
@@ -71,8 +62,6 @@ const migrationHelper = {
71
62
  desc: 'Nur intern durch den Adapter beschreibbar (nicht manuell ändern!)',
72
63
  },
73
64
  });
74
- } else {
75
- this.adapter.log.debug(`[migrationHelper] ${id} ist bereits korrekt konfiguriert.`);
76
65
  }
77
66
  } catch (err) {
78
67
  this.adapter.log.warn(`[migrationHelper] Fehler bei Prüfung von ${id}: ${err.message}`);
@@ -82,18 +71,11 @@ const migrationHelper = {
82
71
  // ------------------------------------------------------
83
72
  // Migration: persist-Flag für solar.warn_active ergänzen
84
73
  // ------------------------------------------------------
85
-
86
- /**
87
- * Ergänzt persist:true bei solar.warn_active,
88
- * damit die Einstellung (Warnfunktion aktivieren/deaktivieren)
89
- * nach einem Neustart erhalten bleibt.
90
- */
91
74
  async _fixSolarWarnActivePersist() {
92
75
  const id = 'solar.warn_active';
93
76
  try {
94
77
  const obj = await this.adapter.getObjectAsync(id);
95
78
  if (!obj) {
96
- this.adapter.log.debug(`[migrationHelper] ${id} existiert nicht – keine Anpassung nötig.`);
97
79
  return;
98
80
  }
99
81
 
@@ -106,8 +88,6 @@ const migrationHelper = {
106
88
  desc: `${obj.common?.desc || ''} (automatisch per Migration persistiert)`,
107
89
  },
108
90
  });
109
- } else {
110
- this.adapter.log.debug(`[migrationHelper] ${id} ist bereits mit persist:true versehen.`);
111
91
  }
112
92
  } catch (err) {
113
93
  this.adapter.log.warn(`[migrationHelper] Fehler bei Prüfung von ${id}: ${err.message}`);
@@ -117,18 +97,11 @@ const migrationHelper = {
117
97
  // ------------------------------------------------------
118
98
  // Migration: Ergänze neuen Pumpenmodus "Automatik (PV)"
119
99
  // ------------------------------------------------------
120
-
121
- /**
122
- * Prüft den State pump.mode und ergänzt, falls nötig, den neuen
123
- * Eintrag "auto_pv" → "Automatik (PV)".
124
- * Dadurch wird der PV-Modus automatisch in bestehenden Installationen sichtbar.
125
- */
126
100
  async _fixPumpModeStates() {
127
101
  const id = 'pump.mode';
128
102
  try {
129
103
  const obj = await this.adapter.getObjectAsync(id);
130
104
  if (!obj) {
131
- this.adapter.log.debug(`[migrationHelper] ${id} existiert nicht – keine Anpassung nötig.`);
132
105
  return;
133
106
  }
134
107
 
@@ -136,16 +109,53 @@ const migrationHelper = {
136
109
  if (!states.auto_pv) {
137
110
  states.auto_pv = 'Automatik (PV)';
138
111
  this.adapter.log.info(`[migrationHelper] Ergänze neuen Modus "Automatik (PV)" in pump.mode`);
139
- await this.adapter.extendObjectAsync(id, {
140
- common: { states },
141
- });
142
- } else {
143
- this.adapter.log.debug(`[migrationHelper] pump.mode enthält bereits "Automatik (PV)".`);
112
+ await this.adapter.extendObjectAsync(id, { common: { states } });
144
113
  }
145
114
  } catch (err) {
146
115
  this.adapter.log.warn(`[migrationHelper] Fehler bei Prüfung von ${id}: ${err.message}`);
147
116
  }
148
117
  },
118
+
119
+ // FIX: Entferne versehentlich angelegte Reset-Buttons aus Wochen- und Monatsstatistik
120
+ async _removeInvalidResetButtons() {
121
+ try {
122
+ const allObjs = await this.adapter.getAdapterObjectsAsync();
123
+ const keys = Object.keys(allObjs);
124
+ let removed = 0;
125
+
126
+ for (const id of keys) {
127
+ if (
128
+ (id.startsWith('analytics.statistics.temperature.week.') ||
129
+ id.startsWith('analytics.statistics.temperature.month.')) &&
130
+ id.endsWith('.reset_today')
131
+ ) {
132
+ try {
133
+ // Erst Statewert entfernen
134
+ await this.adapter.delStateAsync(id);
135
+ } catch {
136
+ this.adapter.log.debug(`[migrationHelper] Kein Statewert für ${id} vorhanden (Überspringe).`);
137
+ }
138
+
139
+ // Danach Objekt löschen (auch wenn persist=true)
140
+ try {
141
+ await this.adapter.delObjectAsync(id, { recursive: false });
142
+ this.adapter.log.info(`[migrationHelper] Veralteter Reset-Button entfernt: ${id}`);
143
+ removed++;
144
+ } catch (err) {
145
+ this.adapter.log.warn(`[migrationHelper] Konnte ${id} nicht löschen: ${err.message}`);
146
+ }
147
+ }
148
+ }
149
+
150
+ if (removed === 0) {
151
+ this.adapter.log.debug('[migrationHelper] Keine alten Reset-Buttons gefunden.');
152
+ } else {
153
+ this.adapter.log.info(`[migrationHelper] Insgesamt ${removed} alte Reset-Buttons entfernt.`);
154
+ }
155
+ } catch (err) {
156
+ this.adapter.log.warn(`[migrationHelper] Fehler beim Entfernen alter Reset-Buttons: ${err.message}`);
157
+ }
158
+ },
149
159
  };
150
160
 
151
161
  module.exports = migrationHelper;
@@ -152,18 +152,29 @@ const photovoltaicHelper = {
152
152
  return this._maybeStopPump(false, 0, 'mode_not_auto_pv');
153
153
  }
154
154
 
155
- // Optional: Umwälzung erreicht?
155
+ // FIX: PV-Helfer darf nur aktiv sein, solange Umwälzung noch nicht erfüllt ist
156
156
  if (ignoreOnCirc) {
157
157
  try {
158
158
  const remainingState = await this.adapter.getForeignStateAsync(
159
159
  'poolcontrol.0.circulation.daily_remaining',
160
160
  );
161
161
  const remaining = Number(remainingState?.val ?? NaN);
162
- if (Number.isFinite(remaining) && remaining <= 0) {
163
- this.adapter.log.debug(
164
- `[photovoltaicHelper] Tagesumwälzung erreicht (daily_remaining = ${remaining})PV-Steuerung ignoriert.`,
165
- );
166
- return this._maybeStopPump(false, afterrunMin, 'circulation_reached');
162
+
163
+ if (Number.isFinite(remaining)) {
164
+ // RULE: Wenn Umwälzung bereits erfülltPumpe sofort AUS (ohne Nachlauf)
165
+ if (remaining <= 0) {
166
+ this.adapter.log.info(
167
+ `[photovoltaicHelper] Tagesumwälzung erreicht (daily_remaining=${remaining}) → PV-Steuerung beendet, Pumpe AUS.`,
168
+ );
169
+ return this._maybeStopPump(true, 0, 'circulation_reached_force_off');
170
+ }
171
+
172
+ // RULE: Wenn Umwälzung noch nicht erfüllt → nur dann darf bei Überschuss eingeschaltet werden
173
+ if (remaining > 0 && surplusActive) {
174
+ this.adapter.log.debug(
175
+ `[photovoltaicHelper] Tagesumwälzung noch nicht erfüllt (${remaining}) → PV-Steuerung aktiv.`,
176
+ );
177
+ }
167
178
  }
168
179
  } catch (err) {
169
180
  this.adapter.log.debug(
@@ -172,10 +183,31 @@ const photovoltaicHelper = {
172
183
  }
173
184
  }
174
185
 
175
- // Schaltlogik
186
+ // FIX: PV-Schaltlogik mit Prüfung der Umwälzung
176
187
  if (surplusActive) {
177
- return this._maybeStartPump('pv_surplus');
188
+ try {
189
+ const remainingState = await this.adapter.getForeignStateAsync(
190
+ 'poolcontrol.0.circulation.daily_remaining',
191
+ );
192
+ const remaining = Number(remainingState?.val ?? NaN);
193
+
194
+ // RULE: Einschalten nur, wenn Umwälzung noch nicht erfüllt
195
+ if (Number.isFinite(remaining) && remaining <= 0) {
196
+ this.adapter.log.info(
197
+ `[photovoltaicHelper] Tagesumwälzung bereits erfüllt (${remaining}) → Pumpe bleibt AUS (kein Start trotz Überschuss).`,
198
+ );
199
+ return this._maybeStopPump(true, 0, 'circulation_already_reached');
200
+ }
201
+
202
+ // RULE: Überschuss aktiv UND Umwälzung noch nicht erfüllt → einschalten
203
+ return this._maybeStartPump('pv_surplus');
204
+ } catch (err) {
205
+ this.adapter.log.warn(`[photovoltaicHelper] Fehler beim Prüfen von daily_remaining: ${err.message}`);
206
+ return this._maybeStartPump('pv_surplus');
207
+ }
178
208
  }
209
+
210
+ // RULE: Kein Überschuss → ggf. Nachlauf/Aus
179
211
  return this._maybeStopPump(false, afterrunMin, 'pv_ended_afterrun');
180
212
  },
181
213
 
@@ -250,6 +250,12 @@ const statisticsHelperMonth = {
250
250
  });
251
251
 
252
252
  await this._updateOverallSummary();
253
+
254
+ // FIX: last_update korrigieren (echtes Aktualisierungsdatum)
255
+ await adapter.setStateAsync(`${basePath}.last_update`, {
256
+ val: new Date().toISOString(),
257
+ ack: true,
258
+ });
253
259
  },
254
260
 
255
261
  /**
@@ -385,6 +391,20 @@ const statisticsHelperMonth = {
385
391
  async _resetMonthlyTemperatureStats() {
386
392
  const adapter = this.adapter;
387
393
 
394
+ // 🟢 Neuer Logikblock: Monatsreset erfolgt nur, wenn wirklich neuer Monat begonnen hat
395
+ try {
396
+ const now = new Date();
397
+ const currentDay = now.getDate();
398
+
399
+ // Nur am 1. Tag des Monats ausführen (00:05 Uhr geplant)
400
+ if (currentDay !== 1) {
401
+ adapter.log.debug('[statisticsHelperMonth] Kein Monatsanfang – Reset übersprungen.');
402
+ return;
403
+ }
404
+ } catch (err) {
405
+ adapter.log.warn(`[statisticsHelperMonth] Fehler bei Monatsbeginn-Prüfung: ${err.message}`);
406
+ }
407
+
388
408
  // 🟢 NEU: Schutz vor Endlosschleifen und Mehrfachausführung
389
409
  if (this.isResetting) {
390
410
  adapter.log.debug('statisticsHelperMonth: Reset bereits aktiv – übersprungen.');
@@ -100,7 +100,6 @@ async function _createTemperatureStatsGroup(adapter, periodId, displayName) {
100
100
  { id: 'temp_avg', name: 'Durchschnittstemperatur', type: 'number', role: 'value.temperature', unit: '°C' },
101
101
  { id: 'data_points_count', name: 'Anzahl Messwerte', type: 'number', role: 'value' },
102
102
  { id: 'last_update', name: 'Letzte Aktualisierung', type: 'string', role: 'value.time' },
103
- { id: 'reset_today', name: 'Tagesstatistik zurücksetzen', type: 'boolean', role: 'button' },
104
103
  {
105
104
  id: 'summary_json',
106
105
  name: `${displayName} (JSON)`,
@@ -115,6 +114,16 @@ async function _createTemperatureStatsGroup(adapter, periodId, displayName) {
115
114
  },
116
115
  ];
117
116
 
117
+ // FIX: Reset-Button nur bei Tagesstatistik anlegen
118
+ if (periodId === 'today') {
119
+ stateDefs.push({
120
+ id: 'reset_today',
121
+ name: 'Tagesstatistik zurücksetzen',
122
+ type: 'boolean',
123
+ role: 'button',
124
+ });
125
+ }
126
+
118
127
  for (const def of stateDefs) {
119
128
  await adapter.setObjectNotExistsAsync(`${basePath}.${def.id}`, {
120
129
  type: 'state',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.poolcontrol",
3
- "version": "0.6.0",
3
+ "version": "0.6.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",