iobroker.zigbee2mqtt 3.1.1 → 3.2.0
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 +10 -67
- package/io-package.json +87 -61
- package/lib/check.js +6 -4
- package/lib/colors.js +9 -9
- package/lib/deviceController.js +90 -37
- package/lib/exposes.js +1362 -1350
- package/lib/imageController.js +56 -26
- package/lib/messages.js +15 -13
- package/lib/mqttServerController.js +36 -30
- package/lib/nonGenericDevicesExtension.js +2 -3
- package/lib/rgb.js +52 -63
- package/lib/states.js +142 -28
- package/lib/statesController.js +103 -45
- package/lib/utils.js +36 -47
- package/lib/websocketController.js +84 -52
- package/lib/z2mController.js +28 -16
- package/main.js +102 -23
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -22,77 +22,20 @@ This adapter allows to control the data points of the devices of a Zigbee2MQTT i
|
|
|
22
22
|
[Adapter Documentation](https://github.com/arteck/ioBroker.zigbee2mqtt/blob/main/docs/wiki.md)
|
|
23
23
|
|
|
24
24
|
## Changelog
|
|
25
|
-
### 3.
|
|
26
|
-
* (arteck)
|
|
25
|
+
### 3.2.0 (2026-04-26)
|
|
26
|
+
* (arteck) del deprectated setStateAsync
|
|
27
27
|
|
|
28
|
-
### 3.1.
|
|
29
|
-
* (arteck)
|
|
28
|
+
### 3.1.9 (2026-04-26)
|
|
29
|
+
* (arteck) fix WS close
|
|
30
30
|
|
|
31
|
-
### 3.
|
|
32
|
-
* (arteck)
|
|
31
|
+
### 3.1.8 (2026-04-26)
|
|
32
|
+
* (arteck) back to old dependency aedes
|
|
33
33
|
|
|
34
|
-
### 3.
|
|
35
|
-
* (arteck)
|
|
34
|
+
### 3.1.7 (2026-04-24)
|
|
35
|
+
* (arteck) fix illuminance = 0
|
|
36
36
|
|
|
37
|
-
### 3.
|
|
38
|
-
* (arteck)
|
|
39
|
-
|
|
40
|
-
### 3.0.19 (2026-01-28)
|
|
41
|
-
* (arteck) modify action dp
|
|
42
|
-
|
|
43
|
-
### 3.0.18 (2026-01-28)
|
|
44
|
-
* (arteck) typo
|
|
45
|
-
|
|
46
|
-
### 3.0.17 (2026-01-28)
|
|
47
|
-
* (arteck) typo
|
|
48
|
-
|
|
49
|
-
### 3.0.16 (2026-01-28)
|
|
50
|
-
* (arteck) fix action dp
|
|
51
|
-
|
|
52
|
-
### 3.0.15 (2026-01-27)
|
|
53
|
-
* (arteck) update
|
|
54
|
-
|
|
55
|
-
### 3.0.14 (2026-01-27)
|
|
56
|
-
* (arteck) back to sharp 0.33.5
|
|
57
|
-
|
|
58
|
-
### 3.0.13 (2026-01-25)
|
|
59
|
-
* (arteck) add action dp
|
|
60
|
-
|
|
61
|
-
### 3.0.12 (2026-01-05)
|
|
62
|
-
* (arteck) Dependencies have been updated
|
|
63
|
-
* (MMeinhardt1) typo fix
|
|
64
|
-
|
|
65
|
-
### 3.0.11 (2025-12-31)
|
|
66
|
-
- (arteck) fix info.connection
|
|
67
|
-
|
|
68
|
-
### 3.0.10 (2025-12-07)
|
|
69
|
-
- (arteck) Dependencies have been updated
|
|
70
|
-
- (bluefox) Changed role of `color_temp_startup` state to `level` to avoid double `level.temperature` in one device
|
|
71
|
-
- (arteck) fix ZBMINIR2 inching DP
|
|
72
|
-
- (arteck) delete DP colortempstartup
|
|
73
|
-
|
|
74
|
-
### 3.0.9 (2025-06-19)
|
|
75
|
-
- (bjoernbusch) queue up message parsing
|
|
76
|
-
- (dotcom84) Support for non-default MQTT base topics
|
|
77
|
-
|
|
78
|
-
### 3.0.8 (2025-06-08)
|
|
79
|
-
- (arteck) fix device is deleted
|
|
80
|
-
- (arteck) fix translation
|
|
81
|
-
|
|
82
|
-
### 3.0.7 (2025-06-07)
|
|
83
|
-
- (arteck) fix jsonconf
|
|
84
|
-
|
|
85
|
-
### 3.0.6 (2025-05-31)
|
|
86
|
-
- (arteck) settings restructure
|
|
87
|
-
- (arteck) fix icon not found message
|
|
88
|
-
|
|
89
|
-
.
|
|
90
|
-
.
|
|
91
|
-
.
|
|
92
|
-
|
|
93
|
-
### 0.1.0 (2022-09-29)
|
|
94
|
-
|
|
95
|
-
- (o0shojo0o) first release
|
|
37
|
+
### 3.1.5 (2026-04-23)
|
|
38
|
+
* (arteck) fix illuminance
|
|
96
39
|
|
|
97
40
|
## License
|
|
98
41
|
|
package/io-package.json
CHANGED
|
@@ -1,72 +1,98 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "zigbee2mqtt",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.2.0",
|
|
5
5
|
"news": {
|
|
6
|
-
"3.
|
|
7
|
-
"en": "
|
|
8
|
-
"de": "
|
|
9
|
-
"ru": "
|
|
10
|
-
"pt": "
|
|
11
|
-
"nl": "
|
|
12
|
-
"fr": "
|
|
13
|
-
"it": "
|
|
14
|
-
"es": "
|
|
15
|
-
"pl": "
|
|
16
|
-
"uk": "
|
|
17
|
-
"zh-cn": "
|
|
6
|
+
"3.2.0": {
|
|
7
|
+
"en": "del deprectated setStateAsync",
|
|
8
|
+
"de": "del deprected setStateAsync",
|
|
9
|
+
"ru": "обсуждение StateAsync",
|
|
10
|
+
"pt": "del deprectated setStateAsync",
|
|
11
|
+
"nl": "del deprectated setStateAsync",
|
|
12
|
+
"fr": "set dépréciéStateAsync",
|
|
13
|
+
"it": "del set deprettatoStateAsync",
|
|
14
|
+
"es": "del deprectated setStateAsync",
|
|
15
|
+
"pl": "del deprectated setStateAsync",
|
|
16
|
+
"uk": "deprectated setStateAsync",
|
|
17
|
+
"zh-cn": "已贬值的设置"
|
|
18
18
|
},
|
|
19
|
-
"3.
|
|
20
|
-
"en": "
|
|
21
|
-
"de": "
|
|
22
|
-
"ru": "
|
|
23
|
-
"pt": "
|
|
24
|
-
"nl": "
|
|
25
|
-
"fr": "
|
|
26
|
-
"it": "
|
|
27
|
-
"es": "
|
|
28
|
-
"pl": "
|
|
29
|
-
"uk": "
|
|
30
|
-
"zh-cn": "
|
|
19
|
+
"3.1.9": {
|
|
20
|
+
"en": "fix WS close",
|
|
21
|
+
"de": "wS schließen",
|
|
22
|
+
"ru": "закрыть WS Close",
|
|
23
|
+
"pt": "corrigir WS fechar",
|
|
24
|
+
"nl": "wS sluiten herstellen",
|
|
25
|
+
"fr": "correction WS fermer",
|
|
26
|
+
"it": "fix WS chiudi",
|
|
27
|
+
"es": "arreglar WS close",
|
|
28
|
+
"pl": "fix WS close",
|
|
29
|
+
"uk": "застібка WS",
|
|
30
|
+
"zh-cn": "修复 WS 关闭"
|
|
31
31
|
},
|
|
32
|
-
"3.
|
|
33
|
-
"en": "
|
|
34
|
-
"de": "
|
|
35
|
-
"ru": "
|
|
36
|
-
"pt": "
|
|
37
|
-
"nl": "
|
|
38
|
-
"fr": "
|
|
39
|
-
"it": "
|
|
40
|
-
"es": "
|
|
41
|
-
"pl": "
|
|
42
|
-
"uk": "
|
|
43
|
-
"zh-cn": "
|
|
32
|
+
"3.1.8": {
|
|
33
|
+
"en": "back to old dependency aedes",
|
|
34
|
+
"de": "zurück zu den alten abhängigkeiten",
|
|
35
|
+
"ru": "возвращение к старой зависимости",
|
|
36
|
+
"pt": "voltar ao velho aedes dependência",
|
|
37
|
+
"nl": "terug naar oude afhankelijkheid",
|
|
38
|
+
"fr": "retour à de vieilles dépendances",
|
|
39
|
+
"it": "torna alla vecchia dipendenza",
|
|
40
|
+
"es": "volver a las viejas",
|
|
41
|
+
"pl": "powrót do dawnej zależności",
|
|
42
|
+
"uk": "назад до старих залежностей",
|
|
43
|
+
"zh-cn": "回到旧的依附物"
|
|
44
44
|
},
|
|
45
|
-
"3.
|
|
46
|
-
"en": "
|
|
47
|
-
"de": "
|
|
48
|
-
"ru": "
|
|
49
|
-
"pt": "
|
|
50
|
-
"nl": "
|
|
51
|
-
"fr": "
|
|
52
|
-
"it": "
|
|
53
|
-
"es": "
|
|
54
|
-
"pl": "
|
|
55
|
-
"uk": "
|
|
56
|
-
"zh-cn": "
|
|
45
|
+
"3.1.7": {
|
|
46
|
+
"en": "fix illuminance = 0",
|
|
47
|
+
"de": "fixe beleuchtungsstärke = 0",
|
|
48
|
+
"ru": "фиксированная освещенность = 0",
|
|
49
|
+
"pt": "iluminação de fixação = 0",
|
|
50
|
+
"nl": "fix verlichtingssterkte = 0",
|
|
51
|
+
"fr": "fixer l'éclairage = 0",
|
|
52
|
+
"it": "illuminazione di correzione = 0",
|
|
53
|
+
"es": "iluminación de fijación = 0",
|
|
54
|
+
"pl": "podświetlenie = 0",
|
|
55
|
+
"uk": "фіксувати ілюмінанс = 0",
|
|
56
|
+
"zh-cn": "固定灯光=0"
|
|
57
57
|
},
|
|
58
|
-
"3.
|
|
59
|
-
"en": "
|
|
60
|
-
"de": "
|
|
61
|
-
"ru": "
|
|
62
|
-
"pt": "
|
|
63
|
-
"nl": "
|
|
64
|
-
"fr": "
|
|
65
|
-
"it": "
|
|
66
|
-
"es": "
|
|
67
|
-
"pl": "
|
|
68
|
-
"uk": "
|
|
69
|
-
"zh-cn": "
|
|
58
|
+
"3.1.6": {
|
|
59
|
+
"en": "fix illuminance = 0",
|
|
60
|
+
"de": "fixe beleuchtungsstärke = 0",
|
|
61
|
+
"ru": "фиксированная освещенность = 0",
|
|
62
|
+
"pt": "iluminação de fixação = 0",
|
|
63
|
+
"nl": "fix verlichtingssterkte = 0",
|
|
64
|
+
"fr": "fixer l'éclairage = 0",
|
|
65
|
+
"it": "illuminazione di correzione = 0",
|
|
66
|
+
"es": "iluminación de fijación = 0",
|
|
67
|
+
"pl": "podświetlenie = 0",
|
|
68
|
+
"uk": "фіксувати ілюмінанс = 0",
|
|
69
|
+
"zh-cn": "固定灯光=0"
|
|
70
|
+
},
|
|
71
|
+
"3.1.5": {
|
|
72
|
+
"en": "fix illuminance",
|
|
73
|
+
"de": "befestigungsleuchten",
|
|
74
|
+
"ru": "фиксировать освещенность",
|
|
75
|
+
"pt": "fixar a iluminação",
|
|
76
|
+
"nl": "fix verlichtingssterkte",
|
|
77
|
+
"fr": "fixer l'éclairage",
|
|
78
|
+
"it": "illuminazione di correzione",
|
|
79
|
+
"es": "iluminación de fijación",
|
|
80
|
+
"pl": "podświetlenie",
|
|
81
|
+
"uk": "фіксувати ілюмінанс",
|
|
82
|
+
"zh-cn": "修补灯光"
|
|
83
|
+
},
|
|
84
|
+
"3.1.4": {
|
|
85
|
+
"en": "fix illuminance if not exists. we calculate it ourselves",
|
|
86
|
+
"de": "fixe beleuchtungsstärke, wenn nicht vorhanden. wir berechnen es selbst",
|
|
87
|
+
"ru": "установить свет, если его нет. мы сами вычисляем",
|
|
88
|
+
"pt": "fixar a iluminação se não existir. nós mesmos calculamos",
|
|
89
|
+
"nl": "fix verlichtingssterkte indien niet bestaat. we berekenen het zelf",
|
|
90
|
+
"fr": "fixer l'éclairage s'il n'existe pas. nous le calculons nous-mêmes",
|
|
91
|
+
"it": "fissare l'illuminazione se non esiste. noi lo calcoliamo noi stessi",
|
|
92
|
+
"es": "fijar la iluminación si no existe. lo calculamos nosotros mismos",
|
|
93
|
+
"pl": "naprawić oświetlenie, jeśli nie istnieje. sami to obliczymy",
|
|
94
|
+
"uk": "зафіксувати ілюмінанс, якщо не існує. ми розраховуємо самі",
|
|
95
|
+
"zh-cn": "如果不存在的话, 则固定灯光。 我们自己计算"
|
|
70
96
|
}
|
|
71
97
|
},
|
|
72
98
|
"messages": [
|
package/lib/check.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* Prüft die Zigbee2MQTT-Konfiguration auf veraltete/inkompatible Einstellungen
|
|
3
|
+
* und gibt Fehlermeldungen mit Korrekturhinweisen aus.
|
|
2
4
|
*
|
|
3
|
-
* @param config
|
|
4
|
-
* @param log
|
|
5
|
-
* @param version
|
|
5
|
+
* @param {object} config Der config-Block aus dem bridge/info-Payload
|
|
6
|
+
* @param {object} log Das ioBroker-Log-Objekt (this.log)
|
|
7
|
+
* @param {string} version Die Zigbee2MQTT-Versionsnummer (z.B. "1.35.0")
|
|
6
8
|
*/
|
|
7
9
|
function checkConfig(config, log, version) {
|
|
8
10
|
if (!config || !log) {
|
|
@@ -55,7 +57,7 @@ function checkConfig(config, log, version) {
|
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
if (Object.values(checkAPIOptionsOutput).filter((x) => x === true).length > 0) {
|
|
58
|
-
if (
|
|
60
|
+
if (checkAPIOptionsOutput.payload_contains_not_json === true) {
|
|
59
61
|
log.error('===================================================');
|
|
60
62
|
log.error(
|
|
61
63
|
'MQTT output type must "attribute_and_json" or "json" , therefore the adapter may process the states of the devices correctly!!!'
|
package/lib/colors.js
CHANGED
|
@@ -431,8 +431,8 @@ const namedColors = {
|
|
|
431
431
|
function NamedColorToRGBstring(name) {
|
|
432
432
|
const lowerName = name.toLowerCase();
|
|
433
433
|
if (namedColors.hasOwnProperty(lowerName)) {
|
|
434
|
-
return namedColors[lowerName].rgb;
|
|
435
|
-
}
|
|
434
|
+
return namedColors[lowerName].rgb;
|
|
435
|
+
}
|
|
436
436
|
return '#0088FF';
|
|
437
437
|
}
|
|
438
438
|
|
|
@@ -444,13 +444,13 @@ function ParseColor(rgbstring) {
|
|
|
444
444
|
if (typeof rgbstring === 'string') {
|
|
445
445
|
const lowerName = rgbstring.toLowerCase();
|
|
446
446
|
if (namedColors.hasOwnProperty(lowerName)) {
|
|
447
|
-
rgbstring = namedColors[lowerName].rgb;
|
|
448
|
-
}
|
|
447
|
+
rgbstring = namedColors[lowerName].rgb;
|
|
448
|
+
}
|
|
449
449
|
rgbstring = rgbstring.trim();
|
|
450
450
|
if (rgbstring.startsWith('#')) {
|
|
451
|
-
rgbstring = rgbstring.slice(1);
|
|
452
|
-
}
|
|
453
|
-
const val = parseInt(`0x${
|
|
451
|
+
rgbstring = rgbstring.slice(1);
|
|
452
|
+
}
|
|
453
|
+
const val = parseInt(`0x${rgbstring}`);
|
|
454
454
|
const oneColor = {};
|
|
455
455
|
oneColor.r = Math.floor(val / (256 * 256));
|
|
456
456
|
oneColor.g = Math.floor((val % (256 * 256)) / 256);
|
|
@@ -466,8 +466,8 @@ rgbstring = rgbstring.slice(1);
|
|
|
466
466
|
*/
|
|
467
467
|
function NamedColorToRGB(name) {
|
|
468
468
|
if (namedColors.hasOwnProperty(name)) {
|
|
469
|
-
return ParseColor(namedColors[name].rgb);
|
|
470
|
-
}
|
|
469
|
+
return ParseColor(namedColors[name].rgb);
|
|
470
|
+
}
|
|
471
471
|
return { r: 0, g: 128, b: 255 };
|
|
472
472
|
}
|
|
473
473
|
module.exports = {
|
package/lib/deviceController.js
CHANGED
|
@@ -6,17 +6,32 @@ const rgb = require('./rgb.js');
|
|
|
6
6
|
const ImageController = require('./imageController').ImageController;
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
+
* Prüft ob eine ieee_address in der kommaseparierten debugDevices-Liste enthalten ist.
|
|
10
|
+
* String.includes() würde Substring-Matches liefern (z.B. "0x12" trifft "0x1234").
|
|
9
11
|
*
|
|
12
|
+
* @param {string} debugDevices
|
|
13
|
+
* @param {string} address
|
|
14
|
+
* @returns {boolean}
|
|
15
|
+
*/
|
|
16
|
+
function isDebugDevice(debugDevices, address) {
|
|
17
|
+
if (!debugDevices || !address) { return false; }
|
|
18
|
+
return String(debugDevices).split(',').map((s) => s.trim()).includes(address);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Verwaltet das Erstellen und Aktualisieren von Geräte- und Gruppenobjekten in ioBroker
|
|
23
|
+
* basierend auf den Zigbee2MQTT-Exposes.
|
|
10
24
|
*/
|
|
11
25
|
class DeviceController {
|
|
12
26
|
/**
|
|
27
|
+
* Erstellt eine neue DeviceController-Instanz.
|
|
13
28
|
*
|
|
14
|
-
* @param adapter
|
|
15
|
-
* @param deviceCache
|
|
16
|
-
* @param groupCache
|
|
17
|
-
* @param config
|
|
18
|
-
* @param logCustomizations
|
|
19
|
-
* @param createCache
|
|
29
|
+
* @param {object} adapter Die ioBroker-Adapter-Instanz
|
|
30
|
+
* @param {Array} deviceCache Gemeinsamer Cache aller bekannten Geräte
|
|
31
|
+
* @param {Array} groupCache Gemeinsamer Cache aller bekannten Gruppen
|
|
32
|
+
* @param {object} config Adapter-Konfiguration
|
|
33
|
+
* @param {object} logCustomizations Debug/Filter-Einstellungen (debugDevices, logfilter)
|
|
34
|
+
* @param {object} createCache Cache bereits erstellter ioBroker-Objekte
|
|
20
35
|
*/
|
|
21
36
|
constructor(adapter, deviceCache, groupCache, config, logCustomizations, createCache) {
|
|
22
37
|
this.adapter = adapter;
|
|
@@ -29,8 +44,10 @@ class DeviceController {
|
|
|
29
44
|
}
|
|
30
45
|
|
|
31
46
|
/**
|
|
47
|
+
* Erstellt Geräte-Definitionen aus dem bridge/devices-Payload von Zigbee2MQTT
|
|
48
|
+
* und befüllt den deviceCache neu.
|
|
32
49
|
*
|
|
33
|
-
* @param devicesMessage
|
|
50
|
+
* @param {Array} devicesMessage Array mit Gerätedaten aus dem bridge/devices-Topic
|
|
34
51
|
*/
|
|
35
52
|
async createDeviceDefinitions(devicesMessage) {
|
|
36
53
|
// Fix 1: devicesMessage kann null/kein Array sein (z.B. leerer bridge/devices payload)
|
|
@@ -44,7 +61,7 @@ class DeviceController {
|
|
|
44
61
|
continue;
|
|
45
62
|
}
|
|
46
63
|
|
|
47
|
-
if (this.logCustomizations.debugDevices
|
|
64
|
+
if (isDebugDevice(this.logCustomizations.debugDevices, devicesMessag.ieee_address)) {
|
|
48
65
|
this.adapter.log.warn(
|
|
49
66
|
`--->>> fromZ2M -> ${devicesMessag.ieee_address} exposes: ${JSON.stringify(devicesMessag)}`
|
|
50
67
|
);
|
|
@@ -71,12 +88,13 @@ class DeviceController {
|
|
|
71
88
|
}
|
|
72
89
|
|
|
73
90
|
/**
|
|
91
|
+
* Erstellt die State-Definition für eine Zigbee2MQTT-Gruppe und legt sie im groupCache ab.
|
|
74
92
|
*
|
|
75
|
-
* @param groupID
|
|
76
|
-
* @param ieee_address
|
|
77
|
-
* @param scenes
|
|
93
|
+
* @param {string} groupID Friendly-Name der Gruppe (wird als ioBroker-ID verwendet)
|
|
94
|
+
* @param {string} ieee_address Interne Gruppen-ID (z.B. "group_1")
|
|
95
|
+
* @param {Array} scenes Liste der Szenen-Objekte ({id, name}) der Gruppe
|
|
78
96
|
*/
|
|
79
|
-
|
|
97
|
+
defineGroupDevice(groupID, ieee_address, scenes) {
|
|
80
98
|
const brmPropName = this.adapter.config.brightnessMoveOnOff === true ? 'brightness_move_onoff' : 'brightness_move';
|
|
81
99
|
const brsPropName = this.adapter.config.brightnessStepOnOff === true ? 'brightness_step_onoff' : 'brightness_step';
|
|
82
100
|
const newDevice = {
|
|
@@ -187,6 +205,9 @@ class DeviceController {
|
|
|
187
205
|
if (payload.color_mode !== 'color_temp') {
|
|
188
206
|
return undefined;
|
|
189
207
|
}
|
|
208
|
+
if (payload.color_temp == null) {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
190
211
|
if (this.config.useKelvin === true) {
|
|
191
212
|
return utils.miredKelvinConversion(payload.color_temp);
|
|
192
213
|
}
|
|
@@ -233,7 +254,7 @@ class DeviceController {
|
|
|
233
254
|
const sceneSate = {
|
|
234
255
|
id: `scene_${scene.id}`,
|
|
235
256
|
prop: `scene_recall`,
|
|
236
|
-
name: scene.name
|
|
257
|
+
name: scene.name || `Scene ${scene.id}`,
|
|
237
258
|
icon: undefined,
|
|
238
259
|
role: 'button',
|
|
239
260
|
write: true,
|
|
@@ -251,8 +272,10 @@ class DeviceController {
|
|
|
251
272
|
}
|
|
252
273
|
|
|
253
274
|
/**
|
|
275
|
+
* Erstellt Gruppen-Definitionen aus dem bridge/groups-Payload von Zigbee2MQTT
|
|
276
|
+
* und befüllt den groupCache neu.
|
|
254
277
|
*
|
|
255
|
-
* @param groupsMessage
|
|
278
|
+
* @param {Array} groupsMessage Array mit Gruppendaten aus dem bridge/groups-Topic
|
|
256
279
|
*/
|
|
257
280
|
async createGroupDefinitions(groupsMessage) {
|
|
258
281
|
// Fix 4: groupsMessage kann null/kein Array sein
|
|
@@ -266,15 +289,16 @@ class DeviceController {
|
|
|
266
289
|
if (!groupMessage || groupMessage.id == null || !groupMessage.friendly_name) {
|
|
267
290
|
continue;
|
|
268
291
|
}
|
|
269
|
-
if (this.logCustomizations.debugDevices
|
|
292
|
+
if (isDebugDevice(this.logCustomizations.debugDevices, String(groupMessage.id))) {
|
|
270
293
|
this.adapter.log.warn(`--->>> fromZ2M -> ${groupMessage.id} exposes: ${JSON.stringify(groupMessage)}`);
|
|
271
294
|
}
|
|
272
|
-
|
|
295
|
+
this.defineGroupDevice(groupMessage.friendly_name, `group_${groupMessage.id}`, groupMessage.scenes || []);
|
|
273
296
|
}
|
|
274
297
|
}
|
|
275
298
|
|
|
276
299
|
/**
|
|
277
|
-
*
|
|
300
|
+
* Legt alle Geräte und Gruppen aus den Caches als ioBroker-Objekte an
|
|
301
|
+
* bzw. aktualisiert sie falls sich Name oder Beschreibung geändert haben.
|
|
278
302
|
*/
|
|
279
303
|
async createOrUpdateDevices() {
|
|
280
304
|
// Gruppen und Geräte getrennt verarbeiten
|
|
@@ -287,12 +311,14 @@ class DeviceController {
|
|
|
287
311
|
}
|
|
288
312
|
|
|
289
313
|
/**
|
|
290
|
-
*
|
|
291
|
-
*
|
|
314
|
+
* Legt ein einzelnes Gerät oder eine Gruppe als ioBroker-Objekt an oder aktualisiert es.
|
|
315
|
+
*
|
|
316
|
+
* @param {object} device Das Gerät/Gruppen-Objekt aus dem Cache
|
|
317
|
+
* @param {boolean} isGroup true = Gruppe, false = echtes Gerät
|
|
292
318
|
*/
|
|
293
319
|
async _createOrUpdateSingleDevice(device, isGroup) {
|
|
294
|
-
let deviceName =
|
|
295
|
-
let description =
|
|
320
|
+
let deviceName = this.getDeviceName(device);
|
|
321
|
+
let description = this.getDeviceDescription(device);
|
|
296
322
|
|
|
297
323
|
if (deviceName === '' && device.description) {
|
|
298
324
|
deviceName = device.description;
|
|
@@ -304,7 +330,9 @@ class DeviceController {
|
|
|
304
330
|
if (this.config.useEventInDesc === true) {
|
|
305
331
|
description = 'Device is disabled!';
|
|
306
332
|
} else {
|
|
307
|
-
|
|
333
|
+
// Fallback auf ieee_address wenn kein friendly_name vorhanden
|
|
334
|
+
const label = deviceName || device.ieee_address;
|
|
335
|
+
deviceName = `[Disabled] ${label}`;
|
|
308
336
|
}
|
|
309
337
|
}
|
|
310
338
|
|
|
@@ -331,7 +359,12 @@ class DeviceController {
|
|
|
331
359
|
}
|
|
332
360
|
|
|
333
361
|
await this.adapter.extendObjectAsync(device.ieee_address, deviceObj);
|
|
334
|
-
|
|
362
|
+
// Bestehende State-Einträge im Cache bewahren – nur name/description aktualisieren
|
|
363
|
+
if (!this.createCache[device.ieee_address]) {
|
|
364
|
+
this.createCache[device.ieee_address] = {};
|
|
365
|
+
}
|
|
366
|
+
this.createCache[device.ieee_address].name = deviceName;
|
|
367
|
+
this.createCache[device.ieee_address].description = description;
|
|
335
368
|
}
|
|
336
369
|
|
|
337
370
|
if (!Array.isArray(device.states)) {
|
|
@@ -358,7 +391,7 @@ class DeviceController {
|
|
|
358
391
|
|
|
359
392
|
const iobState = {
|
|
360
393
|
type: 'state',
|
|
361
|
-
common:
|
|
394
|
+
common: this.copyAndCleanStateObj(state),
|
|
362
395
|
native: {},
|
|
363
396
|
};
|
|
364
397
|
|
|
@@ -369,13 +402,18 @@ class DeviceController {
|
|
|
369
402
|
}
|
|
370
403
|
|
|
371
404
|
/**
|
|
372
|
-
*
|
|
405
|
+
* Prüft alle in ioBroker vorhandenen Geräte-Objekte gegen den deviceCache und markiert
|
|
406
|
+
* nicht mehr vorhandene Geräte als "[Removed]" bzw. setzt available auf false.
|
|
373
407
|
*/
|
|
374
408
|
async checkAndProgressDeviceRemove() {
|
|
375
409
|
let iobDevices = await this.adapter.getDevicesAsync();
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
410
|
+
if (!iobDevices) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
// Nur nicht-entfernte, echte Geräte (keine Gruppen) in einem Schritt filtern
|
|
414
|
+
iobDevices = iobDevices.filter((x) =>
|
|
415
|
+
x.native && x.native.deviceRemoved === false && x.native.groupDevice === false
|
|
416
|
+
);
|
|
379
417
|
|
|
380
418
|
for (const iobDevice of iobDevices) {
|
|
381
419
|
const idParts = iobDevice._id.split('.');
|
|
@@ -407,13 +445,17 @@ class DeviceController {
|
|
|
407
445
|
}
|
|
408
446
|
|
|
409
447
|
/**
|
|
448
|
+
* Aktualisiert die Geräte-ID im Cache wenn ein Gerät in Zigbee2MQTT umbenannt wurde.
|
|
410
449
|
*
|
|
411
|
-
* @param messageObj
|
|
450
|
+
* @param {{ payload: { data: { from: string, to: string } } }} messageObj Die Rename-Nachricht
|
|
412
451
|
*/
|
|
413
452
|
async renameDeviceInCache(messageObj) {
|
|
414
453
|
if (!messageObj.payload || !messageObj.payload.data) {
|
|
415
454
|
return;
|
|
416
455
|
}
|
|
456
|
+
if (!messageObj.payload.data.from || !messageObj.payload.data.to) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
417
459
|
const renamedDevice = this.groupCache
|
|
418
460
|
.concat(this.deviceCache)
|
|
419
461
|
.find((x) => x.id === messageObj.payload.data.from);
|
|
@@ -423,9 +465,10 @@ class DeviceController {
|
|
|
423
465
|
}
|
|
424
466
|
|
|
425
467
|
/**
|
|
468
|
+
* Entfernt ein Gerät anhand seiner IEEE-Adresse aus dem angegebenen Cache-Array.
|
|
426
469
|
*
|
|
427
|
-
* @param devices
|
|
428
|
-
* @param ieee_address
|
|
470
|
+
* @param {Array} devices Das Cache-Array (deviceCache oder groupCache)
|
|
471
|
+
* @param {string} ieee_address Die IEEE-Adresse des zu entfernenden Geräts
|
|
429
472
|
*/
|
|
430
473
|
removeDeviceByIeee(devices, ieee_address) {
|
|
431
474
|
const idx = devices.findIndex((x) => x.ieee_address === ieee_address);
|
|
@@ -435,10 +478,13 @@ class DeviceController {
|
|
|
435
478
|
}
|
|
436
479
|
|
|
437
480
|
/**
|
|
481
|
+
* Erstellt eine bereinigte Kopie eines State-Objekts ohne interne Laufzeit-Felder
|
|
482
|
+
* (getter, setter, prop, etc.) für die ioBroker-Objektdefinition.
|
|
438
483
|
*
|
|
439
|
-
* @param state
|
|
484
|
+
* @param {object} state Das vollständige State-Objekt mit Laufzeit-Feldern
|
|
485
|
+
* @returns {object} Das bereinigte State-Objekt für extendObjectAsync
|
|
440
486
|
*/
|
|
441
|
-
|
|
487
|
+
copyAndCleanStateObj(state) {
|
|
442
488
|
const iobState = { ...state };
|
|
443
489
|
const blacklistedKeys = [
|
|
444
490
|
'prop',
|
|
@@ -460,26 +506,33 @@ class DeviceController {
|
|
|
460
506
|
}
|
|
461
507
|
|
|
462
508
|
/**
|
|
509
|
+
* Gibt den Anzeigenamen eines Geräts zurück.
|
|
510
|
+
* Ist friendly_name gleich der IEEE-Adresse, wird ein leerer String zurückgegeben.
|
|
463
511
|
*
|
|
464
|
-
* @param device
|
|
512
|
+
* @param {object} device Das Geräteobjekt aus dem Cache
|
|
513
|
+
* @returns {string} Der Anzeigename oder ""
|
|
465
514
|
*/
|
|
466
515
|
getDeviceName(device) {
|
|
467
516
|
return device.id === device.ieee_address ? '' : device.id;
|
|
468
517
|
}
|
|
469
518
|
|
|
470
519
|
/**
|
|
520
|
+
* Gibt die Beschreibung eines Geräts zurück (oder "" wenn keine vorhanden).
|
|
471
521
|
*
|
|
472
|
-
* @param device
|
|
522
|
+
* @param {object} device Das Geräteobjekt aus dem Cache
|
|
523
|
+
* @returns {string} Die Beschreibung oder ""
|
|
473
524
|
*/
|
|
474
525
|
getDeviceDescription(device) {
|
|
475
526
|
return device.description ? device.description : '';
|
|
476
527
|
}
|
|
477
528
|
|
|
478
529
|
/**
|
|
530
|
+
* Verarbeitet die Antwort eines Coordinator-Check-Requests von Zigbee2MQTT
|
|
531
|
+
* und schreibt fehlende Router in die info-States.
|
|
479
532
|
*
|
|
480
|
-
* @param payload
|
|
533
|
+
* @param {{ data: { missing_routers: Array } }} payload Der Antwort-Payload
|
|
481
534
|
*/
|
|
482
|
-
processCoordinatorCheck(payload) {
|
|
535
|
+
async processCoordinatorCheck(payload) {
|
|
483
536
|
if (payload && payload.data && payload.data.missing_routers) {
|
|
484
537
|
const missingRoutersCount = payload.data.missing_routers.length;
|
|
485
538
|
this.adapter.setState('info.missing_routers', JSON.stringify(payload.data.missing_routers), true);
|