iobroker.poolcontrol 0.7.1 → 0.7.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.
- package/io-package.json +27 -25
- package/lib/helpers/aiHelper.js +916 -0
- package/lib/helpers/infoHelper.js +159 -0
- package/lib/stateDefinitions/aiStates.js +135 -0
- package/lib/stateDefinitions/infoStates.js +63 -0
- package/main.js +24 -0
- package/package.json +2 -1
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* infoHelper.js
|
|
5
|
+
* ----------------------------------------------------------
|
|
6
|
+
* Verwaltet die Info-States:
|
|
7
|
+
* - info.developer_greeting
|
|
8
|
+
* - info.adapter_version
|
|
9
|
+
* ----------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const infoHelper = {
|
|
13
|
+
adapter: null,
|
|
14
|
+
dailyTimer: null,
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Initialisierung des Info-Helpers
|
|
18
|
+
*
|
|
19
|
+
* @param {import('iobroker').Adapter} adapter - Die ioBroker-Adapterinstanz
|
|
20
|
+
*/
|
|
21
|
+
init(adapter) {
|
|
22
|
+
this.adapter = adapter;
|
|
23
|
+
this.adapter.log.debug('[infoHelper] Initialisiert');
|
|
24
|
+
|
|
25
|
+
// Adapterversion setzen
|
|
26
|
+
this._updateAdapterVersion();
|
|
27
|
+
|
|
28
|
+
// Entwicklergruß setzen
|
|
29
|
+
this._updateDeveloperGreeting();
|
|
30
|
+
|
|
31
|
+
// NEU: täglichen Timer starten
|
|
32
|
+
this._startDailyTimer();
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Liest die Version aus io-package.json und schreibt sie in info.adapter_version
|
|
37
|
+
*/
|
|
38
|
+
_updateAdapterVersion() {
|
|
39
|
+
try {
|
|
40
|
+
const ioPkg = require('../../io-package.json');
|
|
41
|
+
const version = ioPkg.common.version || '';
|
|
42
|
+
|
|
43
|
+
this.adapter.setState('info.adapter_version', version, true);
|
|
44
|
+
} catch (err) {
|
|
45
|
+
this.adapter.log.error(`[infoHelper] Fehler beim Lesen der Adapterversion: ${err}`);
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Setzt saisonale Grüße in info.developer_greeting
|
|
51
|
+
*/
|
|
52
|
+
_updateDeveloperGreeting() {
|
|
53
|
+
const now = new Date();
|
|
54
|
+
const month = now.getMonth() + 1;
|
|
55
|
+
const day = now.getDate();
|
|
56
|
+
let greeting = '';
|
|
57
|
+
|
|
58
|
+
// Weihnachten: 20.12. – 27.12.
|
|
59
|
+
if (month === 12 && day >= 20 && day <= 27) {
|
|
60
|
+
greeting = '🎄 PoolControl wünscht frohe Weihnachten! 🎄';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Jahreswechsel
|
|
64
|
+
// 31.12.: Guten Rutsch
|
|
65
|
+
if (month === 12 && day === 31) {
|
|
66
|
+
greeting = '🎆 PoolControl wünscht einen guten Rutsch ins neue Jahr! 🎆';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 01.01.: Frohes neues Jahr
|
|
70
|
+
if (month === 1 && day === 1) {
|
|
71
|
+
greeting = '🎆 Frohes neues Jahr wünscht PoolControl! 🎆';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Dynamische Berechnung von Ostersonntag (Computus)
|
|
75
|
+
const easter = this._computeEaster(now.getFullYear());
|
|
76
|
+
const easterMonth = easter.getMonth() + 1;
|
|
77
|
+
const easterDay = easter.getDate();
|
|
78
|
+
|
|
79
|
+
const easterMonday = new Date(easter);
|
|
80
|
+
easterMonday.setDate(easterDay + 1);
|
|
81
|
+
|
|
82
|
+
// Ostersonntag
|
|
83
|
+
if (month === easterMonth && day === easterDay) {
|
|
84
|
+
greeting = '🐣 Frohe Ostern wünscht PoolControl! 🐣';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Ostermontag
|
|
88
|
+
if (month === easterMonday.getMonth() + 1 && day === easterMonday.getDate()) {
|
|
89
|
+
greeting = '🐣 PoolControl wünscht einen schönen Ostermontag! 🐣';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this.adapter.setState('info.developer_greeting', greeting, true);
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Berechnet das Datum des Ostersonntags für ein bestimmtes Jahr.
|
|
97
|
+
* Algorithmus: Anonymous Gregorian Computus
|
|
98
|
+
*
|
|
99
|
+
* @param {number} year - Das Jahr, für das Ostern berechnet werden soll
|
|
100
|
+
* @returns {Date} Datum des Ostersonntags
|
|
101
|
+
*/
|
|
102
|
+
_computeEaster(year) {
|
|
103
|
+
const a = year % 19;
|
|
104
|
+
const b = Math.floor(year / 100);
|
|
105
|
+
const c = year % 100;
|
|
106
|
+
const d = Math.floor(b / 4);
|
|
107
|
+
const e = b % 4;
|
|
108
|
+
const f = Math.floor((b + 8) / 25);
|
|
109
|
+
const g = Math.floor((b - f + 1) / 3);
|
|
110
|
+
const h = (19 * a + b - d - g + 15) % 30;
|
|
111
|
+
const i = Math.floor(c / 4);
|
|
112
|
+
const k = c % 4;
|
|
113
|
+
const l = (32 + 2 * e + 2 * i - h - k) % 7;
|
|
114
|
+
const m = Math.floor((a + 11 * h + 22 * l) / 451);
|
|
115
|
+
const month = Math.floor((h + l - 7 * m + 114) / 31);
|
|
116
|
+
const day = ((h + l - 7 * m + 114) % 31) + 1;
|
|
117
|
+
return new Date(year, month - 1, day);
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Startet den täglichen Update-Intervall (Update 00:01 Uhr)
|
|
122
|
+
*/
|
|
123
|
+
_startDailyTimer() {
|
|
124
|
+
// nächsten Trigger für morgen 00:01 berechnen
|
|
125
|
+
const now = new Date();
|
|
126
|
+
const next = new Date(now);
|
|
127
|
+
|
|
128
|
+
next.setDate(now.getDate() + 1);
|
|
129
|
+
next.setHours(0, 1, 0, 0);
|
|
130
|
+
|
|
131
|
+
const delay = next.getTime() - now.getTime();
|
|
132
|
+
|
|
133
|
+
// einmaliger Timer bis 00:01
|
|
134
|
+
this.dailyTimer = setTimeout(() => {
|
|
135
|
+
this._updateDeveloperGreeting();
|
|
136
|
+
|
|
137
|
+
// danach täglich um 24h
|
|
138
|
+
this.dailyTimer = setInterval(
|
|
139
|
+
() => {
|
|
140
|
+
this._updateDeveloperGreeting();
|
|
141
|
+
},
|
|
142
|
+
24 * 60 * 60 * 1000,
|
|
143
|
+
);
|
|
144
|
+
}, delay);
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Stoppt Timer (wichtig beim Adapter-Unload)
|
|
149
|
+
*/
|
|
150
|
+
cleanup() {
|
|
151
|
+
if (this.dailyTimer) {
|
|
152
|
+
clearTimeout(this.dailyTimer);
|
|
153
|
+
clearInterval(this.dailyTimer);
|
|
154
|
+
this.dailyTimer = null;
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
module.exports = infoHelper;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aiStates.js
|
|
5
|
+
* ----------------------------------------------------------
|
|
6
|
+
* Definiert alle States für den KI-Bereich des PoolControl-Adapters.
|
|
7
|
+
* Struktur:
|
|
8
|
+
* ai.switches.*
|
|
9
|
+
* ai.schedule.*
|
|
10
|
+
* ai.outputs.*
|
|
11
|
+
* ----------------------------------------------------------
|
|
12
|
+
*
|
|
13
|
+
* @param {import('iobroker').Adapter} adapter - ioBroker Adapterinstanz
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Erstellt alle KI-bezogenen States (ai.*)
|
|
18
|
+
*
|
|
19
|
+
* @param {import('iobroker').Adapter} adapter - ioBroker Adapterinstanz
|
|
20
|
+
*/
|
|
21
|
+
async function createAiStates(adapter) {
|
|
22
|
+
adapter.log.debug('[aiStates] Initialisierung gestartet');
|
|
23
|
+
|
|
24
|
+
// Hauptordner
|
|
25
|
+
await adapter.setObjectNotExistsAsync('ai', {
|
|
26
|
+
type: 'channel',
|
|
27
|
+
common: { name: 'KI / AI-Funktionen' },
|
|
28
|
+
native: {},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// ------------------------------------------------------
|
|
32
|
+
// Unterordner: switches
|
|
33
|
+
// ------------------------------------------------------
|
|
34
|
+
await adapter.setObjectNotExistsAsync('ai.switches', {
|
|
35
|
+
type: 'channel',
|
|
36
|
+
common: { name: 'Schalter (KI-Steuerung)' },
|
|
37
|
+
native: {},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const switches = [
|
|
41
|
+
{ id: 'enabled', name: 'KI aktivieren', def: false },
|
|
42
|
+
{ id: 'allow_speech', name: 'Sprachausgabe durch KI erlauben', def: false },
|
|
43
|
+
{ id: 'daily_summary_enabled', name: 'Tägliche Zusammenfassung aktiv', def: false },
|
|
44
|
+
{ id: 'daily_pool_tips_enabled', name: 'Tägliche Pool-Tipps aktiv', def: false },
|
|
45
|
+
{ id: 'weather_advice_enabled', name: 'Wetterhinweise aktiv', def: false },
|
|
46
|
+
{ id: 'weekend_summary_enabled', name: 'Wochenende-Zusammenfassung aktiv', def: false },
|
|
47
|
+
{ id: 'debug_mode', name: 'KI-Debugmodus', def: false },
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
for (const s of switches) {
|
|
51
|
+
await adapter.setObjectNotExistsAsync(`ai.switches.${s.id}`, {
|
|
52
|
+
type: 'state',
|
|
53
|
+
common: {
|
|
54
|
+
name: s.name,
|
|
55
|
+
type: 'boolean',
|
|
56
|
+
role: 'switch',
|
|
57
|
+
read: true,
|
|
58
|
+
write: true,
|
|
59
|
+
def: s.def,
|
|
60
|
+
persist: true,
|
|
61
|
+
},
|
|
62
|
+
native: {},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ------------------------------------------------------
|
|
67
|
+
// Unterordner: schedule
|
|
68
|
+
// ------------------------------------------------------
|
|
69
|
+
await adapter.setObjectNotExistsAsync('ai.schedule', {
|
|
70
|
+
type: 'channel',
|
|
71
|
+
common: { name: 'Zeitpläne (KI-Ausgaben)' },
|
|
72
|
+
native: {},
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const schedule = [
|
|
76
|
+
{ id: 'daily_summary_time', name: 'Zeit für tägliche Zusammenfassung', def: '09:00' },
|
|
77
|
+
{ id: 'daily_pool_tips_time', name: 'Zeit für tägliche Pool-Tipps', def: '10:00' },
|
|
78
|
+
{ id: 'weather_advice_time', name: 'Zeit für Wetterhinweise', def: '08:00' },
|
|
79
|
+
{ id: 'weekend_summary_time', name: 'Zeit für Wochenend-Zusammenfassung', def: '18:00' },
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
for (const t of schedule) {
|
|
83
|
+
await adapter.setObjectNotExistsAsync(`ai.schedule.${t.id}`, {
|
|
84
|
+
type: 'state',
|
|
85
|
+
common: {
|
|
86
|
+
name: t.name,
|
|
87
|
+
type: 'string',
|
|
88
|
+
role: 'text',
|
|
89
|
+
read: true,
|
|
90
|
+
write: true,
|
|
91
|
+
def: t.def,
|
|
92
|
+
persist: true,
|
|
93
|
+
},
|
|
94
|
+
native: {},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ------------------------------------------------------
|
|
99
|
+
// Unterordner: outputs
|
|
100
|
+
// ------------------------------------------------------
|
|
101
|
+
await adapter.setObjectNotExistsAsync('ai.outputs', {
|
|
102
|
+
type: 'channel',
|
|
103
|
+
common: { name: 'KI-Ausgaben (Texte)' },
|
|
104
|
+
native: {},
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const outputs = [
|
|
108
|
+
{ id: 'daily_summary', name: 'Tägliche Zusammenfassung' },
|
|
109
|
+
{ id: 'pool_tips', name: 'Pool-Tipps' },
|
|
110
|
+
{ id: 'weather_advice', name: 'Wetterhinweise' },
|
|
111
|
+
{ id: 'weekend_summary', name: 'Wochenende-Zusammenfassung' },
|
|
112
|
+
{ id: 'last_message', name: 'Letzte KI-Meldung' },
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
for (const o of outputs) {
|
|
116
|
+
await adapter.setObjectNotExistsAsync(`ai.outputs.${o.id}`, {
|
|
117
|
+
type: 'state',
|
|
118
|
+
common: {
|
|
119
|
+
name: o.name,
|
|
120
|
+
type: 'string',
|
|
121
|
+
role: 'text',
|
|
122
|
+
read: true,
|
|
123
|
+
write: false,
|
|
124
|
+
persist: false,
|
|
125
|
+
},
|
|
126
|
+
native: {},
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
adapter.log.debug('[aiStates] Initialisierung abgeschlossen');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
module.exports = {
|
|
134
|
+
createAiStates,
|
|
135
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* infoStates.js
|
|
5
|
+
* ----------------------------------------------------------
|
|
6
|
+
* Legt allgemeine Informations-States an:
|
|
7
|
+
* - info.developer_greeting
|
|
8
|
+
* - info.adapter_version
|
|
9
|
+
*
|
|
10
|
+
* Struktur:
|
|
11
|
+
* info.*
|
|
12
|
+
* ----------------------------------------------------------
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Erstellt alle States im Bereich info.
|
|
17
|
+
*
|
|
18
|
+
* @param {import("iobroker").Adapter} adapter - ioBroker Adapterinstanz
|
|
19
|
+
*/
|
|
20
|
+
async function createInfoStates(adapter) {
|
|
21
|
+
// Hauptordner: info
|
|
22
|
+
await adapter.setObjectNotExistsAsync('info', {
|
|
23
|
+
type: 'channel',
|
|
24
|
+
common: {
|
|
25
|
+
name: 'Informationen (PoolControl Systeminfos)',
|
|
26
|
+
},
|
|
27
|
+
native: {},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Entwickler-Grußtext
|
|
31
|
+
await adapter.setObjectNotExistsAsync('info.developer_greeting', {
|
|
32
|
+
type: 'state',
|
|
33
|
+
common: {
|
|
34
|
+
name: 'Entwickler-Grußtext',
|
|
35
|
+
desc: 'Saisonale Grüße und Informationen vom PoolControl-Entwickler',
|
|
36
|
+
type: 'string',
|
|
37
|
+
role: 'text',
|
|
38
|
+
read: true,
|
|
39
|
+
write: false,
|
|
40
|
+
def: '',
|
|
41
|
+
},
|
|
42
|
+
native: {},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Adapterversion
|
|
46
|
+
await adapter.setObjectNotExistsAsync('info.adapter_version', {
|
|
47
|
+
type: 'state',
|
|
48
|
+
common: {
|
|
49
|
+
name: 'Installierte Adapterversion',
|
|
50
|
+
desc: 'Aktuell installierte Version von PoolControl',
|
|
51
|
+
type: 'string',
|
|
52
|
+
role: 'text',
|
|
53
|
+
read: true,
|
|
54
|
+
write: false,
|
|
55
|
+
def: '',
|
|
56
|
+
},
|
|
57
|
+
native: {},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = {
|
|
62
|
+
createInfoStates,
|
|
63
|
+
};
|
package/main.js
CHANGED
|
@@ -21,11 +21,13 @@ const solarHelper = require('./lib/helpers/solarHelper');
|
|
|
21
21
|
const frostHelper = require('./lib/helpers/frostHelper');
|
|
22
22
|
const statusHelper = require('./lib/helpers/statusHelper');
|
|
23
23
|
const photovoltaicHelper = require('./lib/helpers/photovoltaicHelper');
|
|
24
|
+
const aiHelper = require('./lib/helpers/aiHelper');
|
|
24
25
|
const controlHelper = require('./lib/helpers/controlHelper');
|
|
25
26
|
const controlHelper2 = require('./lib/helpers/controlHelper2');
|
|
26
27
|
const debugLogHelper = require('./lib/helpers/debugLogHelper');
|
|
27
28
|
const speechTextHelper = require('./lib/helpers/speechTextHelper');
|
|
28
29
|
const migrationHelper = require('./lib/helpers/migrationHelper');
|
|
30
|
+
const infoHelper = require('./lib/helpers/infoHelper');
|
|
29
31
|
const { createTemperatureStates } = require('./lib/stateDefinitions/temperatureStates');
|
|
30
32
|
const { createPumpStates } = require('./lib/stateDefinitions/pumpStates');
|
|
31
33
|
const { createPumpStates2 } = require('./lib/stateDefinitions/pumpStates2');
|
|
@@ -42,6 +44,8 @@ const { createConsumptionStates } = require('./lib/stateDefinitions/consumptionS
|
|
|
42
44
|
const { createStatusStates } = require('./lib/stateDefinitions/statusStates');
|
|
43
45
|
const { createControlStates } = require('./lib/stateDefinitions/controlStates');
|
|
44
46
|
const { createDebugLogStates } = require('./lib/stateDefinitions/debugLogStates');
|
|
47
|
+
const { createInfoStates } = require('./lib/stateDefinitions/infoStates');
|
|
48
|
+
const { createAiStates } = require('./lib/stateDefinitions/aiStates'); // NEU: KI-States
|
|
45
49
|
|
|
46
50
|
class Poolcontrol extends utils.Adapter {
|
|
47
51
|
constructor(options) {
|
|
@@ -105,6 +109,12 @@ class Poolcontrol extends utils.Adapter {
|
|
|
105
109
|
// --- DebugLog States ---
|
|
106
110
|
await createDebugLogStates(this);
|
|
107
111
|
|
|
112
|
+
// --- Info States ---
|
|
113
|
+
await createInfoStates(this);
|
|
114
|
+
|
|
115
|
+
// --- AI States ---
|
|
116
|
+
await createAiStates(this); // NEU: KI-States anlegen
|
|
117
|
+
|
|
108
118
|
// --- Migration Helper zuletzt starten ---
|
|
109
119
|
await migrationHelper.init(this);
|
|
110
120
|
|
|
@@ -123,8 +133,10 @@ class Poolcontrol extends utils.Adapter {
|
|
|
123
133
|
consumptionHelper.init(this);
|
|
124
134
|
solarHelper.init(this);
|
|
125
135
|
photovoltaicHelper.init(this);
|
|
136
|
+
aiHelper.init(this);
|
|
126
137
|
frostHelper.init(this);
|
|
127
138
|
statusHelper.init(this);
|
|
139
|
+
infoHelper.init(this);
|
|
128
140
|
controlHelper.init(this);
|
|
129
141
|
controlHelper2.init(this);
|
|
130
142
|
debugLogHelper.init(this);
|
|
@@ -180,6 +192,12 @@ class Poolcontrol extends utils.Adapter {
|
|
|
180
192
|
}
|
|
181
193
|
if (speechTextHelper.cleanup) {
|
|
182
194
|
speechTextHelper.cleanup();
|
|
195
|
+
}
|
|
196
|
+
if (aiHelper.cleanup) {
|
|
197
|
+
aiHelper.cleanup();
|
|
198
|
+
}
|
|
199
|
+
if (infoHelper.cleanup) {
|
|
200
|
+
infoHelper.cleanup();
|
|
183
201
|
}
|
|
184
202
|
} catch (e) {
|
|
185
203
|
this.log.warn(`[onUnload] Fehler beim Cleanup: ${e.message}`);
|
|
@@ -248,6 +266,12 @@ class Poolcontrol extends utils.Adapter {
|
|
|
248
266
|
photovoltaicHelper.handleStateChange(id, state);
|
|
249
267
|
} catch (e) {
|
|
250
268
|
this.log.warn(`[photovoltaicHelper] Fehler in handleStateChange: ${e.message}`);
|
|
269
|
+
}
|
|
270
|
+
// --- AI-Helper ---
|
|
271
|
+
try {
|
|
272
|
+
aiHelper.handleStateChange(id, state);
|
|
273
|
+
} catch (e) {
|
|
274
|
+
this.log.warn(`[main] Fehler in aiHelper.handleStateChange: ${e.message}`);
|
|
251
275
|
}
|
|
252
276
|
try {
|
|
253
277
|
statusHelper.handleStateChange(id, state);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.poolcontrol",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
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",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"@iobroker/adapter-dev": "^1.5.0",
|
|
29
29
|
"@iobroker/eslint-config": "^2.2.0",
|
|
30
30
|
"@iobroker/testing": "^5.1.1",
|
|
31
|
+
"baseline-browser-mapping": "^2.8.32",
|
|
31
32
|
"eslint": "^9.36.0",
|
|
32
33
|
"prettier": "^3.6.2",
|
|
33
34
|
"proxyquire": "^2.1.3",
|