iobroker.poolcontrol 0.0.10 → 0.1.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/README.md CHANGED
@@ -94,6 +94,18 @@ Funktionen können sich ändern, bitte regelmäßig den Changelog beachten.
94
94
  ## Changelog
95
95
  Auszug, vollständige Liste siehe `io-package.json`:
96
96
 
97
+ ### 0.1.1
98
+ - Fehlerbehebung: Endlosschleife zwischen `pump_switch` und externer Steckdose (`deviceId`) behoben, die bei bestimmten Smart-Steckdosen (z. B. Shelly, Tasmota, FritzDECT) auftreten konnte.
99
+ - Verbesserte Stabilität im `pumpHelper` durch interne Rückkopplungsprüfung.
100
+ - Keine Änderungen an bestehenden Konfigurationen erforderlich.
101
+
102
+ ### 0.1.0
103
+ - Sprachausgabe über **E-Mail** hinzugefügt (konfigurierbar: Instanz, Empfänger, Betreff).
104
+ - Erweiterung der Instanz-Konfiguration im Tab „Sprachausgaben“.
105
+ **Bugfixes**
106
+ - Kleinere Korrekturen und Optimierungen in der Dokumentation (`help.md`).
107
+ - Logging in `speechHelper` verbessert.
108
+
97
109
  ### 0.0.10
98
110
 
99
111
  Statusübersicht
@@ -124,12 +136,6 @@ Diese Datenpunkte sind besonders für **VIS/vis2, Alexa- oder Telegram-Ausgaben*
124
136
  ### 0.0.7
125
137
  - Help-Datei (`help.md`) und erste README-Version hinzugefügt
126
138
 
127
- ### 0.0.6
128
- - Verbrauchs- und Kostenberechnung mit externem kWh-Zähler
129
-
130
- ### 0.0.5
131
- - Sprachausgabe über Alexa und Telegram
132
-
133
139
  ### 0.0.1
134
140
  - initial release
135
141
 
@@ -49,6 +49,21 @@
49
49
  "lg": 3,
50
50
  "xl": 3,
51
51
  "newLine": true
52
+ },
53
+ "divider_season1": {
54
+ "type": "divider",
55
+ "newLine": true
56
+ },
57
+ "season_active": {
58
+ "type": "checkbox",
59
+ "label": "Poolsaison aktiv",
60
+ "default": false,
61
+ "xs": 12,
62
+ "sm": 3,
63
+ "md": 3,
64
+ "lg": 3,
65
+ "xl": 3,
66
+ "newLine": true
52
67
  }
53
68
  }
54
69
  },
@@ -543,7 +558,6 @@
543
558
  "md": 3,
544
559
  "lg": 3,
545
560
  "xl": 3,
546
- "newLine": true
547
561
  },
548
562
  "time2_end": {
549
563
  "type": "text",
@@ -831,6 +845,53 @@
831
845
  "lg": 6,
832
846
  "xl": 6
833
847
  },
848
+ "divider_speech_email": {
849
+ "type": "divider",
850
+ "newLine": true
851
+ },
852
+ "speech_email_enabled": {
853
+ "type": "checkbox",
854
+ "label": "Ausgabe über E-Mail aktivieren",
855
+ "default": false,
856
+ "xs": 12,
857
+ "sm": 3,
858
+ "md": 3,
859
+ "lg": 3,
860
+ "xl": 3,
861
+ "newLine": true
862
+ },
863
+ "speech_email_instance": {
864
+ "type": "instance",
865
+ "adapter": "email",
866
+ "label": "E-Mail Adapter-Instanz",
867
+ "default": "email.0",
868
+ "xs": 12,
869
+ "sm": 6,
870
+ "md": 6,
871
+ "lg": 6,
872
+ "xl": 6
873
+ },
874
+ "speech_email_recipient": {
875
+ "type": "text",
876
+ "label": "Empfänger-Adresse",
877
+ "default": "meineadresse@example.com",
878
+ "xs": 12,
879
+ "sm": 6,
880
+ "md": 6,
881
+ "lg": 6,
882
+ "xl": 6,
883
+ "newLine": true
884
+ },
885
+ "speech_email_subject": {
886
+ "type": "text",
887
+ "label": "E-Mail Betreff",
888
+ "default": "PoolControl Nachricht",
889
+ "xs": 12,
890
+ "sm": 6,
891
+ "md": 6,
892
+ "lg": 6,
893
+ "xl": 6
894
+ },
834
895
  "divider_speech4": {
835
896
  "type": "divider",
836
897
  "newLine": true
package/io-package.json CHANGED
@@ -1,8 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "poolcontrol",
4
- "version": "0.0.10",
4
+ "version": "0.1.1",
5
5
  "news": {
6
+ "0.1.1": {
7
+ "en": "Fixed endless loop between pump_switch and deviceId for some smart sockets",
8
+ "de": "Endlosschleife zwischen pump_switch und Steckdose (deviceId) behoben",
9
+ "ru": "Исправлен бесконечный цикл между pump_switch и deviceId для некоторых умных розеток",
10
+ "pt": "Corrigido loop infinito entre pump_switch e deviceId em algumas tomadas inteligentes",
11
+ "nl": "Eindeloze lus tussen pump_switch en deviceId voor sommige slimme stopcontacten opgelost",
12
+ "fr": "Correction d'une boucle infinie entre pump_switch et deviceId pour certaines prises intelligentes",
13
+ "it": "Corretto loop infinito tra pump_switch e deviceId per alcune prese intelligenti",
14
+ "es": "Corregido bucle infinito entre pump_switch y deviceId en algunos enchufes inteligentes",
15
+ "pl": "Naprawiono nieskończoną pętlę między pump_switch a deviceId dla niektórych inteligentnych gniazdek",
16
+ "uk": "Виправлено нескінченний цикл між pump_switch і deviceId для деяких розумних розеток",
17
+ "zh-cn": "修复了某些智能插座中 pump_switch 与 deviceId 之间的无限循环"
18
+ },
19
+ "0.1.0": {
20
+ "en": "Added speech output via E-Mail (configurable: instance, recipient, subject)",
21
+ "de": "Sprachausgabe per E-Mail hinzugefügt (konfigurierbar: Instanz, Empfänger, Betreff)",
22
+ "ru": "Добавлен вывод речи по электронной почте (настраивается: экземпляр, получатель, тема)",
23
+ "pt": "Adicionada saída de fala por e-mail (configurável: instância, destinatário, assunto)",
24
+ "nl": "Spraakuitvoer via e-mail toegevoegd (configureerbaar: instantie, ontvanger, onderwerp)",
25
+ "fr": "Ajout de la sortie vocale par e-mail (configurable : instance, destinataire, sujet)",
26
+ "it": "Aggiunta uscita vocale via e-mail (configurabile: istanza, destinatario, oggetto)",
27
+ "es": "Se agregó salida de voz por correo electrónico (configurable: instancia, destinatario, asunto)",
28
+ "pl": "Dodano wyjście głosowe przez e-mail (konfigurowalne: instancja, odbiorca, temat)",
29
+ "uk": "Додано озвучення електронною поштою (налаштовується: екземпляр, одержувач, тема)",
30
+ "zh-cn": "新增通过电子邮件的语音输出(可配置:实例、收件人、主题)"
31
+ },
6
32
  "0.0.10": {
7
33
  "en": "Added extended status overview with pump statistics, system flags and JSON summary",
8
34
  "de": "Erweiterte Statusübersicht mit Pumpenstatistiken, Systemanzeigen und JSON-Zusammenfassung hinzugefügt",
@@ -15,32 +41,6 @@
15
41
  "pl": "Dodano rozszerzony przegląd statusu ze statystykami pompy, flagami systemowymi i podsumowaniem JSON",
16
42
  "uk": "Додано розширений огляд статусу зі статистикою насоса, системними прапорцями та зведенням JSON",
17
43
  "zh-cn": "新增扩展状态概览,包括泵统计、系统标志和 JSON 摘要"
18
- },
19
- "0.0.9": {
20
- "en": "Made runtime, circulation, consumption/costs and temperature min/max states persistent across restarts",
21
- "de": "Laufzeit-, Umwälz-, Verbrauch-/Kosten- und Temperatur-Min/Max-States bleiben jetzt über Neustarts erhalten",
22
- "ru": "Состояния времени работы, циркуляции, потребления/стоимости и мин/макс температуры теперь сохраняются при перезапуске",
23
- "pt": "Estados de tempo de execução, circulação, consumo/custos e temperatura min/máx agora persistem após reinicializações",
24
- "nl": "Runtime-, circulatie-, verbruiks-/kosten- en temperatuur min/max-states blijven nu behouden bij herstart",
25
- "fr": "Les états de durée, de circulation, de consommation/coûts et de température min/max persistent désormais après redémarrage",
26
- "it": "Gli stati di runtime, circolazione, consumo/costi e temperatura min/max ora persistono ai riavvii",
27
- "es": "Los estados de tiempo de ejecución, circulación, consumo/costos y temperatura min/máx ahora persisten tras reinicios",
28
- "pl": "Stany czasu pracy, cyrkulacji, zużycia/kosztów i temp. min/max są teraz zachowane po restartach",
29
- "uk": "Стан часу роботи, циркуляції, споживання/вартості та мін/макс температури тепер зберігаються після перезапусків",
30
- "zh-cn": "运行时间、循环、消耗/成本和温度最小/最大状态现在在重启后保持"
31
- },
32
- "0.0.8": {
33
- "en": "Added Help tab in instance configuration with link to GitHub documentation",
34
- "de": "Hilfetab in der Instanzkonfiguration hinzugefügt mit Link zur GitHub-Dokumentation",
35
- "ru": "Добавлена вкладка помощи в настройке экземпляра со ссылкой на документацию GitHub",
36
- "pt": "Guia de ajuda adicionado na configuração da instância com link para a documentação do GitHub",
37
- "nl": "Help-tab toegevoegd in de instance-configuratie met link naar GitHub-documentatie",
38
- "fr": "Onglet d'aide ajouté dans la configuration de l'instance avec lien vers la documentation GitHub",
39
- "it": "Aggiunta scheda di aiuto nella configurazione dell'istanza con collegamento alla documentazione GitHub",
40
- "es": "Se agregó pestaña de ayuda en la configuración de la instancia con enlace a la documentación de GitHub",
41
- "pl": "Dodano kartę pomocy w konfiguracji instancji z linkiem do dokumentacji GitHub",
42
- "uk": "Додано вкладку довідки в конфігурацію екземпляра з посиланням на документацію GitHub",
43
- "zh-cn": "在实例配置中添加了帮助选项卡,并链接到 документацию GitHub"
44
44
  }
45
45
  },
46
46
  "titleLang": {
@@ -92,6 +92,15 @@ const pumpHelper = {
92
92
  return;
93
93
  }
94
94
 
95
+ // Saisonprüfung
96
+ const season = (await this.adapter.getStateAsync('status.season_active'))?.val;
97
+ if (!season) {
98
+ this.adapter.log.debug(
99
+ '[pumpHelper] Saison inaktiv – Pumpenlogik übersprungen (Frostschutz läuft separat)',
100
+ );
101
+ return;
102
+ }
103
+
95
104
  // 1) Leistung aus Fremd-State spiegeln
96
105
  if (this.currentPowerId && id === this.currentPowerId) {
97
106
  const val = this._parseNumber(state.val);
@@ -103,22 +112,28 @@ const pumpHelper = {
103
112
  return;
104
113
  }
105
114
 
106
- // 2) Fremde Steckdose hat sich verändert → in unseren bool-Schalter spiegeln
115
+ // 2) Fremde Steckdose hat sich verändert → in unseren bool-Schalter spiegeln (mit Loop-Schutz)
107
116
  if (this.deviceId && id === this.deviceId) {
108
117
  const val = !!state.val;
109
- await this.adapter.setStateAsync('pump.pump_switch', { val, ack: true });
110
- await this._updateStatus();
111
- await this._checkErrorConditions();
118
+ const current = (await this.adapter.getStateAsync('pump.pump_switch'))?.val;
119
+ if (current !== val) {
120
+ await this.adapter.setStateAsync('pump.pump_switch', { val, ack: true });
121
+ await this._updateStatus();
122
+ await this._checkErrorConditions();
123
+ }
112
124
  return;
113
125
  }
114
126
 
115
- // 3) Eigene Pumpen-States geändert
127
+ // 3) Eigene Pumpen-States geändert (mit Loop-Schutz bei Rückschreiben)
116
128
  if (id.endsWith('pump.mode') || id.endsWith('pump.pump_switch') || id.endsWith('pump.error')) {
117
129
  if (id.endsWith('pump.pump_switch') && this.deviceId) {
118
- await this.adapter.setForeignStateAsync(this.deviceId, {
119
- val: !!state.val,
120
- ack: false,
121
- });
130
+ const current = (await this.adapter.getForeignStateAsync(this.deviceId))?.val;
131
+ if (current !== !!state.val) {
132
+ await this.adapter.setForeignStateAsync(this.deviceId, {
133
+ val: !!state.val,
134
+ ack: false,
135
+ });
136
+ }
122
137
  }
123
138
 
124
139
  await this._updateStatus();
@@ -32,17 +32,14 @@ const solarHelper = {
32
32
 
33
33
  async _checkSolar() {
34
34
  try {
35
+ // --- NEU: Saisonstatus ---
36
+ const season = (await this.adapter.getStateAsync('status.season_active'))?.val;
37
+
35
38
  // Solarsteuerung aktiv?
36
39
  const active = (await this.adapter.getStateAsync('solar.solar_control_active'))?.val;
37
- if (!active) {
38
- return;
39
- }
40
40
 
41
- // Pumpenmodus muss AUTO sein
41
+ // Pumpenmodus
42
42
  const mode = (await this.adapter.getStateAsync('pump.mode'))?.val;
43
- if (mode !== 'auto') {
44
- return;
45
- }
46
43
 
47
44
  // Grenzwerte laden
48
45
  const tempOn = (await this.adapter.getStateAsync('solar.temp_on'))?.val;
@@ -58,32 +55,45 @@ const solarHelper = {
58
55
  return;
59
56
  }
60
57
 
61
- let shouldRun = false;
62
- const delta = collector - pool;
58
+ // --- Schaltlogik nur ausführen, wenn Saison aktiv, Solar aktiv und Modus AUTO ---
59
+ if (season && active && mode === 'auto') {
60
+ let shouldRun = false;
61
+ const delta = collector - pool;
63
62
 
64
- // Logik: Einschalten, wenn Collector > tempOn und Delta > 0
65
- if (collector >= tempOn && delta > 0) {
66
- shouldRun = true;
67
- }
63
+ // Logik: Einschalten, wenn Collector > tempOn und Delta > 0
64
+ if (collector >= tempOn && delta > 0) {
65
+ shouldRun = true;
66
+ }
68
67
 
69
- // Ausschalten, wenn Collector < tempOff oder Delta <= 0
70
- if (collector <= tempOff || delta <= 0) {
71
- shouldRun = false;
72
- }
68
+ // Ausschalten, wenn Collector < tempOff oder Delta <= 0
69
+ if (collector <= tempOff || delta <= 0) {
70
+ shouldRun = false;
71
+ }
73
72
 
74
- // Optional Hysterese (kann später erweitert werden)
75
- if (hysteresis) {
76
- // z. B. Ausschaltgrenze etwas absenken
77
- }
73
+ // Optional Hysterese (kann später erweitert werden)
74
+ if (hysteresis) {
75
+ // z. B. Ausschaltgrenze etwas absenken
76
+ }
78
77
 
79
- // ZENTRAL: Pumpe über Bool-Schalter setzen
80
- await this.adapter.setStateAsync('pump.pump_switch', {
81
- val: shouldRun,
82
- ack: false,
83
- });
84
- this.adapter.log.debug(
85
- `[solarHelper] Solarregelung → Pumpe ${shouldRun ? 'EIN' : 'AUS'} (Collector=${collector}°C, Pool=${pool}°C, Delta=${delta}°C)`,
86
- );
78
+ // ZENTRAL: Pumpe über Bool-Schalter setzen
79
+ await this.adapter.setStateAsync('pump.pump_switch', {
80
+ val: shouldRun,
81
+ ack: false,
82
+ });
83
+ this.adapter.log.debug(
84
+ `[solarHelper] Solarregelung → Pumpe ${shouldRun ? 'EIN' : 'AUS'} (Collector=${collector}°C, Pool=${pool}°C, Delta=${delta}°C)`,
85
+ );
86
+ } else {
87
+ // Keine Schaltung – Grund protokollieren
88
+ const reason = !season
89
+ ? 'Saison inaktiv'
90
+ : !active
91
+ ? 'Solarsteuerung aus'
92
+ : mode !== 'auto'
93
+ ? 'Pumpenmodus != auto'
94
+ : 'unbekannt';
95
+ this.adapter.log.debug(`[solarHelper] Solarregelung übersprungen (${reason})`);
96
+ }
87
97
 
88
98
  // --- Kollektor-Warnung ---
89
99
  const warnActive = (await this.adapter.getStateAsync('solar.warn_active'))?.val;
@@ -2,7 +2,7 @@
2
2
 
3
3
  /**
4
4
  * speechHelper
5
- * - Sendet Texte an Alexa und/oder Telegram
5
+ * - Sendet Texte an Alexa, Telegram und optional per E-Mail
6
6
  * - Verwendet Config (jsonConfig) + States aus speechStates.js
7
7
  */
8
8
 
@@ -95,6 +95,24 @@ const speechHelper = {
95
95
  });
96
96
  this.adapter.log.info(`[speechHelper] Telegram sendet: ${text}`);
97
97
  }
98
+
99
+ // E-Mail-Ausgabe
100
+ if (this.adapter.config.speech_email_enabled && this.adapter.config.speech_email_instance) {
101
+ const instance = this.adapter.config.speech_email_instance;
102
+ const sendState = `${instance}.mail`;
103
+
104
+ await this.adapter.setForeignStateAsync(sendState, {
105
+ val: {
106
+ to: this.adapter.config.speech_email_recipient,
107
+ subject: this.adapter.config.speech_email_subject || 'PoolControl Nachricht',
108
+ text: text,
109
+ },
110
+ ack: false,
111
+ });
112
+ this.adapter.log.info(
113
+ `[speechHelper] E-Mail gesendet an ${this.adapter.config.speech_email_recipient}: ${text}`,
114
+ );
115
+ }
98
116
  } catch (err) {
99
117
  this.adapter.log.warn(`[speechHelper] Fehler beim Sprechen: ${err.message}`);
100
118
  }
@@ -171,9 +171,9 @@ async function createStatusStates(adapter) {
171
171
  common: {
172
172
  name: 'Poolsaison aktiv',
173
173
  type: 'boolean',
174
- role: 'indicator',
174
+ role: 'switch',
175
175
  read: true,
176
- write: false,
176
+ write: true,
177
177
  },
178
178
  native: {},
179
179
  });
package/main.js CHANGED
@@ -65,6 +65,12 @@ class Poolcontrol extends utils.Adapter {
65
65
  // --- Statusübersicht ---
66
66
  await createStatusStates(this);
67
67
 
68
+ // Saisonstatus aus Config übernehmen
69
+ await this.setStateAsync('status.season_active', {
70
+ val: this.config.season_active,
71
+ ack: true,
72
+ });
73
+
68
74
  // --- Helper starten ---
69
75
  temperatureHelper.init(this);
70
76
  timeHelper.init(this);
@@ -113,12 +119,20 @@ class Poolcontrol extends utils.Adapter {
113
119
  }
114
120
  }
115
121
 
116
- onStateChange(id, state) {
122
+ async onStateChange(id, state) {
117
123
  if (state) {
118
124
  this.log.debug(`state ${id} changed: ${state.val} (ack = ${state.ack})`);
119
125
  } else {
120
126
  this.log.debug(`state ${id} deleted`);
121
127
  }
128
+
129
+ // Saisonstatus manuell ändern (z.B. über VIS)
130
+ if (id.endsWith('status.season_active') && state && state.ack === false) {
131
+ this.log.info(`[main] Saisonstatus geändert: ${state.val}`);
132
+ await this.setStateAsync('status.season_active', { val: state.val, ack: true });
133
+ return; // danach keine Helper mehr aufrufen
134
+ }
135
+
122
136
  try {
123
137
  temperatureHelper.handleStateChange(id, state);
124
138
  } catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.poolcontrol",
3
- "version": "0.0.10",
3
+ "version": "0.1.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",