iobroker.idm-multitalent_002 2.2.3 → 2.2.5
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 +5 -92
- package/io-package.json +27 -1
- package/lib/datablocks/EVR752101.json +1 -1
- package/lib/datablocks/S_H726100.json +1 -10
- package/lib/datablocks/idm701100.json +4 -4
- package/lib/idm-protocol.test.js +1 -1
- package/lib/idm_datablocks.test.js +120 -0
- package/main.js +4 -4
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -76,6 +76,10 @@ Example screenshots of objects:
|
|
|
76
76
|

|
|
77
77
|
|
|
78
78
|
## Changelog
|
|
79
|
+
### 2.2.4 (2026-10-10)
|
|
80
|
+
* (zloe) fixed the same "marked read-only by mistake" bug for `Waermepumpe.Maximaltemperatur` on EVR752101 (found by cross-checking all six firmware definitions against each other, same pattern as the Heizkreis B fix below)
|
|
81
|
+
* (zloe) added a permanent automated test (`lib/idm_datablocks.test.js`) that cross-checks every bundled firmware definition against the others - same statename + register ("function") id must agree on `writable`/`length`/`factor` - so this class of bug is caught by CI from now on instead of needing a one-off manual check. A handful of genuine, still-unconfirmed differences (`Waermepumpe.MinimaleLaufzeit` writable, and three `length` mismatches around `Heizkreis-A.Absenkfaktor`/`Heizung.PufferVorhanden`/`Heizung.SchichttrennplatteVorhanden`) are documented as known exceptions in that test rather than guessed at - see the test file for why
|
|
82
|
+
|
|
79
83
|
### 2.2.3 (2026-10-10)
|
|
80
84
|
* (zloe) fixed: "Heizkreis B" operating mode (Betriebsart) could not be changed on the S_H726100 and idm750100 control versions - it was incorrectly marked read-only in the data block definition (`writable: false` instead of `true`), while reading always worked fine. Found by cross-checking all six firmware definitions against each other: every other control version already had `function: 19` (same register, same min/max) correctly set to `writable: true`
|
|
81
85
|
|
|
@@ -112,98 +116,7 @@ Example screenshots of objects:
|
|
|
112
116
|
### 2.0.0 (2026-09-10)
|
|
113
117
|
* (zloe) for S_H726100 (currently the only firmware with every data block's actual wire length verified against real hardware), collect all settings data blocks in one multi-block request per settings turn instead of one block per poll cycle, with automatic re-asking/backoff for the control's typically-partial replies - a full settings refresh now takes seconds instead of roughly a minute. Every other supported firmware is completely unaffected and keeps requesting settings blocks one at a time (see the Architecture section)
|
|
114
118
|
|
|
115
|
-
|
|
116
|
-
* (zloe) fix: a retry on an already finely-tuned data block used to always jump its delay up by the full, coarse step (300ms) regardless of how small a correction was actually needed - now it corrects by the same (possibly already tiny) step that tuning had converged to, and only doubles that step towards the coarse ceiling if retries actually keep recurring
|
|
117
|
-
|
|
118
|
-
### 1.3.9 (2026-09-09)
|
|
119
|
-
* (zloe) list every data block's current content delay in the full-coverage cycle log line, so a change in total cycle time can be traced back to which block(s) grew
|
|
120
|
-
* (zloe) the adaptive per-block content delay's ease-down step now starts coarse (100ms) and halves each time it's used (down to a 1ms floor), instead of always easing by a flat 100ms - a block that's been stable for a while gets refined much more finely, converging near its true minimum safe delay instead of only ever landing on multiples of 100ms. A retry resets a block's step back to the coarse starting point
|
|
121
|
-
|
|
122
|
-
### 1.3.8 (2026-09-09)
|
|
123
|
-
* (zloe) remove the "completed one full poll cycle (every sensor block + one settings block)" log line entirely - it fired every single sensor sweep (~14s on real hardware), far too often to be useful. Only the full-coverage cycle line (every sensor and settings block actually read at least once, confirmed correct against real production logs) remains
|
|
124
|
-
|
|
125
|
-
### 1.3.7 (2026-09-08)
|
|
126
|
-
* (zloe) fix: the full-coverage cycle log line still fired far too often on real hardware - it was gated by the settings-block round-robin index advancing at *request* time, not by data actually being read, so a retry, a response-watchdog reset, or the periodic resync could let a "lap" complete without every block truly having been read. Now gated by actual received data instead
|
|
127
|
-
|
|
128
|
-
### 1.3.6 (2026-09-08)
|
|
129
|
-
* (zloe) shorten the full-coverage cycle log line to `full-coverage cycle #N done in Xms` - same information (elapsed time, running total), just without the long parenthetical explanation
|
|
130
|
-
* (zloe) fix three `npm run check` (typescript) errors surfaced by the typescript 7 / axios 1.20 / @types/sinon 22 updates, without changing any runtime behavior
|
|
131
|
-
|
|
132
|
-
### 1.3.5 (2026-09-08)
|
|
133
|
-
* (zloe) hotfix: 1.3.4's CI run failed on Node 20 - `engines: ">=22"` and testing on Node 20 at the same time don't work together, npm install fails with EBADENGINE. Drop Node 20 from the CI test matrix again (keeping the >=22 requirement); this reintroduces one repository-checker item (E3025) that directly conflicts with another (E0028) - can't satisfy both
|
|
134
|
-
|
|
135
|
-
### 1.3.4 (2026-09-08)
|
|
136
|
-
* (zloe) rename/rework the second cycle-timing log line: it's now explicitly about every data block (sensor and settings) having been read at least once, not just the settings side, and it now also reports a running total of how many full-coverage cycles have completed
|
|
137
|
-
* (zloe) address most of the ioBroker repository checker's findings from #349: raise the minimum Node.js version to 22, bump the required admin/js-controller versions, add missing translations, trim the in-admin news list to real, published versions, switch built-in module imports to the `node:` form, add the missing release-script plugins, tidy up CI/dependabot config, and rewrite the README's installation section to stop suggesting a direct `npm install` (see below for the couple of checker items intentionally left alone)
|
|
138
|
-
|
|
139
|
-
### 1.3.3 (2026-09-08)
|
|
140
|
-
* (zloe) shorten the recurring per-data-block request log line (data block 07) to one compact line with the same information
|
|
141
|
-
* (zloe) also log how long a full settings cycle (every settings block once, not just the one per sweep) takes, once the next one starts
|
|
142
|
-
|
|
143
|
-
### 1.3.2 (2026-09-08)
|
|
144
|
-
* (zloe) replace the per-data-block content delay's averaging with a proper hill-climb: it now only grows when a "not ready" retry was actually needed and eases back down after several clean cycles, converging on a sweet spot instead of only ever ratcheting upward
|
|
145
|
-
* (zloe) lower the default/floor data-content delay from 1000ms to 650ms
|
|
146
|
-
* (zloe) log how long one full poll cycle (every sensor block plus one settings block) actually takes, once the next cycle starts
|
|
147
|
-
|
|
148
|
-
### 1.3.1 (2026-09-08)
|
|
149
|
-
* (zloe) log which firmware versions have a data block definition available, and which one (bundled or a custom override) was actually selected once the heat pump reports its version
|
|
150
|
-
* (zloe) add estimated min/max write limits for every remaining writable S_H726100 field (temperature setpoints, cooling settings, two on/off flags, pump speed) - conservative, margin-padded ranges, not hardware-verified for every field, see lib/datablocks/README.md
|
|
151
|
-
* (zloe) learn a per-data-block delay before requesting its content instead of one fixed guess for all of them, reducing "not ready" retries over time (see the Architecture section)
|
|
152
|
-
|
|
153
|
-
### 1.3.0 (2026-09-06)
|
|
154
|
-
* (zloe) move the hardware data block definitions out of the code into one JSON file per firmware version (lib/datablocks/), validated at load time
|
|
155
|
-
* (zloe) enforce configured min/max limits when writing a value to the heatpump, reverting the displayed value if a write is rejected
|
|
156
|
-
* (zloe) support a directory of custom data block files (one per firmware version, matched by their own version field, not the filename) to override or add definitions without an adapter update - see lib/datablocks/README.md
|
|
157
|
-
* (zloe) fix a bug where the per-version speed adjustment (e.g. idm722100's 75%) never actually took effect
|
|
158
|
-
* (zloe) give every adapter instance its own protocol/connection state instead of a shared module-level singleton, fixing multi-instance ("compact mode") safety
|
|
159
|
-
* (zloe) extract the TCP connection and request/response state machine out of main.js into its own class (lib/idm-session.js)
|
|
160
|
-
* (zloe) add a short per-request response timeout and a frame-length cap, so a dropped reply or a garbled byte stream is recovered from in seconds instead of stalling
|
|
161
|
-
* (zloe) translate the admin config screen and fill in missing changelog translations (previously English-only outside of a few fields)
|
|
162
|
-
|
|
163
|
-
### 1.2.9 (2026-09-05)
|
|
164
|
-
* (zloe) switch npm deploy from the retired classic npm token to Trusted Publishing (OIDC) - both 1.2.7 and 1.2.8 failed to publish to npm because of this
|
|
165
|
-
|
|
166
|
-
### 1.2.8 (2026-09-05)
|
|
167
|
-
* (zloe) fix repository checker issues (#298): add engines.node, German news translations, correct js-controller/admin dependency versions, add missing tier/licenseInformation, remove deprecated common.main/title, fix broken vscode schema link
|
|
168
|
-
* (zloe) add .releaseconfig.json so io-package.json's version is kept in sync automatically on release
|
|
169
|
-
* (zloe) fix broken `npm run lint` (missing @eslint/js dependency)
|
|
170
|
-
|
|
171
|
-
### 1.2.7 (2026-09-05)
|
|
172
|
-
* (zloe) fix broken test/lint toolchain (incompatible chai/sinon-chai/chai-as-promised versions, outdated tsconfig moduleResolution)
|
|
173
|
-
* (zloe) fix three duplicate `function` numbers in data block definitions that could have targeted the wrong register once made writable
|
|
174
|
-
* (zloe) clear all pending communication timers on adapter unload, not just reconnect/resend
|
|
175
|
-
* (zloe) remove unused imports, clear the default TCP server IP placeholder
|
|
176
|
-
* (zloe) add real unit tests for idm-utils and the main.js communication state machine
|
|
177
|
-
|
|
178
|
-
### 1.2.6 (2024-09-21)
|
|
179
|
-
* (zloe) fixed reconnect handling
|
|
180
|
-
|
|
181
|
-
### 1.2.5 (2024-01-21)
|
|
182
|
-
* (zloe) further fixes in error handling
|
|
183
|
-
|
|
184
|
-
### 1.2.4 (2024-01-21)
|
|
185
|
-
* (zloe) further improve logging and handling of transmission errors
|
|
186
|
-
|
|
187
|
-
### 1.2.3 (2024-01-21)
|
|
188
|
-
* (zloe) improve handling of data transmission problems
|
|
189
|
-
|
|
190
|
-
### 1.2.2 (2024-01-21)
|
|
191
|
-
* (zloe) fix handling of data transmission problems which lead to stopping requesting data
|
|
192
|
-
|
|
193
|
-
### 1.2.1 (2024-01-20)
|
|
194
|
-
* (zloe) improving statistics and log messages
|
|
195
|
-
* (zloe) fix data definition for idm722100
|
|
196
|
-
|
|
197
|
-
### 1.2.0 (2024-01-19)
|
|
198
|
-
* (zloe) adding support for idm722100
|
|
199
|
-
|
|
200
|
-
### 1.1.1 (2023-11-04)
|
|
201
|
-
* (zloe) optimizing protocol
|
|
202
|
-
* (zloe) updated dependencies
|
|
203
|
-
|
|
204
|
-
### 1.1.0 (2023-11-02)
|
|
205
|
-
* (zloe) initial version TERRA130601 - S_H726100 support
|
|
206
|
-
* (zloe) updated dependencies
|
|
119
|
+
Older changes (versions 1.1.0 - 1.3.10) have been moved to [CHANGELOG_OLD.md](CHANGELOG_OLD.md).
|
|
207
120
|
|
|
208
121
|
## Installation
|
|
209
122
|
As the adapter is not (yet) listed in the official ioBroker repository, install it through the Admin UI rather than a direct npm command:
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "idm-multitalent_002",
|
|
4
|
-
"version": "2.2.
|
|
4
|
+
"version": "2.2.5",
|
|
5
5
|
"news": {
|
|
6
|
+
"2.2.5": {
|
|
7
|
+
"en": "fixed: \"Heizkreis-A.Absenkfaktor\" was declared 1 byte instead of 2 on S_H726100 - the following, previously unidentified \"padding\" byte was actually its own high byte (confirmed both by makki's original reference data and by live values read straight off Klaus's running heat pump); also fixed a copy/paste mix-up on idm701100 where \"Laufzeit Zirkulation\" and an unidentified field had their object names swapped, so the wrong one showed up under each name. Checked but intentionally left unchanged: \"Puffer vorhanden\"/\"Schichttrennplatte\" on idm701100/S_H726100 looked like they might need the same 1-byte fix per older reference documents, but live hardware captures confirmed the current 2-byte definition is actually the correct one for these two control versions",
|
|
8
|
+
"de": "behoben: \"Heizkreis-A.Absenkfaktor\" war bei S_H726100 fälschlich mit 1 statt 2 Byte definiert - das direkt danach liegende, bisher nicht identifizierte \"Padding\"-Byte war in Wirklichkeit sein eigenes High-Byte (bestätigt sowohl durch makkis Original-Referenzdaten als auch durch Live-Werte direkt von Klaus' laufender Wärmepumpe); außerdem einen Kopierfehler bei idm701100 behoben, bei dem \"Laufzeit Zirkulation\" und ein nicht identifiziertes Feld ihre Objektnamen vertauscht hatten, sodass unter jedem Namen der falsche Wert erschien. Geprüft, aber bewusst unverändert gelassen: \"Puffer vorhanden\"/\"Schichttrennplatte\" bei idm701100/S_H726100 sahen laut älteren Referenzdokumenten so aus, als bräuchten sie denselben 1-Byte-Fix, aber Live-Messungen an echter Hardware haben bestätigt, dass die aktuelle 2-Byte-Definition für diese beiden Steuerungsversionen tatsächlich richtig ist",
|
|
9
|
+
"ru": "исправлено: \"Heizkreis-A.Absenkfaktor\" на S_H726100 был объявлен как 1 байт вместо 2 - следующий за ним, ранее неопознанный \"padding\"-байт на самом деле был его собственным старшим байтом (подтверждено как исходными данными makki, так и живыми значениями прямо с работающего теплового насоса Клауса); также исправлена путаница из-за копирования в idm701100, где \"Laufzeit Zirkulation\" и неопознанное поле были перепутаны по именам объектов. Проверено, но намеренно оставлено без изменений: \"Puffer vorhanden\"/\"Schichttrennplatte\" на idm701100/S_H726100 выглядели так, будто нуждаются в том же исправлении на 1 байт по старым справочным документам, но живые данные с реального оборудования подтвердили, что текущее определение в 2 байта на самом деле верно для этих двух версий управления",
|
|
10
|
+
"pt": "corrigido: \"Heizkreis-A.Absenkfaktor\" estava declarado com 1 byte em vez de 2 no S_H726100 - o byte de \"padding\" seguinte, até então não identificado, era na verdade o seu próprio byte alto (confirmado tanto pelos dados de referência originais de makki quanto por valores em tempo real lidos direto da bomba de calor do Klaus); também corrigida uma confusão de copiar/colar no idm701100, em que \"Laufzeit Zirkulation\" e um campo não identificado tinham os nomes de objeto trocados. Verificado, mas deixado intencionalmente inalterado: \"Puffer vorhanden\"/\"Schichttrennplatte\" no idm701100/S_H726100 pareciam precisar da mesma correção de 1 byte segundo documentos de referência mais antigos, mas capturas em tempo real do hardware confirmaram que a definição atual de 2 bytes é, na verdade, a correta para essas duas versões de controle",
|
|
11
|
+
"nl": "opgelost: \"Heizkreis-A.Absenkfaktor\" was bij S_H726100 ten onrechte als 1 byte in plaats van 2 gedefinieerd - het daaropvolgende, voorheen niet-geïdentificeerde \"padding\"-byte was in werkelijkheid zijn eigen hoge byte (bevestigd door zowel makki's originele referentiegegevens als live waarden rechtstreeks van Klaus' draaiende warmtepomp); ook een kopieerfout bij idm701100 opgelost waarbij \"Laufzeit Zirkulation\" en een niet-geïdentificeerd veld hun objectnamen hadden verwisseld. Gecontroleerd maar opzettelijk ongewijzigd gelaten: \"Puffer vorhanden\"/\"Schichttrennplatte\" bij idm701100/S_H726100 leken volgens oudere referentiedocumenten dezelfde 1-byte-fix nodig te hebben, maar live hardwaremetingen bevestigden dat de huidige 2-byte-definitie voor deze twee besturingsversies daadwerkelijk correct is",
|
|
12
|
+
"fr": "corrigé : \"Heizkreis-A.Absenkfaktor\" était déclaré sur 1 octet au lieu de 2 sur S_H726100 - l'octet de \"padding\" suivant, jusqu'alors non identifié, était en réalité son propre octet de poids fort (confirmé à la fois par les données de référence originales de makki et par des valeurs lues en direct sur la pompe à chaleur de Klaus) ; correction également d'une confusion de copier/coller sur idm701100, où \"Laufzeit Zirkulation\" et un champ non identifié avaient leurs noms d'objet échangés. Vérifié mais volontairement laissé inchangé : \"Puffer vorhanden\"/\"Schichttrennplatte\" sur idm701100/S_H726100 semblaient nécessiter le même correctif d'1 octet selon d'anciens documents de référence, mais des captures en direct sur du matériel réel ont confirmé que la définition actuelle sur 2 octets est en fait correcte pour ces deux versions de régulation",
|
|
13
|
+
"it": "risolto: \"Heizkreis-A.Absenkfaktor\" era dichiarato come 1 byte invece di 2 su S_H726100 - il byte di \"padding\" successivo, fino ad ora non identificato, era in realtà il suo byte alto (confermato sia dai dati di riferimento originali di makki sia da valori letti in diretta dalla pompa di calore di Klaus); corretto anche un errore di copia/incolla su idm701100, dove \"Laufzeit Zirkulation\" e un campo non identificato avevano i nomi oggetto scambiati. Verificato ma volutamente lasciato invariato: \"Puffer vorhanden\"/\"Schichttrennplatte\" su idm701100/S_H726100 sembravano richiedere la stessa correzione a 1 byte secondo documenti di riferimento più vecchi, ma le acquisizioni live dall'hardware reale hanno confermato che l'attuale definizione a 2 byte è in realtà quella corretta per queste due versioni di controllo",
|
|
14
|
+
"es": "corregido: \"Heizkreis-A.Absenkfaktor\" estaba declarado con 1 byte en lugar de 2 en S_H726100 - el byte de \"padding\" siguiente, hasta ahora no identificado, era en realidad su propio byte alto (confirmado tanto por los datos de referencia originales de makki como por valores en vivo leídos directamente de la bomba de calor de Klaus); también se corrigió una confusión de copiar/pegar en idm701100, donde \"Laufzeit Zirkulation\" y un campo no identificado tenían sus nombres de objeto intercambiados. Comprobado pero dejado intencionalmente sin cambios: \"Puffer vorhanden\"/\"Schichttrennplatte\" en idm701100/S_H726100 parecían necesitar la misma corrección de 1 byte según documentos de referencia más antiguos, pero capturas en vivo de hardware real confirmaron que la definición actual de 2 bytes es, de hecho, la correcta para estas dos versiones de control",
|
|
15
|
+
"pl": "naprawiono: \"Heizkreis-A.Absenkfaktor\" był błędnie zadeklarowany jako 1 bajt zamiast 2 w S_H726100 - następujący po nim, wcześniej niezidentyfikowany bajt \"padding\" był w rzeczywistości jego własnym starszym bajtem (potwierdzone zarówno przez oryginalne dane referencyjne makki, jak i przez wartości odczytane na żywo z działającej pompy ciepła Klausa); naprawiono też pomyłkę powstałą przy kopiowaniu w idm701100, gdzie \"Laufzeit Zirkulation\" i niezidentyfikowane pole miały zamienione nazwy obiektów. Sprawdzono, ale celowo pozostawiono bez zmian: \"Puffer vorhanden\"/\"Schichttrennplatte\" w idm701100/S_H726100 wyglądały, jakby wymagały tej samej poprawki na 1 bajt według starszych dokumentów referencyjnych, jednak zrzuty na żywo z rzeczywistego sprzętu potwierdziły, że obecna definicja 2-bajtowa jest w rzeczywistości poprawna dla tych dwóch wersji sterowania",
|
|
16
|
+
"zh-cn": "修复:S_H726100 上 \"Heizkreis-A.Absenkfaktor\" 被错误地声明为 1 字节而非 2 字节——紧随其后的、此前未识别的\"填充\"字节实际上是它自己的高位字节(通过 makki 的原始参考数据以及直接从 Klaus 运行中的热泵读取的实时数值共同确认);同时修复了 idm701100 上的一个复制粘贴混淆问题,\"Laufzeit Zirkulation\" 与一个未识别字段的对象名称被互换了。已检查但有意保持不变:根据较旧的参考文档,idm701100/S_H726100 上的 \"Puffer vorhanden\"/\"Schichttrennplatte\" 看起来也需要同样的 1 字节修复,但来自真实硬件的实时采集数据确认,目前的 2 字节定义对这两个控制版本实际上才是正确的",
|
|
17
|
+
"uk": "виправлено: \"Heizkreis-A.Absenkfaktor\" на S_H726100 був оголошений як 1 байт замість 2 - наступний за ним, раніше невідомий \"padding\"-байт насправді був його власним старшим байтом (підтверджено як оригінальними довідковими даними makki, так і живими значеннями, зчитаними прямо з працюючого теплового насоса Клауса); також виправлено плутанину через копіювання в idm701100, де \"Laufzeit Zirkulation\" та невідоме поле мали переплутані імена об'єктів. Перевірено, але свідомо залишено без змін: \"Puffer vorhanden\"/\"Schichttrennplatte\" на idm701100/S_H726100 виглядали так, ніби потребують того самого виправлення на 1 байт згідно зі старішими довідковими документами, але живі дані з реального обладнання підтвердили, що поточне визначення в 2 байти насправді правильне для цих двох версій керування"
|
|
18
|
+
},
|
|
19
|
+
"2.2.4": {
|
|
20
|
+
"en": "fixed the same \"marked read-only by mistake\" bug for \"Waermepumpe.Maximaltemperatur\" on EVR752101 (found by cross-checking all six firmware definitions against each other, same pattern as the Heizkreis B fix in 2.2.3); added a permanent automated test that cross-checks every bundled firmware definition against the others so this class of bug gets caught by CI from now on, instead of needing a one-off manual check",
|
|
21
|
+
"de": "denselben \"versehentlich nur lesbar markiert\"-Fehler auch für \"Waermepumpe.Maximaltemperatur\" bei EVR752101 behoben (gefunden durch Quervergleich aller sechs Firmware-Definitionen, gleiches Muster wie der Heizkreis-B-Fix in 2.2.3); ein dauerhafter automatisierter Test hinzugefügt, der alle mitgelieferten Firmware-Definitionen gegeneinander prüft, damit diese Fehlerklasse ab sofort von der CI erkannt wird statt eine manuelle Einzelprüfung zu brauchen",
|
|
22
|
+
"ru": "исправлена та же ошибка \"случайно помечено только для чтения\" для \"Waermepumpe.Maximaltemperatur\" на EVR752101 (найдена путём сверки всех шести определений прошивок друг с другом, та же схема, что и исправление Heizkreis B в 2.2.3); добавлен постоянный автоматический тест, сверяющий все встроенные определения прошивок друг с другом, чтобы такие ошибки теперь выявлялись CI",
|
|
23
|
+
"pt": "corrigido o mesmo erro de \"marcado como somente leitura por engano\" para \"Waermepumpe.Maximaltemperatur\" no EVR752101 (encontrado ao comparar todas as seis definições de firmware entre si, mesmo padrão da correção do Heizkreis B na 2.2.3); adicionado um teste automatizado permanente que compara todas as definições de firmware incluídas entre si, para que esse tipo de erro seja detectado pela CI a partir de agora",
|
|
24
|
+
"nl": "dezelfde \"per ongeluk alleen-lezen\"-fout ook opgelost voor \"Waermepumpe.Maximaltemperatur\" op EVR752101 (gevonden door alle zes firmware-definities onderling te vergelijken, zelfde patroon als de Heizkreis B-fix in 2.2.3); een permanente geautomatiseerde test toegevoegd die alle meegeleverde firmware-definities onderling controleert, zodat dit type fout voortaan door CI wordt opgemerkt",
|
|
25
|
+
"fr": "correction du même bug \"marqué par erreur en lecture seule\" pour \"Waermepumpe.Maximaltemperatur\" sur EVR752101 (trouvé en comparant les six définitions de firmware entre elles, même schéma que le correctif Heizkreis B de la 2.2.3) ; ajout d'un test automatisé permanent qui compare toutes les définitions de firmware fournies entre elles, afin que ce type de bug soit désormais détecté par la CI",
|
|
26
|
+
"it": "corretto lo stesso bug \"erroneamente contrassegnato come sola lettura\" per \"Waermepumpe.Maximaltemperatur\" su EVR752101 (trovato confrontando tutte le sei definizioni firmware tra loro, stesso schema della correzione Heizkreis B nella 2.2.3); aggiunto un test automatico permanente che confronta tutte le definizioni firmware incluse tra loro, così questo tipo di bug viene ora rilevato dalla CI",
|
|
27
|
+
"es": "corregido el mismo error de \"marcado como solo lectura por error\" para \"Waermepumpe.Maximaltemperatur\" en EVR752101 (encontrado al comparar las seis definiciones de firmware entre sí, mismo patrón que la corrección de Heizkreis B en 2.2.3); se añadió una prueba automatizada permanente que compara todas las definiciones de firmware incluidas entre sí, para que este tipo de error ahora lo detecte la CI",
|
|
28
|
+
"pl": "naprawiono ten sam błąd \"omyłkowo oznaczone jako tylko do odczytu\" dla \"Waermepumpe.Maximaltemperatur\" w EVR752101 (znaleziony przez wzajemne porównanie wszystkich sześciu definicji firmware, ten sam wzorzec co poprawka Heizkreis B w 2.2.3); dodano stały zautomatyzowany test porównujący wszystkie dołączone definicje firmware ze sobą, aby ten rodzaj błędu był odtąd wykrywany przez CI",
|
|
29
|
+
"zh-cn": "修复了 EVR752101 上 \"Waermepumpe.Maximaltemperatur\" 同样的\"误标记为只读\"问题(通过交叉核对全部六个固件定义发现,与 2.2.3 中 Heizkreis B 的修复模式相同);新增了一个永久性自动化测试,用于交叉核对所有内置固件定义,从此由 CI 自动捕获此类错误",
|
|
30
|
+
"uk": "виправлено ту саму помилку \"помилково позначено лише для читання\" для \"Waermepumpe.Maximaltemperatur\" на EVR752101 (знайдено шляхом звірки всіх шести визначень прошивок одне з одним, той самий шаблон, що й виправлення Heizkreis B у 2.2.3); додано постійний автоматизований тест, який звіряє всі вбудовані визначення прошивок одне з одним, щоб цей клас помилок відтепер виявляла CI"
|
|
31
|
+
},
|
|
6
32
|
"2.2.3": {
|
|
7
33
|
"en": "fixed: \"Heizkreis B\" (heating circuit B) operating mode (Betriebsart) could not be changed on the S_H726100 and idm750100 control versions - it was incorrectly marked as read-only in the data block definition (writable:false instead of true), while reading it always worked fine. All other known control versions already had this correct; the field now matches circuit A/C/D on every firmware",
|
|
8
34
|
"de": "behoben: Die Betriebsart von \"Heizkreis B\" ließ sich bei den Steuerungsversionen S_H726100 und idm750100 nicht ändern - sie war in der Datenblock-Definition fälschlich als nur lesbar markiert (writable:false statt true), Lesen funktionierte dabei immer einwandfrei. Bei allen anderen bekannten Steuerungsversionen war das bereits korrekt; das Feld verhält sich jetzt überall wie Heizkreis A/C/D",
|
|
@@ -336,20 +336,11 @@
|
|
|
336
336
|
"statename": "Heizkreis-A.Absenkfaktor",
|
|
337
337
|
"field": "faktor_A",
|
|
338
338
|
"description": "Absenkfaktor A",
|
|
339
|
-
"length":
|
|
339
|
+
"length": 2,
|
|
340
340
|
"factor": 1,
|
|
341
341
|
"writable": false,
|
|
342
342
|
"function": 50
|
|
343
343
|
},
|
|
344
|
-
{
|
|
345
|
-
"statename": "",
|
|
346
|
-
"field": "padding5",
|
|
347
|
-
"description": "padding5",
|
|
348
|
-
"length": 1,
|
|
349
|
-
"factor": 1,
|
|
350
|
-
"writable": false,
|
|
351
|
-
"function": -1
|
|
352
|
-
},
|
|
353
344
|
{
|
|
354
345
|
"statename": "Heizkreis-A.Schnellabsenkung",
|
|
355
346
|
"field": "absenkA",
|
|
@@ -91,8 +91,8 @@
|
|
|
91
91
|
"function": 55
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
|
-
"statename": "Heizung.
|
|
95
|
-
"field": "
|
|
94
|
+
"statename": "Heizung.LaufzeitZirkulation",
|
|
95
|
+
"field": "zirkzeit",
|
|
96
96
|
"description": "Laufzeit Zirkulation",
|
|
97
97
|
"length": 2,
|
|
98
98
|
"factor": 1,
|
|
@@ -118,8 +118,8 @@
|
|
|
118
118
|
"function": 56
|
|
119
119
|
},
|
|
120
120
|
{
|
|
121
|
-
"statename": "Heizung.
|
|
122
|
-
"field": "
|
|
121
|
+
"statename": "Heizung.unbekannt",
|
|
122
|
+
"field": "unbekannt",
|
|
123
123
|
"description": "unbekannt",
|
|
124
124
|
"length": 2,
|
|
125
125
|
"factor": 1,
|
package/lib/idm-protocol.test.js
CHANGED
|
@@ -119,7 +119,7 @@ describe('idm-protocol', () => {
|
|
|
119
119
|
|
|
120
120
|
it('S_H726100', () => {
|
|
121
121
|
expectParse('S_H726100', '03', '00002E001200010F00000001000B2701000100260200000000000000', 'padding:0; Warmwasser-Sollwert:46; Sommer-Winter-Umsch.:18; autom. WP Zuschaltung:1; WP Zuschaltzeit:15; Notbetrieb:0; Bad-Sommerbetrieb:0; Schichttrennplatte:1; min. Drehzahl HZK-Pumpe:9995; Puffer vorhanden:1; Laufzeit Zirkulation:1; gew. HGL-Temperatur:55; Funktion ext. Kontakt:0; Restzeit?:0; * add data: 000000');
|
|
122
|
-
expectParse('S_H726100', '04', '0000010400150013000102002D00010012002D000100030A0001FA0005000014000101000003000300FA00FA000001000005000500010100001E001E00320032000A000A00100010006400640001010A000A0014001400', 'padding:0; Frostschutz:1; Kennlinie:4; Nenntemperatur:21; Spartemperatur:19; Art des Heizkreises:1; Betriebsart:2; Maximaltemperatur:45; Raumeinfluss:1; Betriebsart Warmwasser:0; Minimaltemperatur:18; Anteil Raumeinfluss:45; Raumeinfluss von:1; Raumeinfluss auf:0; mit Mischer A:3; padding2:10; passing3:1; padding4:250; Absenkfaktor A:5;
|
|
122
|
+
expectParse('S_H726100', '04', '0000010400150013000102002D00010012002D000100030A0001FA0005000014000101000003000300FA00FA000001000005000500010100001E001E00320032000A000A00100010006400640001010A000A0014001400', 'padding:0; Frostschutz:1; Kennlinie:4; Nenntemperatur:21; Spartemperatur:19; Art des Heizkreises:1; Betriebsart:2; Maximaltemperatur:45; Raumeinfluss:1; Betriebsart Warmwasser:0; Minimaltemperatur:18; Anteil Raumeinfluss:45; Raumeinfluss von:1; Raumeinfluss auf:0; mit Mischer A:3; padding2:10; passing3:1; padding4:250; Absenkfaktor A:5; Schnellabsenkung A:0; Konstanttemperatur A:20; mit Mischer C:1; mit Mischer D:1; Schnellabsenkung C:0; Schnellabsenkung D:0; Betriebsart C:3; Betriebsart D:3; padding6:250; Raumeinfluss auf C:0; padding7:250; Raumeinfluss auf D:0; padding8:256; Raumeinfluss C:0; Raumeinfluss D:0; Absenkfaktor C:5; Absenkfaktor D:5; Art des Heizkreises C:1; Art des Heizkreises D:1; Frostschutz C:0; Frostschutz D:0; Konstanttemperatur C:30; Konstanttemperatur D:30; Maximaltemperatur C:50; Maximaltemperatur D:50; Minimaltemperatur C:10; Minimaltemperatur D:10; Spartemperatur C:16; Spartemperatur D:16; Anteil Raumeinfluss C:100; Anteil Raumeinfluss D:100; Raumeinfluss von C:1; Raumeinfluss von D:1; Kennlinie C:10; Kennlinie D:10; Nenntemperatur C:20; Nenntemperatur D:20; ');
|
|
123
123
|
expectParse('S_H726100', '05', '0000000132000A00140010000300000A00640002010500001E000600FA00', 'padding:0; Frostschutz B:0; Art HK B:1; Maximaltemp HK B:50; Kennlinie HK B:10; Nenntemp HK B:20; Spartemp HK B:16; Betriebsart HK B:3; Raumeinfluss HK B:0; Minimaltemp HK B:10; Anteil Raumeinfluss B:100; Raumeinfluss B von:2; Raumeinfluss B auf:1; Absenkfaktor B:5; HK B mit Mischer:0; Konstanttemp B:30; Schnellabsenkung B:6; * add data: 00FA00');
|
|
124
124
|
expectParse('S_H726100', '06', '00000101040039000A000A00F1FFEEFF0002001E000000', 'padding:0; WP-Freigabe:1; wp?:1; WP Schaltdifferenz:4; WP Maximaltemp.:57; min. WP Laufzeit:10; min. WP Stehzeit:10; min. Solewarnung:-15; min. Solealarm:-18; min Soletemp:512; WP-Freigabe Kunde:0; Ueberhoehung Stromsperrung:30; Vorverlegezeit Stromsperrung:0; * add data: 00');
|
|
125
125
|
expectParse('S_H726100', '07', '000000000000000000000000000000000000000000000000000001000000000000000000', 'padding:0; padding2:0; Relais1 Solepumpe:0; Relais2 WP Stufe 1:0; Relais3 Mischer A - auf:0; Relais4 Mischer A - zu:0; Relais5 WP Stufe 2:0; Relais6 Pumpe Heizkreis B:0; Relais7 Mischer B - auf:0; Relais8 Mischer B - zu:0; Relais9 Kühlventil:0; Relais10 HG-Mischer - auf:0; Relais11 HG-Mischer - zu:0; Relais12 Zirkulationspumpe:0; Relais13 Störmeldeausgang:0; Triac Plattentauscherpumpe:0; Triac Ladepumpe:0; Triac Pumpe Heizkreis A:0; Störung Übertemperatur:0; padding3:0; padding4:0; Telefonkontakt:1; * add data: 000000000000000000');
|
|
@@ -52,6 +52,126 @@ describe('idm_datablocks (data blocks loader)', () => {
|
|
|
52
52
|
});
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
+
// Catches transcription bugs like the one fixed in 2.2.3 (and again in 2.2.4): a field
|
|
56
|
+
// was accidentally copy-pasted with the wrong "writable" flag into exactly one of the six
|
|
57
|
+
// bundled files, so "Heizkreis B" could be read but never changed on that control version.
|
|
58
|
+
// A field is the "same" field across firmware files when it shares both a statename AND a
|
|
59
|
+
// function (register) id there - the protocol has no other way to say "this register is
|
|
60
|
+
// the same thing on every control version". writable/length/factor MUST then match: they
|
|
61
|
+
// describe how the register is framed on the wire and whether writes are even attempted,
|
|
62
|
+
// none of which plausibly differs by firmware revision for the same physical register.
|
|
63
|
+
// min/max are treated more leniently: today only S_H726100 (and partially EVR752101) has
|
|
64
|
+
// hand-verified limits (see README - "neither source documents official min/max limits"),
|
|
65
|
+
// so one side being undocumented (undefined) while the other has a real value is expected,
|
|
66
|
+
// not a bug. Two DIFFERENT non-undefined bounds for the same register would still fail.
|
|
67
|
+
describe('cross-firmware consistency of the bundled definitions', () => {
|
|
68
|
+
// Each entry: a (statename, function) pair that genuinely differs across firmware files
|
|
69
|
+
// as of 2026-10. One other that used to be listed here (Heizkreis-A.Absenkfaktor) was
|
|
70
|
+
// confirmed and fixed in 2.2.5: makki's original idm712/idm750 source data (Klaus found
|
|
71
|
+
// and shared both idm712-datatype.txt and idm750_Datatypes.csv - our bundled
|
|
72
|
+
// idm712100.json and idm750100.json already matched them with 0 discrepancies out of
|
|
73
|
+
// 120/142 fields each) said Absenkfaktor A is 2 bytes everywhere, and S_H726100's block
|
|
74
|
+
// 04 had an unexplained 1-byte "padding5" entry (function: -1, i.e. nobody had ever
|
|
75
|
+
// identified what that byte was for) sitting immediately AFTER a 1-byte Absenkfaktor A.
|
|
76
|
+
// That byte was never padding - it was Absenkfaktor's own second byte, misclassified as
|
|
77
|
+
// unknown filler. Widening Absenkfaktor to 2 bytes and removing the adjacent padding5
|
|
78
|
+
// entry keeps block 04's hardware-confirmed wireLength (87) exactly satisfied while
|
|
79
|
+
// every later field lands at the same offset as before. Klaus independently spotted the
|
|
80
|
+
// same fix by reading fresh values straight off his running adapter: with the old 1-byte
|
|
81
|
+
// field, Absenkfaktor A read 5 and the very next (phantom) padding5 read 0 - exactly the
|
|
82
|
+
// low/high byte pair you'd expect for a 2-byte value of 5, matching Absenkfaktor C/D
|
|
83
|
+
// (already 2 bytes) which also read 5 on his hardware.
|
|
84
|
+
//
|
|
85
|
+
// Heizung.PufferVorhanden and Heizung.SchichttrennplatteVorhanden were the INVERSE
|
|
86
|
+
// lesson, and are listed below rather than fixed: the same source documents say both are
|
|
87
|
+
// 1 byte, and idm712100/idm722100/idm750100/EVR752101 do use 1 byte - but shrinking them
|
|
88
|
+
// on idm701100 and S_H726100 (both currently 2 bytes) does NOT produce sane output. Live
|
|
89
|
+
// block 03 reads from Klaus's actual S_H726100 hardware, and this project's own
|
|
90
|
+
// regression-snapshot captures (lib/idm-protocol.test.js) for both idm701100 and
|
|
91
|
+
// S_H726100, decode to sensible values (booleans 0/1, small Laufzeit Zirkulation,
|
|
92
|
+
// plausible min. Drehzahl HZK-Pumpe) ONLY with the current 2-byte lengths; shrinking
|
|
93
|
+
// either field by 1 byte shifts every subsequent field in the block and turns all of
|
|
94
|
+
// them into nonsense (e.g. Puffer vorhanden reading 39, Laufzeit Zirkulation reading
|
|
95
|
+
// 2560). Unlike Absenkfaktor, no adjacent misclassified padding field was found that
|
|
96
|
+
// would absorb a 1-byte shrink here - so, exactly like Heizkreis-A.Absenkfaktor before it
|
|
97
|
+
// was understood, treat the source documents as describing idm712100/idm750100 correctly
|
|
98
|
+
// but NOT idm701100/S_H726100 for this specific pair of fields, until a live capture
|
|
99
|
+
// (not just another reference document) proves otherwise.
|
|
100
|
+
//
|
|
101
|
+
// Waermepumpe.MinimaleLaufzeit remains unresolved for a different reason: neither
|
|
102
|
+
// reference file has a "writable" column (they only cover Id/Block-Id/Beschreibung/
|
|
103
|
+
// Name/Groesse/Faktor), so they cannot adjudicate a writable-flag disagreement at all.
|
|
104
|
+
const KNOWN_UNRESOLVED_DIFFERENCES = new Set([
|
|
105
|
+
'Waermepumpe.MinimaleLaufzeit/38', // writable: true on idm712100/idm722100, false elsewhere
|
|
106
|
+
'Heizung.SchichttrennplatteVorhanden/55', // length: 2 on idm701100/S_H726100, 1 everywhere else (incl. source docs)
|
|
107
|
+
'Heizung.PufferVorhanden/56', // length: 2 on idm701100/S_H726100, 1 everywhere else (incl. source docs)
|
|
108
|
+
]);
|
|
109
|
+
|
|
110
|
+
it('keeps writable/length/factor identical for the same (statename, function) across every firmware', () => {
|
|
111
|
+
/** @type {Map<string, {file: string, writable: boolean, length: number, factor: number, min?: number, max?: number}[]>} */
|
|
112
|
+
const byKey = new Map();
|
|
113
|
+
for (const { file, data } of idm_datablocks.readVersionFilesFrom(idm_datablocks.BUNDLED_DIR)) {
|
|
114
|
+
for (const block of data.data_blocks) {
|
|
115
|
+
for (const field of block.definition) {
|
|
116
|
+
if (!field.statename || field.function === -1) continue; // padding/unidentified
|
|
117
|
+
const key = field.statename + '/' + field.function;
|
|
118
|
+
let list = byKey.get(key);
|
|
119
|
+
if (!list) {
|
|
120
|
+
list = [];
|
|
121
|
+
byKey.set(key, list);
|
|
122
|
+
}
|
|
123
|
+
list.push({ file, writable: field.writable, length: field.length, factor: field.factor, min: field.min, max: field.max });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const problems = [];
|
|
129
|
+
for (const [key, entries] of byKey) {
|
|
130
|
+
if (entries.length < 2 || KNOWN_UNRESOLVED_DIFFERENCES.has(key)) continue;
|
|
131
|
+
|
|
132
|
+
for (const attr of ['writable', 'length', 'factor']) {
|
|
133
|
+
const values = new Set(entries.map(e => e[attr]));
|
|
134
|
+
if (values.size > 1) {
|
|
135
|
+
problems.push(key + ': ' + attr + ' differs - ' + entries.map(e => e.file.split('/').pop() + '=' + e[attr]).join(', '));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
for (const attr of ['min', 'max']) {
|
|
139
|
+
const defined = entries.map(e => e[attr]).filter(v => v !== undefined);
|
|
140
|
+
if (new Set(defined).size > 1) {
|
|
141
|
+
problems.push(key + ': ' + attr + ' disagrees (not just undocumented) - ' + entries.map(e => e.file.split('/').pop() + '=' + e[attr]).join(', '));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
expect(problems, 'found inconsistent field definitions for what should be the same register - see KNOWN_UNRESOLVED_DIFFERENCES above if this is an intentional, confirmed difference').to.deep.equal([]);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('fails loudly if a KNOWN_UNRESOLVED_DIFFERENCES entry stops being a real difference (so it gets removed, not forgotten)', () => {
|
|
150
|
+
/** @type {Map<string, Set<string>>} */
|
|
151
|
+
const byKey = new Map();
|
|
152
|
+
for (const { data } of idm_datablocks.readVersionFilesFrom(idm_datablocks.BUNDLED_DIR)) {
|
|
153
|
+
for (const block of data.data_blocks) {
|
|
154
|
+
for (const field of block.definition) {
|
|
155
|
+
if (!field.statename || field.function === -1) continue;
|
|
156
|
+
const key = field.statename + '/' + field.function;
|
|
157
|
+
if (!KNOWN_UNRESOLVED_DIFFERENCES.has(key)) continue;
|
|
158
|
+
let seen = byKey.get(key);
|
|
159
|
+
if (!seen) {
|
|
160
|
+
seen = new Set();
|
|
161
|
+
byKey.set(key, seen);
|
|
162
|
+
}
|
|
163
|
+
seen.add(JSON.stringify({ writable: field.writable, length: field.length, factor: field.factor }));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
for (const key of KNOWN_UNRESOLVED_DIFFERENCES) {
|
|
168
|
+
const seen = byKey.get(key);
|
|
169
|
+
expect(seen, key + ' is listed as unresolved but no longer appears in the bundled files - remove it from the list').to.not.be.undefined;
|
|
170
|
+
expect(seen ? seen.size : 0, key + ' is listed as unresolved but all bundled files now agree - remove it from the list').to.be.greaterThan(1);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
55
175
|
describe('validateVersionFile', () => {
|
|
56
176
|
it('rejects a non-object root', () => {
|
|
57
177
|
expect(idm_datablocks.validateVersionFile(null)).to.not.be.empty;
|
package/main.js
CHANGED
|
@@ -49,7 +49,7 @@ class IdmMultitalent002 extends utils.Adapter {
|
|
|
49
49
|
|
|
50
50
|
statesCreated;
|
|
51
51
|
statesSubscribed;
|
|
52
|
-
|
|
52
|
+
idmControlVersion;
|
|
53
53
|
connectedToIDM;
|
|
54
54
|
stateNameMap = new Map();
|
|
55
55
|
// Last value actually confirmed for a state - either read from the heat pump, or a write
|
|
@@ -158,7 +158,7 @@ class IdmMultitalent002 extends utils.Adapter {
|
|
|
158
158
|
// create the states
|
|
159
159
|
async CreateStates() {
|
|
160
160
|
this.log.debug('creating states');
|
|
161
|
-
const dataBlocks = this.idm.getDataBlocks(this.
|
|
161
|
+
const dataBlocks = this.idm.getDataBlocks(this.idmControlVersion); // get the known data blocks for the connected version
|
|
162
162
|
|
|
163
163
|
if (!dataBlocks) {
|
|
164
164
|
this.log.warn('no data blocks defined, no states will be created');
|
|
@@ -168,7 +168,7 @@ class IdmMultitalent002 extends utils.Adapter {
|
|
|
168
168
|
// Wait for every state to actually be created before flagging statesCreated/statesSubscribed -
|
|
169
169
|
// Array.prototype.forEach does not await its (async) callback, so this used to mark the states
|
|
170
170
|
// as created while most of the setObjectNotExistsAsync calls were still in flight.
|
|
171
|
-
await this.idm.mapStatenames(this.
|
|
171
|
+
await this.idm.mapStatenames(this.idmControlVersion, this.createIDMState.bind(this));
|
|
172
172
|
for (const element of dataBlocks) {
|
|
173
173
|
const stateName = 'Data_block_' + idm_u.get_byte(element);
|
|
174
174
|
await this.setObjectNotExistsAsync(stateName, {
|
|
@@ -253,7 +253,7 @@ class IdmMultitalent002 extends utils.Adapter {
|
|
|
253
253
|
});
|
|
254
254
|
},
|
|
255
255
|
onVersion: (version) => {
|
|
256
|
-
this.
|
|
256
|
+
this.idmControlVersion = version;
|
|
257
257
|
if (this.idm.dataDefinitions.has(version)) {
|
|
258
258
|
const sourceKind = this.idm.isCustomDefinition(version) ? 'custom override' : 'bundled';
|
|
259
259
|
this.log.info('heat pump reports version "' + version + '" - using its ' + sourceKind + ' data block definition (' + this.idm.dataSources.get(version) + ')');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.idm-multitalent_002",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.5",
|
|
4
4
|
"description": "Read and write values of a iDM heatpump with multitalent.002 control.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "zloe",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"@alcalzone/release-script-plugin-license": "^5.2.2",
|
|
32
32
|
"@eslint/js": "^10.0.1",
|
|
33
33
|
"@iobroker/testing": "^6.2.2",
|
|
34
|
+
"@tsconfig/node22": "^22.0.6",
|
|
34
35
|
"@types/gulp": "^4.0.18",
|
|
35
36
|
"@types/node": "^22.20.4",
|
|
36
37
|
"@types/proxyquire": "^1.3.31",
|