iobroker.poolcontrol 1.3.1 → 1.3.3

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.
@@ -0,0 +1,616 @@
1
+ 'use strict';
2
+
3
+ const { I18n } = require('@iobroker/adapter-core');
4
+
5
+ /**
6
+ * solarLogbookHelper
7
+ * - Creates human-readable solar logbook entries for the current day
8
+ * - Uses existing solar insights states only
9
+ * - Writes JSON + text + HTML logbook outputs
10
+ * - Event-based with debounce
11
+ * - Keeps user-facing texts human-friendly
12
+ */
13
+
14
+ const solarLogbookHelper = {
15
+ adapter: null,
16
+ checkTimer: null,
17
+ resetTimer: null,
18
+
19
+ init(adapter) {
20
+ this.adapter = adapter;
21
+
22
+ void this._subscribeStates();
23
+ this._scheduleDailyReset();
24
+ this._scheduleCheck(0);
25
+
26
+ this.adapter.log.debug('[solarLogbookHelper] Initialized');
27
+ },
28
+
29
+ handleStateChange(id, state) {
30
+ if (!state || state.ack !== true) {
31
+ return;
32
+ }
33
+
34
+ if (!this._isRelevantState(id)) {
35
+ return;
36
+ }
37
+
38
+ this._scheduleCheck(250);
39
+ },
40
+
41
+ _scheduleCheck(delayMs = 0) {
42
+ if (this.checkTimer) {
43
+ this.adapter.clearTimeout(this.checkTimer);
44
+ this.checkTimer = null;
45
+ }
46
+
47
+ this.checkTimer = this.adapter.setTimeout(() => {
48
+ this.checkTimer = null;
49
+ void this._updateLogbook();
50
+ }, delayMs);
51
+ },
52
+
53
+ _scheduleDailyReset() {
54
+ if (this.resetTimer) {
55
+ this.adapter.clearTimeout(this.resetTimer);
56
+ this.resetTimer = null;
57
+ }
58
+
59
+ const now = new Date();
60
+ const next = new Date(now);
61
+ next.setDate(now.getDate() + 1);
62
+ next.setHours(0, 0, 10, 0);
63
+
64
+ const delay = Math.max(1000, next.getTime() - now.getTime());
65
+
66
+ this.resetTimer = this.adapter.setTimeout(async () => {
67
+ try {
68
+ await this.adapter.setStateChangedAsync('analytics.insights.solar.logbook.current_entry', {
69
+ val: '',
70
+ ack: true,
71
+ });
72
+
73
+ await this.adapter.setStateChangedAsync('analytics.insights.solar.logbook.current_entry_html', {
74
+ val: '',
75
+ ack: true,
76
+ });
77
+
78
+ await this.adapter.setStateChangedAsync('analytics.insights.solar.logbook.day_log_json', {
79
+ val: '[]',
80
+ ack: true,
81
+ });
82
+
83
+ await this.adapter.setStateChangedAsync('analytics.insights.solar.logbook.day_log_text', {
84
+ val: '',
85
+ ack: true,
86
+ });
87
+
88
+ await this.adapter.setStateChangedAsync('analytics.insights.solar.logbook.last_entry_time', {
89
+ val: '',
90
+ ack: true,
91
+ });
92
+
93
+ this.adapter.log.debug('[solarLogbookHelper] Daily reset executed');
94
+ } catch (err) {
95
+ this.adapter.log.warn(`[solarLogbookHelper] Daily reset failed: ${err.message}`);
96
+ }
97
+
98
+ this._scheduleDailyReset();
99
+ }, delay);
100
+ },
101
+
102
+ async _subscribeStates() {
103
+ const ids = [
104
+ 'analytics.insights.solar.results.solar_ran_today',
105
+ 'analytics.insights.solar.results.solar_effective_now',
106
+ 'analytics.insights.solar.results.solar_gain_state',
107
+ 'analytics.insights.solar.results.collector_temp_used',
108
+ 'analytics.insights.solar.results.pool_reference_temp_used',
109
+ 'analytics.insights.solar.results.delta_t_used',
110
+ 'analytics.insights.solar.results.outside_temp_used',
111
+ 'analytics.insights.solar.results.flow_lh_used',
112
+ 'analytics.insights.solar.results.pump_power_w_used',
113
+ 'analytics.insights.solar.results.estimated_thermal_power_w',
114
+ 'analytics.insights.solar.results.estimated_thermal_power_kw',
115
+ 'analytics.insights.solar.results.estimated_efficiency_ratio',
116
+ 'analytics.insights.solar.results.estimated_gain_today_wh',
117
+ 'analytics.insights.solar.results.estimated_gain_today_kwh',
118
+ 'analytics.insights.solar.results.active_minutes_today',
119
+ 'analytics.insights.solar.results.peak_power_today_w',
120
+
121
+ 'analytics.insights.solar.calculation.quality_level',
122
+ 'analytics.insights.solar.calculation.confidence_percent',
123
+ 'analytics.insights.solar.calculation.weather_correction_active',
124
+
125
+ 'analytics.insights.solar.inputs.used_sensors_text',
126
+
127
+ 'ai.weather.outputs.daily_summary',
128
+ ];
129
+
130
+ for (const id of ids) {
131
+ await this.adapter.subscribeStatesAsync(id);
132
+ }
133
+
134
+ this.adapter.log.debug('[solarLogbookHelper] Relevant states subscribed');
135
+ },
136
+
137
+ _isRelevantState(id) {
138
+ const ids = [
139
+ 'analytics.insights.solar.results.solar_ran_today',
140
+ 'analytics.insights.solar.results.solar_effective_now',
141
+ 'analytics.insights.solar.results.solar_gain_state',
142
+ 'analytics.insights.solar.results.collector_temp_used',
143
+ 'analytics.insights.solar.results.pool_reference_temp_used',
144
+ 'analytics.insights.solar.results.delta_t_used',
145
+ 'analytics.insights.solar.results.outside_temp_used',
146
+ 'analytics.insights.solar.results.flow_lh_used',
147
+ 'analytics.insights.solar.results.pump_power_w_used',
148
+ 'analytics.insights.solar.results.estimated_thermal_power_w',
149
+ 'analytics.insights.solar.results.estimated_thermal_power_kw',
150
+ 'analytics.insights.solar.results.estimated_efficiency_ratio',
151
+ 'analytics.insights.solar.results.estimated_gain_today_wh',
152
+ 'analytics.insights.solar.results.estimated_gain_today_kwh',
153
+ 'analytics.insights.solar.results.active_minutes_today',
154
+ 'analytics.insights.solar.results.peak_power_today_w',
155
+
156
+ 'analytics.insights.solar.calculation.quality_level',
157
+ 'analytics.insights.solar.calculation.confidence_percent',
158
+ 'analytics.insights.solar.calculation.weather_correction_active',
159
+
160
+ 'analytics.insights.solar.inputs.used_sensors_text',
161
+
162
+ 'ai.weather.outputs.daily_summary',
163
+ ];
164
+
165
+ return ids.some(relevantId => id === relevantId || id.endsWith(`.${relevantId}`));
166
+ },
167
+
168
+ async _updateLogbook() {
169
+ try {
170
+ const solarRanToday = await this._readBoolean('analytics.insights.solar.results.solar_ran_today');
171
+ const solarEffectiveNow = await this._readBoolean('analytics.insights.solar.results.solar_effective_now');
172
+
173
+ const collectorTemp = await this._readNumber('analytics.insights.solar.results.collector_temp_used');
174
+ const poolReferenceTemp = await this._readNumber(
175
+ 'analytics.insights.solar.results.pool_reference_temp_used',
176
+ );
177
+ const deltaTUsed = await this._readNumber('analytics.insights.solar.results.delta_t_used');
178
+ const outsideTemp = await this._readNumber('analytics.insights.solar.results.outside_temp_used');
179
+ const flowLhUsed = await this._readNumber('analytics.insights.solar.results.flow_lh_used');
180
+ const pumpPowerWUsed = await this._readNumber('analytics.insights.solar.results.pump_power_w_used');
181
+ const thermalPowerW = await this._readNumber('analytics.insights.solar.results.estimated_thermal_power_w');
182
+ const thermalPowerKW = await this._readNumber(
183
+ 'analytics.insights.solar.results.estimated_thermal_power_kw',
184
+ );
185
+ const efficiencyRatio = await this._readNumber(
186
+ 'analytics.insights.solar.results.estimated_efficiency_ratio',
187
+ );
188
+ const gainTodayWh = await this._readNumber('analytics.insights.solar.results.estimated_gain_today_wh');
189
+ const gainTodayKWh = await this._readNumber('analytics.insights.solar.results.estimated_gain_today_kwh');
190
+ const activeMinutesToday = await this._readNumber('analytics.insights.solar.results.active_minutes_today');
191
+ const peakPowerTodayW = await this._readNumber('analytics.insights.solar.results.peak_power_today_w');
192
+
193
+ const qualityLevel = await this._readString('analytics.insights.solar.calculation.quality_level');
194
+ const confidencePercent = await this._readNumber('analytics.insights.solar.calculation.confidence_percent');
195
+ const weatherCorrectionActive = await this._readBoolean(
196
+ 'analytics.insights.solar.calculation.weather_correction_active',
197
+ );
198
+
199
+ const usedSensorsText = await this._readString('analytics.insights.solar.inputs.used_sensors_text');
200
+ const weatherSummary = await this._readString('ai.weather.outputs.daily_summary');
201
+
202
+ const entry = this._buildHumanEntry({
203
+ solarRanToday,
204
+ solarEffectiveNow,
205
+ collectorTemp,
206
+ poolReferenceTemp,
207
+ deltaTUsed,
208
+ outsideTemp,
209
+ flowLhUsed,
210
+ pumpPowerWUsed,
211
+ thermalPowerW,
212
+ thermalPowerKW,
213
+ efficiencyRatio,
214
+ gainTodayWh,
215
+ gainTodayKWh,
216
+ activeMinutesToday,
217
+ peakPowerTodayW,
218
+ qualityLevel,
219
+ confidencePercent,
220
+ weatherCorrectionActive,
221
+ usedSensorsText,
222
+ weatherSummary,
223
+ });
224
+
225
+ const currentEntry = await this._readString('analytics.insights.solar.logbook.current_entry');
226
+
227
+ if (currentEntry === entry.text) {
228
+ return;
229
+ }
230
+
231
+ const now = new Date();
232
+ const nowIso = now.toISOString();
233
+ const timeLabel = this._formatTime(now);
234
+
235
+ const newLogItem = {
236
+ ts: nowIso,
237
+ time: timeLabel,
238
+ type: entry.type,
239
+ text: entry.text,
240
+ html: entry.html,
241
+ };
242
+
243
+ const dayLogJsonRaw = await this._readString('analytics.insights.solar.logbook.day_log_json');
244
+ const dayLog = this._safeParseArray(dayLogJsonRaw);
245
+
246
+ dayLog.push(newLogItem);
247
+
248
+ const trimmedLog = dayLog.slice(-100);
249
+
250
+ const dayLogText = trimmedLog.map(item => `${item.time} - ${item.text}`).join('\n');
251
+
252
+ await this.adapter.setStateChangedAsync('analytics.insights.solar.logbook.current_entry', {
253
+ val: entry.text,
254
+ ack: true,
255
+ });
256
+
257
+ await this.adapter.setStateChangedAsync('analytics.insights.solar.logbook.current_entry_html', {
258
+ val: entry.html,
259
+ ack: true,
260
+ });
261
+
262
+ await this.adapter.setStateChangedAsync('analytics.insights.solar.logbook.day_log_json', {
263
+ val: JSON.stringify(trimmedLog),
264
+ ack: true,
265
+ });
266
+
267
+ await this.adapter.setStateChangedAsync('analytics.insights.solar.logbook.day_log_text', {
268
+ val: dayLogText,
269
+ ack: true,
270
+ });
271
+
272
+ await this.adapter.setStateChangedAsync('analytics.insights.solar.logbook.last_entry_time', {
273
+ val: nowIso,
274
+ ack: true,
275
+ });
276
+
277
+ this.adapter.log.debug('[solarLogbookHelper] Logbook updated successfully');
278
+ } catch (err) {
279
+ this.adapter.log.warn(`[solarLogbookHelper] Error in update: ${err.message}`);
280
+ }
281
+ },
282
+
283
+ _buildHumanEntry(data) {
284
+ const {
285
+ solarRanToday,
286
+ solarEffectiveNow,
287
+ collectorTemp,
288
+ poolReferenceTemp,
289
+ deltaTUsed,
290
+ outsideTemp,
291
+ flowLhUsed,
292
+ pumpPowerWUsed,
293
+ thermalPowerW,
294
+ thermalPowerKW,
295
+ efficiencyRatio,
296
+ gainTodayWh,
297
+ gainTodayKWh,
298
+ activeMinutesToday,
299
+ peakPowerTodayW,
300
+ qualityLevel,
301
+ confidencePercent,
302
+ weatherCorrectionActive,
303
+ usedSensorsText,
304
+ weatherSummary,
305
+ } = data;
306
+
307
+ const sentences = [];
308
+ const usedSensors = usedSensorsText || this._t('solar_log_value_unknown');
309
+ const confidenceText = Number.isFinite(confidencePercent)
310
+ ? this._tf('solar_log_confidence_text', this._formatNumber(confidencePercent, 0))
311
+ : '';
312
+ const weatherTextShort = this._extractShortWeather(weatherSummary);
313
+
314
+ if (!solarRanToday) {
315
+ sentences.push(this._t('solar_log_text_no_runtime_today'));
316
+
317
+ if (weatherTextShort !== '') {
318
+ sentences.push(this._tf('solar_log_text_weather_short', weatherTextShort));
319
+ }
320
+
321
+ if (confidenceText !== '') {
322
+ sentences.push(confidenceText);
323
+ }
324
+
325
+ sentences.push(this._tf('solar_log_text_used_sensors', usedSensors));
326
+
327
+ const text = sentences.join(' ');
328
+ return {
329
+ type: 'no_runtime_today',
330
+ text,
331
+ html: this._escapeHtml(text),
332
+ };
333
+ }
334
+
335
+ if (solarEffectiveNow && Number.isFinite(thermalPowerKW) && thermalPowerKW > 0) {
336
+ sentences.push(this._tf('solar_log_text_active_effective', this._formatNumber(thermalPowerKW, 2)));
337
+ } else if (solarEffectiveNow) {
338
+ sentences.push(this._t('solar_log_text_active_without_clear_gain'));
339
+ } else {
340
+ sentences.push(this._t('solar_log_text_not_active_now'));
341
+ }
342
+
343
+ if (Number.isFinite(gainTodayKWh) && gainTodayKWh >= 3) {
344
+ sentences.push(this._tf('solar_log_text_good_day', this._formatNumber(gainTodayKWh, 2)));
345
+ } else if (Number.isFinite(gainTodayKWh) && gainTodayKWh >= 1) {
346
+ sentences.push(this._tf('solar_log_text_moderate_day', this._formatNumber(gainTodayKWh, 2)));
347
+ } else if (Number.isFinite(gainTodayKWh) && gainTodayKWh > 0) {
348
+ sentences.push(this._tf('solar_log_text_low_day', this._formatNumber(gainTodayKWh, 2)));
349
+ } else {
350
+ sentences.push(this._t('solar_log_text_no_clear_day_gain'));
351
+ }
352
+
353
+ if (Number.isFinite(collectorTemp) && Number.isFinite(poolReferenceTemp) && Number.isFinite(deltaTUsed)) {
354
+ if (deltaTUsed > 0.5) {
355
+ sentences.push(
356
+ this._tf(
357
+ 'solar_log_text_temperature_positive',
358
+ this._formatNumber(collectorTemp, 1),
359
+ this._formatNumber(poolReferenceTemp, 1),
360
+ this._formatNumber(deltaTUsed, 1),
361
+ ),
362
+ );
363
+ } else if (deltaTUsed <= 0.5 && deltaTUsed >= -0.5) {
364
+ sentences.push(
365
+ this._tf(
366
+ 'solar_log_text_temperature_neutral',
367
+ this._formatNumber(collectorTemp, 1),
368
+ this._formatNumber(poolReferenceTemp, 1),
369
+ ),
370
+ );
371
+ } else {
372
+ sentences.push(
373
+ this._tf(
374
+ 'solar_log_text_temperature_negative',
375
+ this._formatNumber(collectorTemp, 1),
376
+ this._formatNumber(poolReferenceTemp, 1),
377
+ ),
378
+ );
379
+ }
380
+ }
381
+
382
+ if (Number.isFinite(flowLhUsed) && flowLhUsed > 0 && Number.isFinite(pumpPowerWUsed) && pumpPowerWUsed > 0) {
383
+ sentences.push(
384
+ this._tf(
385
+ 'solar_log_text_flow_and_pump',
386
+ this._formatNumber(flowLhUsed, 0),
387
+ this._formatNumber(pumpPowerWUsed, 0),
388
+ ),
389
+ );
390
+ } else if (Number.isFinite(flowLhUsed) && flowLhUsed > 0) {
391
+ sentences.push(this._tf('solar_log_text_flow_only', this._formatNumber(flowLhUsed, 0)));
392
+ }
393
+
394
+ if (
395
+ Number.isFinite(thermalPowerW) &&
396
+ thermalPowerW > 0 &&
397
+ Number.isFinite(peakPowerTodayW) &&
398
+ peakPowerTodayW > 0
399
+ ) {
400
+ sentences.push(
401
+ this._tf(
402
+ 'solar_log_text_power_and_peak',
403
+ this._formatNumber(thermalPowerW, 0),
404
+ this._formatNumber(peakPowerTodayW, 0),
405
+ ),
406
+ );
407
+ }
408
+
409
+ if (Number.isFinite(efficiencyRatio) && efficiencyRatio > 0) {
410
+ if (efficiencyRatio >= 5) {
411
+ sentences.push(this._tf('solar_log_text_efficiency_high', this._formatNumber(efficiencyRatio, 2)));
412
+ } else if (efficiencyRatio >= 2) {
413
+ sentences.push(this._tf('solar_log_text_efficiency_medium', this._formatNumber(efficiencyRatio, 2)));
414
+ } else {
415
+ sentences.push(this._tf('solar_log_text_efficiency_low', this._formatNumber(efficiencyRatio, 2)));
416
+ }
417
+ }
418
+
419
+ if (Number.isFinite(activeMinutesToday) && activeMinutesToday > 0) {
420
+ sentences.push(this._tf('solar_log_text_active_minutes', this._formatNumber(activeMinutesToday, 0)));
421
+ }
422
+
423
+ if (Number.isFinite(outsideTemp)) {
424
+ sentences.push(this._tf('solar_log_text_outside_temp', this._formatNumber(outsideTemp, 1)));
425
+ }
426
+
427
+ if (weatherCorrectionActive) {
428
+ if (weatherTextShort !== '') {
429
+ sentences.push(this._tf('solar_log_text_weather_supported_with_text', weatherTextShort));
430
+ } else {
431
+ sentences.push(this._t('solar_log_text_weather_supported'));
432
+ }
433
+ }
434
+
435
+ if (Number.isFinite(gainTodayWh) && gainTodayWh > 0 && gainTodayWh < 1000 && Number.isFinite(gainTodayKWh)) {
436
+ sentences.push(
437
+ this._tf(
438
+ 'solar_log_text_small_gain_detail',
439
+ this._formatNumber(gainTodayWh, 0),
440
+ this._formatNumber(gainTodayKWh, 2),
441
+ ),
442
+ );
443
+ }
444
+
445
+ if (qualityLevel !== '') {
446
+ sentences.push(this._tf('solar_log_text_quality_level', qualityLevel));
447
+ }
448
+
449
+ if (confidenceText !== '') {
450
+ sentences.push(confidenceText);
451
+ }
452
+
453
+ sentences.push(this._tf('solar_log_text_used_sensors', usedSensors));
454
+
455
+ const text = sentences.join(' ');
456
+ return {
457
+ type: solarEffectiveNow ? 'active_log_entry' : 'daily_log_entry',
458
+ text,
459
+ html: this._escapeHtml(text),
460
+ };
461
+ },
462
+
463
+ _extractShortWeather(weatherSummary) {
464
+ if (!weatherSummary || weatherSummary.trim() === '') {
465
+ return '';
466
+ }
467
+
468
+ const text = weatherSummary.replace(/\s+/g, ' ').trim();
469
+
470
+ if (text.length <= 140) {
471
+ return text;
472
+ }
473
+
474
+ return `${text.slice(0, 137)}...`;
475
+ },
476
+
477
+ async _readState(id) {
478
+ try {
479
+ return await this.adapter.getStateAsync(id);
480
+ } catch {
481
+ return null;
482
+ }
483
+ },
484
+
485
+ async _readBoolean(id) {
486
+ const state = await this._readState(id);
487
+
488
+ if (!state) {
489
+ return false;
490
+ }
491
+
492
+ return state.val === true;
493
+ },
494
+
495
+ async _readNumber(id) {
496
+ const state = await this._readState(id);
497
+
498
+ if (!state || state.val === null || state.val === undefined || state.val === '') {
499
+ return null;
500
+ }
501
+
502
+ const value = Number(state.val);
503
+ return Number.isFinite(value) ? value : null;
504
+ },
505
+
506
+ async _readString(id) {
507
+ const state = await this._readState(id);
508
+
509
+ if (!state || state.val === null || state.val === undefined) {
510
+ return '';
511
+ }
512
+
513
+ return String(state.val);
514
+ },
515
+
516
+ _safeParseArray(jsonText) {
517
+ if (!jsonText || jsonText.trim() === '') {
518
+ return [];
519
+ }
520
+
521
+ try {
522
+ const parsed = JSON.parse(jsonText);
523
+ return Array.isArray(parsed) ? parsed : [];
524
+ } catch {
525
+ return [];
526
+ }
527
+ },
528
+
529
+ _formatNumber(value, digits = 1) {
530
+ if (!Number.isFinite(value)) {
531
+ return '';
532
+ }
533
+
534
+ return Number(value).toFixed(digits);
535
+ },
536
+
537
+ _formatTime(date) {
538
+ const hours = String(date.getHours()).padStart(2, '0');
539
+ const minutes = String(date.getMinutes()).padStart(2, '0');
540
+ return `${hours}:${minutes}`;
541
+ },
542
+
543
+ _escapeHtml(text) {
544
+ return String(text)
545
+ .replace(/&/g, '&amp;')
546
+ .replace(/</g, '&lt;')
547
+ .replace(/>/g, '&gt;')
548
+ .replace(/"/g, '&quot;')
549
+ .replace(/'/g, '&#39;');
550
+ },
551
+
552
+ _t(key) {
553
+ try {
554
+ return I18n.t(key);
555
+ } catch {
556
+ return key;
557
+ }
558
+ },
559
+
560
+ _tf(key, ...args) {
561
+ try {
562
+ let text = I18n.t(key);
563
+
564
+ for (const arg of args) {
565
+ text = text.replace('%s', String(arg));
566
+ }
567
+
568
+ return text;
569
+ } catch {
570
+ return key;
571
+ }
572
+ },
573
+
574
+ cleanup() {
575
+ if (this.checkTimer) {
576
+ this.adapter.clearTimeout(this.checkTimer);
577
+ this.checkTimer = null;
578
+ }
579
+
580
+ if (this.resetTimer) {
581
+ this.adapter.clearTimeout(this.resetTimer);
582
+ this.resetTimer = null;
583
+ }
584
+ },
585
+ };
586
+
587
+ module.exports = solarLogbookHelper;
588
+
589
+ // i18n keys required:
590
+ // solar_log_value_unknown
591
+ // solar_log_confidence_text
592
+ // solar_log_text_no_runtime_today
593
+ // solar_log_text_weather_short
594
+ // solar_log_text_used_sensors
595
+ // solar_log_text_active_effective
596
+ // solar_log_text_active_without_clear_gain
597
+ // solar_log_text_not_active_now
598
+ // solar_log_text_good_day
599
+ // solar_log_text_moderate_day
600
+ // solar_log_text_low_day
601
+ // solar_log_text_no_clear_day_gain
602
+ // solar_log_text_temperature_positive
603
+ // solar_log_text_temperature_neutral
604
+ // solar_log_text_temperature_negative
605
+ // solar_log_text_flow_and_pump
606
+ // solar_log_text_flow_only
607
+ // solar_log_text_power_and_peak
608
+ // solar_log_text_efficiency_high
609
+ // solar_log_text_efficiency_medium
610
+ // solar_log_text_efficiency_low
611
+ // solar_log_text_active_minutes
612
+ // solar_log_text_outside_temp
613
+ // solar_log_text_weather_supported_with_text
614
+ // solar_log_text_weather_supported
615
+ // solar_log_text_small_gain_detail
616
+ // solar_log_text_quality_level
@@ -23,11 +23,11 @@ const timeHelper = {
23
23
 
24
24
  _scheduleCheck() {
25
25
  if (this.checkTimer) {
26
- clearInterval(this.checkTimer);
26
+ this.adapter.clearInterval(this.checkTimer);
27
27
  }
28
- this.checkTimer = setInterval(() => this._checkWindows(), 60 * 1000);
28
+ this.checkTimer = this.adapter.setInterval(() => this._checkWindows(), 60 * 1000);
29
29
  // Beim Start sofort prüfen
30
- this._checkWindows();
30
+ void this._checkWindows();
31
31
  },
32
32
 
33
33
  async _checkWindows() {
@@ -109,7 +109,7 @@ const timeHelper = {
109
109
 
110
110
  cleanup() {
111
111
  if (this.checkTimer) {
112
- clearInterval(this.checkTimer);
112
+ this.adapter.clearInterval(this.checkTimer);
113
113
  this.checkTimer = null;
114
114
  }
115
115
  },