iobroker.poolcontrol 1.3.14 → 1.3.15

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
@@ -188,6 +188,23 @@ New features are added regularly – please refer to the changelog.
188
188
  ---
189
189
 
190
190
  ## Changelog
191
+ ### 1.3.15 (2026-05-08)
192
+
193
+ - Added speech source cooldown handling for solar and time announcements
194
+ - Added configurable `speech.sources.*` states for source-based speech control
195
+ - Reduced excessive solar speech notifications during unstable weather conditions
196
+ - Added persistent numeric runtime second states:
197
+ - `runtime.total_seconds`
198
+ - `runtime.today_seconds`
199
+ - `runtime.current_session_seconds`
200
+ - `runtime.season_total_seconds`
201
+ - Improved runtime restore handling using numeric fallback logic
202
+ - Fixed live runtime display consistency for total, today and season runtimes
203
+ - Improved season runtime handling using `status.season_active`
204
+ - Converted runtime helper timers to ioBroker adapter timer methods
205
+ - Improved runtime timer cleanup and reset protection
206
+ - Improved speech logging for skipped and cooldown-limited announcements
207
+
191
208
  ### 1.3.14 (2026-05-08)
192
209
 
193
210
  - Improved runtime handling and persistence
@@ -270,37 +287,6 @@ New features are added regularly – please refer to the changelog.
270
287
  - improves separation of solar control modes
271
288
  - stabilizes speech output behavior
272
289
 
273
- ### 1.3.10 (2026-05-01)
274
-
275
- New: Photovoltaic Insights
276
- - Introduced a new analytics module `analytics.insights.photovoltaic`
277
- - Tracks PV-based pump runtime, energy usage and estimated savings
278
- - New helper: `photovoltaicInsightsHelper`
279
- - New states: inputs, calculation, results, debug
280
- - Includes summary outputs (text, JSON, HTML)
281
- - Fully integrated with i18n translations
282
-
283
- Improvement: Active Helper Handling
284
- - Added consistent `pump.active_helper` ownership handling for:
285
- - photovoltaicHelper
286
- - solarHelper
287
- - solarExtendedHelper
288
- - Each helper now:
289
- - sets its own identifier when controlling the pump
290
- - releases it when stopping
291
- - does not override other active helpers
292
- - Ensures correct priority handling and prevents conflicts
293
-
294
- Improvement: PV Runtime Evaluation
295
- - Photovoltaic runtime is now only counted when:
296
- - PV surplus is active
297
- - AND photovoltaicHelper actually owns the pump
298
- - Enables accurate runtime, energy and savings calculation
299
-
300
- Fix: PV Circulation Logic
301
- - Fixed issue where pump stopped despite `photovoltaic.ignore_on_circulation = false`
302
- - Circulation check is now only applied when explicitly enabled
303
-
304
290
  ## Support
305
291
  - [ioBroker Forum](https://forum.iobroker.net/)
306
292
  - [GitHub Issues](https://github.com/DasBo1975/ioBroker.poolcontrol/issues)
package/io-package.json CHANGED
@@ -1,8 +1,21 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "poolcontrol",
4
- "version": "1.3.14",
4
+ "version": "1.3.15",
5
5
  "news": {
6
+ "1.3.15": {
7
+ "en": "Added speech source cooldown handling, improved solar/time speech control, added persistent runtime second states, improved runtime restore logic and converted runtime timers to ioBroker adapter timers.",
8
+ "de": "Sprachquellen mit Cooldown-Steuerung ergänzt, Solar-/Zeit-Sprachsteuerung verbessert, persistente Runtime-Sekundenstates hinzugefügt, Runtime-Wiederherstellung verbessert und Runtime-Timer auf ioBroker-Adapter-Timer umgestellt.",
9
+ "ru": "Добавлена ​​обработка перезарядки источника речи, улучшено управление речью по солнечной энергии и времени, добавлены постоянные секунды времени выполнения, улучшена логика восстановления времени выполнения и преобразованы таймеры времени выполнения в таймеры адаптера ioBroker.",
10
+ "pt": "Adicionado tratamento de resfriamento da fonte de fala, controle de fala solar/tempo aprimorado, segundos estados de tempo de execução persistentes adicionados, lógica de restauração de tempo de execução aprimorada e temporizadores de tempo de execução convertidos em temporizadores de adaptador ioBroker.",
11
+ "nl": "Afkoeling van spraakbronnen toegevoegd, verbeterde spraakcontrole op zonne-energie/tijd, persistente tweede runtime-statussen toegevoegd, verbeterde runtime-herstellogica en geconverteerde runtime-timers naar ioBroker-adaptertimers.",
12
+ "fr": "Ajout de la gestion du temps de recharge de la source vocale, du contrôle vocal solaire/temporel amélioré, ajout des seconds états d'exécution persistants, amélioration de la logique de restauration de l'exécution et conversion des minuteries d'exécution en minuteries d'adaptateur ioBroker.",
13
+ "it": "Aggiunta la gestione del raffreddamento della sorgente vocale, controllo vocale solare/ora migliorato, aggiunti secondi stati di runtime persistenti, logica di ripristino del runtime migliorata e timer di runtime convertiti in timer dell'adattatore ioBroker.",
14
+ "es": "Se agregó manejo de enfriamiento de la fuente de voz, control de voz solar/tiempo mejorado, se agregaron segundos estados de tiempo de ejecución persistentes, lógica de restauración de tiempo de ejecución mejorada y temporizadores de tiempo de ejecución convertidos en temporizadores de adaptador ioBroker.",
15
+ "pl": "Dodano obsługę schładzania źródła mowy, ulepszoną kontrolę mowy w czasie słonecznym/czasem, dodano trwałe drugie stany czasu wykonania, ulepszoną logikę przywracania w czasie wykonywania i przekonwertowano liczniki czasu działania na liczniki czasu adaptera ioBroker.",
16
+ "uk": "Додано обробку перезарядки джерела мовлення, покращено керування мовленням із сонячними променями/часом, додано постійні другі стани під час виконання, покращено логіку відновлення під час виконання та перетворено таймери часу виконання на таймери адаптера ioBroker.",
17
+ "zh-cn": "添加了语音源冷却处理、改进了太阳/时间语音控制、添加了持久运行时第二状态、改进了运行时恢复逻辑并将运行时计时器转换为 ioBroker 适配器计时器。"
18
+ },
6
19
  "1.3.14": {
7
20
  "en": "Improved runtime handling and persistence. Fixed season runtime calculation to use the correct season state, improved live runtime updates, added robust numeric runtime second states for safer persistence and recovery, and converted runtime timers to adapter-managed timers for better ioBroker compatibility.",
8
21
  "de": "Laufzeit-Handling und Persistenz verbessert. Saisonlaufzeit nutzt jetzt den korrekten Saison-Status, Live-Laufzeiten wurden vereinheitlicht, robuste Sekunden-States fuer Laufzeiten zur sicheren Wiederherstellung hinzugefuegt und Runtime-Timer auf adapterverwaltete Timer fuer bessere ioBroker-Kompatibilitaet umgestellt.",
@@ -54,19 +67,6 @@
54
67
  "pl": "Nowość: Dodano moduł oceny pH (chemistry.ph) z ręcznym i zewnętrznym wprowadzaniem danych, walidacją, obsługą miejsca pomiaru i zaleceniami. Nowość: Dodano moduł oceny TDS (chemistry.tds) z analizą trendów (24h, 7d, 30d), śledzeniem referencji i wynikami podsumowującymi (tekst/JSON/HTML). Poprawka: rozwiązano problem z przełączaniem mowy słonecznej między trybem standardowym i rozszerzonym. solarExtendedHelper nie zastępuje już mowy.solar_active w trybie standardowym.",
55
68
  "uk": "Нове: додано модуль оцінки pH (chemistry.ph) із ручним і зовнішнім введенням, перевіркою, обробкою місця вимірювання та рекомендаціями. Нове: додано модуль оцінки TDS (chemistry.tds) з ​​аналізом тенденцій (24 години, 7 днів, 30 днів), відстеженням посилань і підсумковими виходами (текст/JSON/HTML). Виправлення: вирішено проблему перемикання сонячної мови між стандартним і розширеним режимами. solarExtendedHelper більше не перезаписує speak.solar_active у стандартному режимі.",
56
69
  "zh-cn": "新增内容:添加了 pH 评估模块 (chemistry.ph),具有手动和外部输入、验证、测量位置处理和建议。新增内容:添加了 TDS 评估模块 (chemistry.tds),具有趋势分析(24 小时、7 天、30 天)、参考跟踪和摘要输出(文本/JSON/HTML)。修复:解决了标准模式和扩展模式之间的太阳能语音切换问题。在标准模式下,solarExtendedHelper 不再覆盖pepe.solar_active。"
57
- },
58
- "1.3.10": {
59
- "en": "Added photovoltaic insights (runtime, energy, savings) with new analytics states and helper. Improved active_helper ownership handling across photovoltaic, solar and extended solar helpers. Fixed PV circulation logic when ignore_on_circulation is disabled.",
60
- "de": "Photovoltaik-Einblicke (Laufzeit, Energie, Einsparungen) mit neuen Analysezuständen und Hilfsfunktionen hinzugefügt. Verbesserte Handhabung des Active_Helper-Besitzes für Photovoltaik-, Solar- und erweiterte Solar-Helfer. Die PV-Zirkulationslogik wurde korrigiert, wenn „ignore_on_circulation“ deaktiviert ist.",
61
- "ru": "Добавлены данные по фотоэлектрической энергии (время работы, энергия, экономия) с новыми аналитическими состояниями и помощником. Улучшено управление владением active_helper для фотоэлектрических, солнечных и расширенных солнечных помощников. Исправлена ​​логика циркуляции PV, когда ignore_on_circulation отключен.",
62
- "pt": "Adicionados insights fotovoltaicos (tempo de execução, energia, economia) com novos estados analíticos e auxiliares. Melhor gerenciamento de propriedade de active_helper em ajudantes fotovoltaicos, solares e solares estendidos. Lógica de circulação fotovoltaica corrigida quando ignore_on_circulation está desativado.",
63
- "nl": "Fotovoltaïsche inzichten toegevoegd (runtime, energie, besparingen) met nieuwe analysestatussen en helper. Verbeterde afhandeling van active_helper-eigendom voor fotovoltaïsche, zonne-energie en uitgebreide zonne-helpers. Vaste PV-circulatielogica wanneer negeer_on_circulatie is uitgeschakeld.",
64
- "fr": "Ajout d'informations photovoltaïques (durée de fonctionnement, énergie, économies) avec de nouveaux états d'analyse et une nouvelle aide. Amélioration de la gestion de la propriété active_helper pour les assistants photovoltaïques, solaires et solaires étendus. Correction de la logique de circulation PV lorsque ignore_on_circulation est désactivé.",
65
- "it": "Aggiunti approfondimenti sul fotovoltaico (autonomia, energia, risparmio) con nuovi stati di analisi e supporto. Migliorata la gestione della proprietà di active_helper tra gli helper fotovoltaici, solari e solari estesi. Risolta la logica di circolazione FV quando ignore_on_circulation è disabilitato.",
66
- "es": "Se agregaron conocimientos fotovoltaicos (tiempo de ejecución, energía, ahorros) con nuevos estados analíticos y ayuda. Se mejoró el manejo de la propiedad de active_helper en los asistentes fotovoltaicos, solares y solares extendidos. Se corrigió la lógica de circulación de PV cuando ignore_on_circulation estaba deshabilitado.",
67
- "pl": "Dodano statystyki fotowoltaiczne (czas pracy, energia, oszczędności) z nowymi stanami analitycznymi i pomocą. Ulepszona obsługa własności active_helper w przypadku fotowoltaiki, energii słonecznej i rozszerzonych pomocników energii słonecznej. Naprawiono logikę cyrkulacji PV, gdy ignorowanie_cyrkulacji jest wyłączone.",
68
- "uk": "Додано статистику фотоелектричної системи (час роботи, енергія, економія) з новими аналітичними станами та помічником. Покращено керування правами власності active_helper на фотоелектричні, сонячні та розширені сонячні помічники. Виправлена ​​логіка циркуляції PV, коли ignore_on_circulation вимкнено.",
69
- "zh-cn": "通过新的分析状态和帮助器添加了光伏见解(运行时间、能源、节省)。改进了跨光伏、太阳能和扩展太阳能助手的 active_helper 所有权处理。修复了禁用ignore_on_circulation时的PV循环逻辑。"
70
70
  }
71
71
  },
72
72
  "titleLang": {
@@ -77,6 +77,14 @@ const speechTextHelper = {
77
77
  if (id.endsWith('solar.collector_warning')) {
78
78
  const val = !!state.val;
79
79
 
80
+ const warnSpeech = !!(await this.adapter.getStateAsync('solar.warn_speech'))?.val;
81
+ if (!warnSpeech) {
82
+ this.adapter.log.debug(
83
+ '[speechTextHelper] Solar warning speech skipped (solar.warn_speech=false).',
84
+ );
85
+ return;
86
+ }
87
+
80
88
  if (val) {
81
89
  // Neue Warnung aktiv
82
90
  const collectorTemp = Number(
@@ -100,6 +108,8 @@ const speechTextHelper = {
100
108
  // --- NEU: Reaktion auf Solarsteuerung ---
101
109
  if (id.endsWith('speech.solar_active')) {
102
110
  const val = !!state.val;
111
+ const canSpeak = await this._canSendFromSource('solar');
112
+
103
113
  // Pumpenstatus aktualisieren, damit auch im VIS korrekt sichtbar
104
114
  if (val) {
105
115
  await this.adapter.setStateAsync('pump.status', {
@@ -114,12 +124,20 @@ const speechTextHelper = {
114
124
  }
115
125
  if (val) {
116
126
  const text = 'Die Poolpumpe wurde durch die Solarsteuerung eingeschaltet.';
117
- await this._sendSpeech(text);
118
- this.adapter.log.debug('[speechTextHelper] Solar control activated → announcement sent.');
127
+ const sent = await this._sendSpeechFromSource('solar', text, canSpeak);
128
+ this.adapter.log.debug(
129
+ sent
130
+ ? '[speechTextHelper] Solar control activated → announcement sent.'
131
+ : '[speechTextHelper] Solar control activated → announcement skipped.',
132
+ );
119
133
  } else {
120
134
  const text = 'Solarsteuerung beendet – Poolpumpe ausgeschaltet.';
121
- await this._sendSpeech(text);
122
- this.adapter.log.debug('[speechTextHelper] Solar control deactivated → announcement sent.');
135
+ const sent = await this._sendSpeechFromSource('solar', text, canSpeak);
136
+ this.adapter.log.debug(
137
+ sent
138
+ ? '[speechTextHelper] Solar control deactivated → announcement sent.'
139
+ : '[speechTextHelper] Solar control deactivated → announcement skipped.',
140
+ );
123
141
  }
124
142
  return;
125
143
  }
@@ -127,6 +145,7 @@ const speechTextHelper = {
127
145
  // --- NEU: Reaktion auf Zeitsteuerung ---
128
146
  if (id.endsWith('speech.time_active')) {
129
147
  const val = !!state.val;
148
+ const canSpeak = await this._canSendFromSource('time');
130
149
 
131
150
  // Pumpenstatus mitpflegen
132
151
  if (val) {
@@ -135,16 +154,24 @@ const speechTextHelper = {
135
154
  ack: true,
136
155
  });
137
156
  const text = 'Die Poolpumpe wurde durch die Zeitsteuerung eingeschaltet.';
138
- await this._sendSpeech(text);
139
- this.adapter.log.debug('[speechTextHelper] Time control activated → announcement sent.');
157
+ const sent = await this._sendSpeechFromSource('time', text, canSpeak);
158
+ this.adapter.log.debug(
159
+ sent
160
+ ? '[speechTextHelper] Time control activated → announcement sent.'
161
+ : '[speechTextHelper] Time control activated → announcement skipped.',
162
+ );
140
163
  } else {
141
164
  await this.adapter.setStateAsync('pump.status', {
142
165
  val: 'AUS (Zeitsteuerung beendet)',
143
166
  ack: true,
144
167
  });
145
168
  const text = 'Zeitsteuerung beendet – Poolpumpe ausgeschaltet.';
146
- await this._sendSpeech(text);
147
- this.adapter.log.debug('[speechTextHelper] Time control deactivated → announcement sent.');
169
+ const sent = await this._sendSpeechFromSource('time', text, canSpeak);
170
+ this.adapter.log.debug(
171
+ sent
172
+ ? '[speechTextHelper] Time control deactivated → announcement sent.'
173
+ : '[speechTextHelper] Time control deactivated → announcement skipped.',
174
+ );
148
175
  }
149
176
  return;
150
177
  }
@@ -155,6 +182,54 @@ const speechTextHelper = {
155
182
  }
156
183
  },
157
184
 
185
+ async _canSendFromSource(source) {
186
+ const enabled = !!(await this.adapter.getStateAsync(`speech.sources.${source}.enabled`))?.val;
187
+ if (!enabled) {
188
+ this.adapter.log.debug(`[speechTextHelper] Speech source "${source}" is disabled.`);
189
+ return false;
190
+ }
191
+
192
+ const cooldownMinutes = Number(
193
+ (await this.adapter.getStateAsync(`speech.sources.${source}.cooldown_minutes`))?.val || 0,
194
+ );
195
+ if (cooldownMinutes <= 0) {
196
+ return true;
197
+ }
198
+
199
+ const lastSentRaw = (await this.adapter.getStateAsync(`speech.sources.${source}.last_sent`))?.val;
200
+ const lastSentTs = Date.parse(String(lastSentRaw || ''));
201
+
202
+ if (!Number.isFinite(lastSentTs)) {
203
+ return true;
204
+ }
205
+
206
+ const elapsedMs = Date.now() - lastSentTs;
207
+ const cooldownMs = cooldownMinutes * 60 * 1000;
208
+
209
+ if (elapsedMs < cooldownMs) {
210
+ this.adapter.log.debug(
211
+ `[speechTextHelper] Speech source "${source}" skipped by cooldown (${cooldownMinutes} min).`,
212
+ );
213
+ return false;
214
+ }
215
+
216
+ return true;
217
+ },
218
+
219
+ async _sendSpeechFromSource(source, text, canSpeak) {
220
+ if (!canSpeak) {
221
+ return false;
222
+ }
223
+
224
+ await this._sendSpeech(text);
225
+ await this.adapter.setStateAsync(`speech.sources.${source}.last_sent`, {
226
+ val: new Date().toISOString(),
227
+ ack: true,
228
+ });
229
+
230
+ return true;
231
+ },
232
+
158
233
  /**
159
234
  * Sendet Text an speech.queue.
160
235
  *
@@ -285,6 +285,157 @@ async function createSpeechStates(adapter) {
285
285
 
286
286
  adapter.log.debug('[speechStates] Amazon Alexa quiet-time states checked and created.');
287
287
 
288
+ // ------------------------------------------------------------------
289
+ // FIX: Speech sources - user configurable message sources
290
+ // ------------------------------------------------------------------
291
+
292
+ await adapter.setObjectNotExistsAsync('speech.sources', {
293
+ type: 'channel',
294
+ common: {
295
+ name: {
296
+ en: 'Speech sources',
297
+ de: 'Sprachquellen',
298
+ },
299
+ },
300
+ native: {},
301
+ });
302
+
303
+ const speechSources = [
304
+ {
305
+ id: 'solar',
306
+ name: {
307
+ en: 'Solar control messages',
308
+ de: 'Solarsteuerung-Meldungen',
309
+ },
310
+ enabledName: {
311
+ en: 'Enable solar control messages',
312
+ de: 'Solarsteuerung-Meldungen aktivieren',
313
+ },
314
+ enabledDesc: {
315
+ en: 'Allows speech messages when the solar control switches the pump on or off',
316
+ de: 'Erlaubt Sprachmeldungen, wenn die Solarsteuerung die Pumpe ein- oder ausschaltet',
317
+ },
318
+ cooldownName: {
319
+ en: 'Solar message cooldown',
320
+ de: 'Solar-Meldungssperre',
321
+ },
322
+ cooldownDesc: {
323
+ en: 'Minimum time in minutes between solar control speech messages',
324
+ de: 'Mindestzeit in Minuten zwischen Solarsteuerung-Sprachmeldungen',
325
+ },
326
+ cooldownDefault: 30,
327
+ },
328
+ {
329
+ id: 'time',
330
+ name: {
331
+ en: 'Time control messages',
332
+ de: 'Zeitsteuerung-Meldungen',
333
+ },
334
+ enabledName: {
335
+ en: 'Enable time control messages',
336
+ de: 'Zeitsteuerung-Meldungen aktivieren',
337
+ },
338
+ enabledDesc: {
339
+ en: 'Allows speech messages when the time control switches the pump on or off',
340
+ de: 'Erlaubt Sprachmeldungen, wenn die Zeitsteuerung die Pumpe ein- oder ausschaltet',
341
+ },
342
+ cooldownName: {
343
+ en: 'Time control message cooldown',
344
+ de: 'Zeitsteuerung-Meldungssperre',
345
+ },
346
+ cooldownDesc: {
347
+ en: 'Minimum time in minutes between time control speech messages',
348
+ de: 'Mindestzeit in Minuten zwischen Zeitsteuerung-Sprachmeldungen',
349
+ },
350
+ cooldownDefault: 0,
351
+ },
352
+ ];
353
+
354
+ for (const source of speechSources) {
355
+ const baseId = `speech.sources.${source.id}`;
356
+
357
+ await adapter.setObjectNotExistsAsync(baseId, {
358
+ type: 'channel',
359
+ common: {
360
+ name: source.name,
361
+ },
362
+ native: {},
363
+ });
364
+
365
+ await adapter.setObjectNotExistsAsync(`${baseId}.enabled`, {
366
+ type: 'state',
367
+ common: {
368
+ name: source.enabledName,
369
+ desc: source.enabledDesc,
370
+ type: 'boolean',
371
+ role: 'switch',
372
+ read: true,
373
+ write: true,
374
+ def: true,
375
+ persist: true,
376
+ },
377
+ native: {},
378
+ });
379
+
380
+ const enabledState = await adapter.getStateAsync(`${baseId}.enabled`);
381
+ if (!enabledState || enabledState.val === null || enabledState.val === undefined) {
382
+ await adapter.setStateAsync(`${baseId}.enabled`, { val: true, ack: true });
383
+ }
384
+
385
+ await adapter.setObjectNotExistsAsync(`${baseId}.cooldown_minutes`, {
386
+ type: 'state',
387
+ common: {
388
+ name: source.cooldownName,
389
+ desc: source.cooldownDesc,
390
+ type: 'number',
391
+ role: 'level',
392
+ unit: 'min',
393
+ read: true,
394
+ write: true,
395
+ min: 0,
396
+ def: source.cooldownDefault,
397
+ persist: true,
398
+ },
399
+ native: {},
400
+ });
401
+
402
+ const cooldownState = await adapter.getStateAsync(`${baseId}.cooldown_minutes`);
403
+ if (!cooldownState || cooldownState.val === null || cooldownState.val === undefined) {
404
+ await adapter.setStateAsync(`${baseId}.cooldown_minutes`, {
405
+ val: source.cooldownDefault,
406
+ ack: true,
407
+ });
408
+ }
409
+
410
+ await adapter.setObjectNotExistsAsync(`${baseId}.last_sent`, {
411
+ type: 'state',
412
+ common: {
413
+ name: {
414
+ en: 'Last message sent',
415
+ de: 'Letzte gesendete Meldung',
416
+ },
417
+ desc: {
418
+ en: 'Timestamp of the last speech message for this source',
419
+ de: 'Zeitstempel der letzten Sprachmeldung dieser Quelle',
420
+ },
421
+ type: 'string',
422
+ role: 'value.time',
423
+ read: true,
424
+ write: false,
425
+ def: '',
426
+ persist: true,
427
+ },
428
+ native: {},
429
+ });
430
+
431
+ const lastSentState = await adapter.getStateAsync(`${baseId}.last_sent`);
432
+ if (!lastSentState || lastSentState.val === null || lastSentState.val === undefined) {
433
+ await adapter.setStateAsync(`${baseId}.last_sent`, { val: '', ack: true });
434
+ }
435
+ }
436
+
437
+ adapter.log.debug('[speechStates] Speech source states checked and created');
438
+
288
439
  // versteckte Dateien
289
440
 
290
441
  await adapter.setObjectNotExistsAsync('speech.solar_active', {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.poolcontrol",
3
- "version": "1.3.14",
3
+ "version": "1.3.15",
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",