iobroker.zigbee2mqtt 3.1.1 → 3.1.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 +14 -0
- package/io-package.json +53 -27
- package/lib/check.js +6 -4
- package/lib/colors.js +9 -9
- package/lib/deviceController.js +92 -39
- package/lib/exposes.js +19 -7
- package/lib/imageController.js +56 -26
- package/lib/messages.js +15 -13
- package/lib/mqttServerController.js +14 -8
- package/lib/nonGenericDevicesExtension.js +2 -3
- package/lib/rgb.js +52 -63
- package/lib/states.js +138 -28
- package/lib/statesController.js +102 -44
- package/lib/utils.js +36 -47
- package/lib/websocketController.js +84 -52
- package/lib/z2mController.js +28 -16
- package/main.js +103 -33
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,6 +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.1.5 (2026-04-23)
|
|
26
|
+
* (arteck) fix illuminance
|
|
27
|
+
|
|
28
|
+
### 3.1.4 (2026-04-23)
|
|
29
|
+
* (arteck) fix illuminance if not exists. we calculate it ourselves
|
|
30
|
+
|
|
31
|
+
### 3.1.3 (2026-04-23)
|
|
32
|
+
* (arteck) fix illuminance_raw
|
|
33
|
+
* (arteck) fix illuminance
|
|
34
|
+
* (arteck) fix action state
|
|
35
|
+
|
|
36
|
+
### 3.1.2 (2026-04-23)
|
|
37
|
+
* (arteck) add test
|
|
38
|
+
|
|
25
39
|
### 3.1.1 (2026-04-21)
|
|
26
40
|
* (arteck) fix connection handling
|
|
27
41
|
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,60 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "zigbee2mqtt",
|
|
4
|
-
"version": "3.1.
|
|
4
|
+
"version": "3.1.5",
|
|
5
5
|
"news": {
|
|
6
|
+
"3.1.5": {
|
|
7
|
+
"en": "fix illuminance",
|
|
8
|
+
"de": "befestigungsleuchten",
|
|
9
|
+
"ru": "фиксировать освещенность",
|
|
10
|
+
"pt": "fixar a iluminação",
|
|
11
|
+
"nl": "fix verlichtingssterkte",
|
|
12
|
+
"fr": "fixer l'éclairage",
|
|
13
|
+
"it": "illuminazione di correzione",
|
|
14
|
+
"es": "iluminación de fijación",
|
|
15
|
+
"pl": "podświetlenie",
|
|
16
|
+
"uk": "фіксувати ілюмінанс",
|
|
17
|
+
"zh-cn": "修补灯光"
|
|
18
|
+
},
|
|
19
|
+
"3.1.4": {
|
|
20
|
+
"en": "fix illuminance if not exists. we calculate it ourselves",
|
|
21
|
+
"de": "fixe beleuchtungsstärke, wenn nicht vorhanden. wir berechnen es selbst",
|
|
22
|
+
"ru": "установить свет, если его нет. мы сами вычисляем",
|
|
23
|
+
"pt": "fixar a iluminação se não existir. nós mesmos calculamos",
|
|
24
|
+
"nl": "fix verlichtingssterkte indien niet bestaat. we berekenen het zelf",
|
|
25
|
+
"fr": "fixer l'éclairage s'il n'existe pas. nous le calculons nous-mêmes",
|
|
26
|
+
"it": "fissare l'illuminazione se non esiste. noi lo calcoliamo noi stessi",
|
|
27
|
+
"es": "fijar la iluminación si no existe. lo calculamos nosotros mismos",
|
|
28
|
+
"pl": "naprawić oświetlenie, jeśli nie istnieje. sami to obliczymy",
|
|
29
|
+
"uk": "зафіксувати ілюмінанс, якщо не існує. ми розраховуємо самі",
|
|
30
|
+
"zh-cn": "如果不存在的话, 则固定灯光。 我们自己计算"
|
|
31
|
+
},
|
|
32
|
+
"3.1.3": {
|
|
33
|
+
"en": "fix illuminance_raw \nfix illuminance\nfix action state",
|
|
34
|
+
"de": "fix illuminance raw\nbefestigungsleuchten\nfixer aktionszustand",
|
|
35
|
+
"ru": "осветительный прибор raw\nфиксировать освещенность\nопределить состояние",
|
|
36
|
+
"pt": "corrigir illuminance raw\nfixar a iluminação\ncorrigir o estado da ação",
|
|
37
|
+
"nl": "fix illuminantie raw\nfix verlichtingssterkte\nfix actiestatus",
|
|
38
|
+
"fr": "correction de l'éclairage raw\nfixer l'éclairage\nfixer l'état d'action",
|
|
39
|
+
"it": "correzione illuminazione raw\nilluminazione di correzione\nfix azione stato",
|
|
40
|
+
"es": "iluminación raw\niluminación de fijación\nestado de acción",
|
|
41
|
+
"pl": "fix lightinance _ raw\npodświetlenie\nstan działania",
|
|
42
|
+
"uk": "фіксація талії raw\nфіксувати ілюмінанс\nфіксувати стан дії",
|
|
43
|
+
"zh-cn": "修补灯光 raw\n修补灯光\n固定动作状态"
|
|
44
|
+
},
|
|
45
|
+
"3.1.2": {
|
|
46
|
+
"en": "add test",
|
|
47
|
+
"de": "test hinzufügen",
|
|
48
|
+
"ru": "добавить тест",
|
|
49
|
+
"pt": "adicionar teste",
|
|
50
|
+
"nl": "test toevoegen",
|
|
51
|
+
"fr": "ajouter un essai",
|
|
52
|
+
"it": "aggiungere test",
|
|
53
|
+
"es": "agregar la prueba",
|
|
54
|
+
"pl": "dodać test",
|
|
55
|
+
"uk": "додати тест",
|
|
56
|
+
"zh-cn": "添加测试"
|
|
57
|
+
},
|
|
6
58
|
"3.1.1": {
|
|
7
59
|
"en": "fix connection handling",
|
|
8
60
|
"de": "befestigungstechnik",
|
|
@@ -41,32 +93,6 @@
|
|
|
41
93
|
"pl": "sprawdzanie ładunku użytecznego, jeżeli nie określono",
|
|
42
94
|
"uk": "перевірити навантаження, якщо не визначено",
|
|
43
95
|
"zh-cn": "检查未定义的有效载荷"
|
|
44
|
-
},
|
|
45
|
-
"3.0.19": {
|
|
46
|
-
"en": "modify action dp",
|
|
47
|
-
"de": "änderung der aktion dp",
|
|
48
|
-
"ru": "модифицировать действие dp",
|
|
49
|
-
"pt": "modificar ação dp",
|
|
50
|
-
"nl": "actie dp wijzigen",
|
|
51
|
-
"fr": "modifier l'action dp",
|
|
52
|
-
"it": "modificare l'azione",
|
|
53
|
-
"es": "modificar la acción dp",
|
|
54
|
-
"pl": "modyfikacja działania dp",
|
|
55
|
-
"uk": "змінити дію dp",
|
|
56
|
-
"zh-cn": "修改动作 dp"
|
|
57
|
-
},
|
|
58
|
-
"3.0.18": {
|
|
59
|
-
"en": "typo",
|
|
60
|
-
"de": "typo",
|
|
61
|
-
"ru": "опечатка",
|
|
62
|
-
"pt": "erro de digitação",
|
|
63
|
-
"nl": "type",
|
|
64
|
-
"fr": "typo",
|
|
65
|
-
"it": "tipo",
|
|
66
|
-
"es": "typo",
|
|
67
|
-
"pl": "typo",
|
|
68
|
-
"uk": "типи",
|
|
69
|
-
"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,30 +506,37 @@ 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
|
-
this.adapter.
|
|
486
|
-
this.adapter.
|
|
538
|
+
await this.adapter.setStateAsync('info.missing_routers', JSON.stringify(payload.data.missing_routers), true);
|
|
539
|
+
await this.adapter.setStateAsync('info.missing_routers_count', missingRoutersCount, true);
|
|
487
540
|
|
|
488
541
|
if (missingRoutersCount > 0) {
|
|
489
542
|
const logLvl = this.config.coordinatorCheckLogLvl;
|
package/lib/exposes.js
CHANGED
|
@@ -726,9 +726,23 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
|
|
|
726
726
|
break;
|
|
727
727
|
|
|
728
728
|
case 'illuminance':
|
|
729
|
-
// Z2M sendet 'illuminance' = Rohwert (kein
|
|
730
|
-
//
|
|
731
|
-
|
|
729
|
+
// Z2M sendet 'illuminance' = Rohwert (kein Lux)
|
|
730
|
+
// Wir legen BEIDE States an:
|
|
731
|
+
// 1. illuminance_raw – der unveränderte Rohwert
|
|
732
|
+
// 2. illuminance – in Lux konvertiert (10^(raw/10000))
|
|
733
|
+
// Damit bleiben bestehende Scripts auf illuminance_raw kompatibel
|
|
734
|
+
// und neue Scripts können direkt illuminance (Lux) nutzen.
|
|
735
|
+
pushToStates(statesDefs.illuminance_raw, expose.access);
|
|
736
|
+
state = statesDefs.illuminance_from_raw;
|
|
737
|
+
break;
|
|
738
|
+
|
|
739
|
+
case 'illuminance_raw':
|
|
740
|
+
// Gerät sendet payload.illuminance_raw direkt (eigener Expose-Typ)
|
|
741
|
+
// Wir legen ebenfalls BEIDE States an:
|
|
742
|
+
// 1. illuminance_raw – der unveränderte Rohwert (prop='illuminance_raw')
|
|
743
|
+
// 2. illuminance – in Lux konvertiert (10^(raw/10000))
|
|
744
|
+
pushToStates(statesDefs.illuminance_raw_direct, expose.access);
|
|
745
|
+
state = statesDefs.illuminance_from_illuminance_raw;
|
|
732
746
|
break;
|
|
733
747
|
|
|
734
748
|
case 'illuminance_lux':
|
|
@@ -1261,7 +1275,7 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
|
|
|
1261
1275
|
const state = genState(prop);
|
|
1262
1276
|
// Workaround for FP1 new state (region_upsert)
|
|
1263
1277
|
if (!state) {
|
|
1264
|
-
|
|
1278
|
+
continue;
|
|
1265
1279
|
}
|
|
1266
1280
|
|
|
1267
1281
|
state.prop = expose.property;
|
|
@@ -1332,7 +1346,7 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
|
|
|
1332
1346
|
});
|
|
1333
1347
|
}
|
|
1334
1348
|
|
|
1335
|
-
|
|
1349
|
+
return {
|
|
1336
1350
|
id: deviceID,
|
|
1337
1351
|
ieee_address: ieee_address,
|
|
1338
1352
|
power_source: power_source,
|
|
@@ -1341,8 +1355,6 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
|
|
|
1341
1355
|
optionsValues: {},
|
|
1342
1356
|
states: states,
|
|
1343
1357
|
};
|
|
1344
|
-
|
|
1345
|
-
return newDevice;
|
|
1346
1358
|
}
|
|
1347
1359
|
|
|
1348
1360
|
module.exports = {
|