iobroker.idm-multitalent_002 2.2.2 → 2.2.4
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
|
@@ -76,6 +76,13 @@ 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
|
+
|
|
83
|
+
### 2.2.3 (2026-10-10)
|
|
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`
|
|
85
|
+
|
|
79
86
|
### 2.2.2 (2026-09-13)
|
|
80
87
|
* (zloe) scheduler tests (sensor/settings priority, sweep completion, no starvation, debug-level logging) now run against every bundled firmware, not just idm701100/S_H726100 - and against a synthetic, non-bundled definition too, proving the scheduler doesn't just happen to work for the shapes this project ships, but for any valid "Custom data blocks directory" file a user adds themselves
|
|
81
88
|
* (zloe) docs: the hardware/RS422 setup instructions have their own clear, numbered "Hardware setup" section now, instead of being mixed into the intro alongside a duplicate (and out-of-place) explanation of the polling architecture
|
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.4",
|
|
5
5
|
"news": {
|
|
6
|
+
"2.2.4": {
|
|
7
|
+
"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",
|
|
8
|
+
"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",
|
|
9
|
+
"ru": "исправлена та же ошибка \"случайно помечено только для чтения\" для \"Waermepumpe.Maximaltemperatur\" на EVR752101 (найдена путём сверки всех шести определений прошивок друг с другом, та же схема, что и исправление Heizkreis B в 2.2.3); добавлен постоянный автоматический тест, сверяющий все встроенные определения прошивок друг с другом, чтобы такие ошибки теперь выявлялись CI",
|
|
10
|
+
"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",
|
|
11
|
+
"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",
|
|
12
|
+
"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",
|
|
13
|
+
"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",
|
|
14
|
+
"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",
|
|
15
|
+
"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",
|
|
16
|
+
"zh-cn": "修复了 EVR752101 上 \"Waermepumpe.Maximaltemperatur\" 同样的\"误标记为只读\"问题(通过交叉核对全部六个固件定义发现,与 2.2.3 中 Heizkreis B 的修复模式相同);新增了一个永久性自动化测试,用于交叉核对所有内置固件定义,从此由 CI 自动捕获此类错误",
|
|
17
|
+
"uk": "виправлено ту саму помилку \"помилково позначено лише для читання\" для \"Waermepumpe.Maximaltemperatur\" на EVR752101 (знайдено шляхом звірки всіх шести визначень прошивок одне з одним, той самий шаблон, що й виправлення Heizkreis B у 2.2.3); додано постійний автоматизований тест, який звіряє всі вбудовані визначення прошивок одне з одним, щоб цей клас помилок відтепер виявляла CI"
|
|
18
|
+
},
|
|
19
|
+
"2.2.3": {
|
|
20
|
+
"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",
|
|
21
|
+
"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",
|
|
22
|
+
"ru": "исправлено: режим работы \"Heizkreis B\" (контур отопления B) нельзя было изменить на версиях управления S_H726100 и idm750100 - в определении блока данных он был ошибочно помечен только для чтения (writable:false вместо true), при этом чтение всегда работало корректно. На всех остальных известных версиях это уже было верно; теперь поле ведёт себя так же, как контуры A/C/D",
|
|
23
|
+
"pt": "corrigido: o modo de operação do \"Heizkreis B\" (circuito de aquecimento B) não podia ser alterado nas versões de controle S_H726100 e idm750100 - estava incorretamente marcado como somente leitura na definição do bloco de dados (writable:false em vez de true), embora a leitura sempre funcionasse. Em todas as outras versões conhecidas isso já estava correto; o campo agora se comporta como os circuitos A/C/D em todos os firmwares",
|
|
24
|
+
"nl": "opgelost: de bedrijfsmodus van \"Heizkreis B\" (verwarmingscircuit B) kon niet worden gewijzigd bij de besturingsversies S_H726100 en idm750100 - het was in de datablokdefinitie ten onrechte als alleen-lezen gemarkeerd (writable:false in plaats van true), terwijl lezen altijd goed werkte. Bij alle andere bekende besturingsversies was dit al correct; het veld gedraagt zich nu overal zoals circuit A/C/D",
|
|
25
|
+
"fr": "corrigé : le mode de fonctionnement de \"Heizkreis B\" (circuit de chauffage B) ne pouvait pas être modifié sur les versions de régulation S_H726100 et idm750100 - il était incorrectement marqué en lecture seule dans la définition du bloc de données (writable:false au lieu de true), alors que la lecture fonctionnait toujours correctement. Sur toutes les autres versions de régulation connues, c'était déjà correct ; le champ se comporte désormais comme les circuits A/C/D sur tous les firmwares",
|
|
26
|
+
"it": "risolto: la modalità operativa di \"Heizkreis B\" (circuito di riscaldamento B) non poteva essere modificata sulle versioni di controllo S_H726100 e idm750100 - era erroneamente contrassegnata come sola lettura nella definizione del blocco dati (writable:false invece di true), mentre la lettura ha sempre funzionato correttamente. Su tutte le altre versioni di controllo note era già corretto; il campo ora si comporta come i circuiti A/C/D su ogni firmware",
|
|
27
|
+
"es": "corregido: el modo de funcionamiento de \"Heizkreis B\" (circuito de calefacción B) no se podía cambiar en las versiones de control S_H726100 e idm750100 - estaba marcado incorrectamente como de solo lectura en la definición del bloque de datos (writable:false en lugar de true), aunque la lectura siempre funcionó correctamente. En todas las demás versiones de control conocidas ya era correcto; el campo ahora se comporta como los circuitos A/C/D en todos los firmwares",
|
|
28
|
+
"pl": "naprawiono: tryb pracy \"Heizkreis B\" (obiegu grzewczego B) nie mógł być zmieniany w wersjach sterowania S_H726100 i idm750100 - w definicji bloku danych był błędnie oznaczony jako tylko do odczytu (writable:false zamiast true), podczas gdy odczyt zawsze działał poprawnie. We wszystkich innych znanych wersjach sterowania było to już poprawne; pole zachowuje się teraz tak samo jak obiegi A/C/D we wszystkich firmware'ach",
|
|
29
|
+
"zh-cn": "修复:在 S_H726100 和 idm750100 控制版本上,\"Heizkreis B\"(B 采暖回路)的运行模式无法更改——数据块定义中该字段被错误标记为只读(writable:false 而非 true),而读取始终正常。所有其他已知控制版本此前已是正确的;现在该字段在所有固件上的行为与 A/C/D 回路一致",
|
|
30
|
+
"uk": "виправлено: режим роботи \"Heizkreis B\" (контуру опалення B) не можна було змінити на версіях керування S_H726100 та idm750100 - у визначенні блоку даних його помилково позначено як тільки для читання (writable:false замість true), хоча читання завжди працювало коректно. На всіх інших відомих версіях керування це вже було правильно; тепер поле поводиться так само, як контури A/C/D на будь-якій прошивці"
|
|
31
|
+
},
|
|
6
32
|
"2.2.2": {
|
|
7
33
|
"en": "scheduler tests now cover every bundled firmware plus a synthetic custom definition, not just two; hardware/RS422 setup now has its own clear, step-by-step section in the README; general housekeeping ahead of submitting to the official ioBroker adapter repository (dependency cleanup, CI matrix, stale changelog entry removed)",
|
|
8
34
|
"de": "Scheduler-Tests laufen jetzt für alle mitgelieferten Firmwares sowie eine synthetische Custom-Definition, nicht nur für zwei; die Hardware-/RS422-Einrichtung hat jetzt einen eigenen, klaren Schritt-für-Schritt-Abschnitt im README; allgemeine Aufräumarbeiten vor der Einreichung ins offizielle ioBroker-Adapter-Repository (Abhängigkeiten bereinigt, CI-Matrix erweitert, veralteten Changelog-Eintrag entfernt)",
|
|
@@ -52,6 +52,99 @@ 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 found to genuinely differ across firmware
|
|
69
|
+
// files as of 2026-10, left alone rather than "fixed" because changing length/factor
|
|
70
|
+
// risks silently breaking a wire format nobody has reverse-engineered a second time,
|
|
71
|
+
// and because S_H726100 is the one control version with hand-verified field lengths
|
|
72
|
+
// (confirmed live via the wireLength-learning mechanism) - so when it disagrees with
|
|
73
|
+
// the other five, it is at least as likely that THEY are the ones mistranscribed, not
|
|
74
|
+
// S_H726100. Needs confirming against source documentation (makki's KNX-forum data)
|
|
75
|
+
// or a live capture on the affected hardware before touching either side.
|
|
76
|
+
const KNOWN_UNRESOLVED_DIFFERENCES = new Set([
|
|
77
|
+
'Waermepumpe.MinimaleLaufzeit/38', // writable: true on idm712100/idm722100, false elsewhere
|
|
78
|
+
'Heizkreis-A.Absenkfaktor/50', // length: 1 on S_H726100, 2 everywhere else
|
|
79
|
+
'Heizung.PufferVorhanden/56', // length: 2 on S_H726100+idm701100, 1 elsewhere
|
|
80
|
+
'Heizung.SchichttrennplatteVorhanden/55', // length: 2 on S_H726100+idm701100, 1 elsewhere
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
it('keeps writable/length/factor identical for the same (statename, function) across every firmware', () => {
|
|
84
|
+
/** @type {Map<string, {file: string, writable: boolean, length: number, factor: number, min?: number, max?: number}[]>} */
|
|
85
|
+
const byKey = new Map();
|
|
86
|
+
for (const { file, data } of idm_datablocks.readVersionFilesFrom(idm_datablocks.BUNDLED_DIR)) {
|
|
87
|
+
for (const block of data.data_blocks) {
|
|
88
|
+
for (const field of block.definition) {
|
|
89
|
+
if (!field.statename || field.function === -1) continue; // padding/unidentified
|
|
90
|
+
const key = field.statename + '/' + field.function;
|
|
91
|
+
let list = byKey.get(key);
|
|
92
|
+
if (!list) {
|
|
93
|
+
list = [];
|
|
94
|
+
byKey.set(key, list);
|
|
95
|
+
}
|
|
96
|
+
list.push({ file, writable: field.writable, length: field.length, factor: field.factor, min: field.min, max: field.max });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const problems = [];
|
|
102
|
+
for (const [key, entries] of byKey) {
|
|
103
|
+
if (entries.length < 2 || KNOWN_UNRESOLVED_DIFFERENCES.has(key)) continue;
|
|
104
|
+
|
|
105
|
+
for (const attr of ['writable', 'length', 'factor']) {
|
|
106
|
+
const values = new Set(entries.map(e => e[attr]));
|
|
107
|
+
if (values.size > 1) {
|
|
108
|
+
problems.push(key + ': ' + attr + ' differs - ' + entries.map(e => e.file.split('/').pop() + '=' + e[attr]).join(', '));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
for (const attr of ['min', 'max']) {
|
|
112
|
+
const defined = entries.map(e => e[attr]).filter(v => v !== undefined);
|
|
113
|
+
if (new Set(defined).size > 1) {
|
|
114
|
+
problems.push(key + ': ' + attr + ' disagrees (not just undocumented) - ' + entries.map(e => e.file.split('/').pop() + '=' + e[attr]).join(', '));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
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([]);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('fails loudly if a KNOWN_UNRESOLVED_DIFFERENCES entry stops being a real difference (so it gets removed, not forgotten)', () => {
|
|
123
|
+
/** @type {Map<string, Set<string>>} */
|
|
124
|
+
const byKey = new Map();
|
|
125
|
+
for (const { data } of idm_datablocks.readVersionFilesFrom(idm_datablocks.BUNDLED_DIR)) {
|
|
126
|
+
for (const block of data.data_blocks) {
|
|
127
|
+
for (const field of block.definition) {
|
|
128
|
+
if (!field.statename || field.function === -1) continue;
|
|
129
|
+
const key = field.statename + '/' + field.function;
|
|
130
|
+
if (!KNOWN_UNRESOLVED_DIFFERENCES.has(key)) continue;
|
|
131
|
+
let seen = byKey.get(key);
|
|
132
|
+
if (!seen) {
|
|
133
|
+
seen = new Set();
|
|
134
|
+
byKey.set(key, seen);
|
|
135
|
+
}
|
|
136
|
+
seen.add(JSON.stringify({ writable: field.writable, length: field.length, factor: field.factor }));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
for (const key of KNOWN_UNRESOLVED_DIFFERENCES) {
|
|
141
|
+
const seen = byKey.get(key);
|
|
142
|
+
expect(seen, key + ' is listed as unresolved but no longer appears in the bundled files - remove it from the list').to.not.be.undefined;
|
|
143
|
+
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);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
55
148
|
describe('validateVersionFile', () => {
|
|
56
149
|
it('rejects a non-object root', () => {
|
|
57
150
|
expect(idm_datablocks.validateVersionFile(null)).to.not.be.empty;
|
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.4",
|
|
4
4
|
"description": "Read and write values of a iDM heatpump with multitalent.002 control.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "zloe",
|
|
@@ -30,12 +30,12 @@
|
|
|
30
30
|
"@alcalzone/release-script-plugin-iobroker": "^5.2.0",
|
|
31
31
|
"@alcalzone/release-script-plugin-license": "^5.2.2",
|
|
32
32
|
"@eslint/js": "^10.0.1",
|
|
33
|
-
"@iobroker/testing": "^6.2.
|
|
33
|
+
"@iobroker/testing": "^6.2.2",
|
|
34
34
|
"@types/gulp": "^4.0.18",
|
|
35
|
-
"@types/node": "^22.20.
|
|
35
|
+
"@types/node": "^22.20.4",
|
|
36
36
|
"@types/proxyquire": "^1.3.31",
|
|
37
37
|
"axios": "^1.20.0",
|
|
38
|
-
"eslint": "^10.
|
|
38
|
+
"eslint": "^10.11.0",
|
|
39
39
|
"gulp": "^5.0.1",
|
|
40
40
|
"proxyquire": "^2.1.3",
|
|
41
41
|
"typescript": "~7.0.2"
|