iobroker.zigbee2mqtt 3.1.5 → 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 -81
- package/io-package.json +66 -66
- package/lib/deviceController.js +2 -2
- package/lib/exposes.js +1362 -1362
- package/lib/mqttServerController.js +22 -22
- package/lib/states.js +6 -2
- package/lib/statesController.js +4 -4
- package/lib/websocketController.js +1 -1
- package/lib/z2mController.js +3 -3
- package/main.js +26 -17
- package/package.json +2 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const core = require('@iobroker/adapter-core');
|
|
4
|
-
const
|
|
4
|
+
const Aedes = require('aedes');
|
|
5
5
|
const net = require('node:net');
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -69,22 +69,24 @@ class MqttServerController {
|
|
|
69
69
|
if (!db.setup) {
|
|
70
70
|
db.setup = async () => {};
|
|
71
71
|
}
|
|
72
|
-
|
|
73
|
-
this.
|
|
72
|
+
const aedes = Aedes({ persistence: db });
|
|
73
|
+
this.aedesBroker = aedes;
|
|
74
|
+
this.mqttServer = net.createServer(aedes.handle);
|
|
74
75
|
this._attachServerEvents('MQTT-Server');
|
|
75
76
|
|
|
76
77
|
await new Promise((resolve, reject) => {
|
|
78
|
+
this.mqttServer.once('error', reject);
|
|
77
79
|
this.mqttServer.listen(
|
|
78
80
|
this.adapter.config.mqttServerPort,
|
|
79
81
|
this.adapter.config.mqttServerIPBind,
|
|
80
82
|
() => {
|
|
83
|
+
this.mqttServer.removeListener('error', reject);
|
|
81
84
|
this.adapter.log.info(
|
|
82
85
|
`Starting MQTT-Server on IP ${this.adapter.config.mqttServerIPBind} and Port ${this.adapter.config.mqttServerPort}`
|
|
83
86
|
);
|
|
84
87
|
resolve();
|
|
85
88
|
}
|
|
86
89
|
);
|
|
87
|
-
this.mqttServer.once('error', reject);
|
|
88
90
|
});
|
|
89
91
|
} catch (err) {
|
|
90
92
|
this.adapter.log.error(`createMQTTServer error: ${err && err.message ? err.message : String(err)}`);
|
|
@@ -102,22 +104,24 @@ class MqttServerController {
|
|
|
102
104
|
return;
|
|
103
105
|
}
|
|
104
106
|
try {
|
|
105
|
-
|
|
106
|
-
this.
|
|
107
|
+
const aedes = Aedes();
|
|
108
|
+
this.aedesBroker = aedes;
|
|
109
|
+
this.mqttServer = net.createServer(aedes.handle);
|
|
107
110
|
this._attachServerEvents('DummyMQTT-Server');
|
|
108
111
|
|
|
109
112
|
await new Promise((resolve, reject) => {
|
|
113
|
+
this.mqttServer.once('error', reject);
|
|
110
114
|
this.mqttServer.listen(
|
|
111
115
|
this.adapter.config.mqttServerPort,
|
|
112
116
|
this.adapter.config.mqttServerIPBind,
|
|
113
117
|
() => {
|
|
118
|
+
this.mqttServer.removeListener('error', reject);
|
|
114
119
|
this.adapter.log.info(
|
|
115
120
|
`Starting DummyMQTT-Server on IP ${this.adapter.config.mqttServerIPBind} and Port ${this.adapter.config.mqttServerPort}`
|
|
116
121
|
);
|
|
117
122
|
resolve();
|
|
118
123
|
}
|
|
119
124
|
);
|
|
120
|
-
this.mqttServer.once('error', reject);
|
|
121
125
|
});
|
|
122
126
|
} catch (err) {
|
|
123
127
|
this.adapter.log.error(`createDummyMQTTServer error: ${err && err.message ? err.message : String(err)}`);
|
|
@@ -130,6 +134,17 @@ class MqttServerController {
|
|
|
130
134
|
* Wird beim Adapter-Stop oder nach einem Fehler beim Start aufgerufen.
|
|
131
135
|
*/
|
|
132
136
|
closeServer() {
|
|
137
|
+
if (this.aedesBroker) {
|
|
138
|
+
const broker = this.aedesBroker;
|
|
139
|
+
this.aedesBroker = null;
|
|
140
|
+
try {
|
|
141
|
+
broker.close(() => {
|
|
142
|
+
this.adapter.log.debug('Aedes broker closed.');
|
|
143
|
+
});
|
|
144
|
+
} catch (err) {
|
|
145
|
+
this.adapter.log.error(`closeServer aedesBroker.close() error: ${err}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
133
148
|
if (this.mqttServer) {
|
|
134
149
|
const server = this.mqttServer;
|
|
135
150
|
this.mqttServer = null;
|
|
@@ -143,21 +158,6 @@ class MqttServerController {
|
|
|
143
158
|
this.adapter.log.error(`closeServer mqttServer.close() error: ${err}`);
|
|
144
159
|
}
|
|
145
160
|
}
|
|
146
|
-
if (this.aedesBroker) {
|
|
147
|
-
const broker = this.aedesBroker;
|
|
148
|
-
this.aedesBroker = null;
|
|
149
|
-
try {
|
|
150
|
-
broker.close((err) => {
|
|
151
|
-
if (err) {
|
|
152
|
-
this.adapter.log.debug(`Aedes broker close callback error: ${err}`);
|
|
153
|
-
} else {
|
|
154
|
-
this.adapter.log.debug('Aedes broker closed.');
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
} catch (err) {
|
|
158
|
-
this.adapter.log.error(`closeServer aedesBroker.close() error: ${err}`);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
|
package/lib/states.js
CHANGED
|
@@ -365,7 +365,9 @@ const states = {
|
|
|
365
365
|
unit: 'lux',
|
|
366
366
|
getter: (payload) => {
|
|
367
367
|
if (payload.illuminance == null) { return undefined; }
|
|
368
|
-
|
|
368
|
+
const raw = payload.illuminance;
|
|
369
|
+
if (raw <= 0) { return 0; }
|
|
370
|
+
return Math.round(Math.pow(10, (raw - 1) / 10000));
|
|
369
371
|
},
|
|
370
372
|
},
|
|
371
373
|
|
|
@@ -418,7 +420,9 @@ const states = {
|
|
|
418
420
|
unit: 'lux',
|
|
419
421
|
getter: (payload) => {
|
|
420
422
|
if (payload.illuminance_raw == null) { return undefined; }
|
|
421
|
-
|
|
423
|
+
const raw = payload.illuminance_raw;
|
|
424
|
+
if (raw <= 0) { return 0; }
|
|
425
|
+
return Math.round(Math.pow(10, (raw - 1) / 10000));
|
|
422
426
|
},
|
|
423
427
|
},
|
|
424
428
|
|
package/lib/statesController.js
CHANGED
|
@@ -157,7 +157,7 @@ class StatesController {
|
|
|
157
157
|
if (typeof value === 'object') {
|
|
158
158
|
value = JSON.stringify(value);
|
|
159
159
|
}
|
|
160
|
-
|
|
160
|
+
this.adapter.setState(`${fullPath}.${key}`, value, true);
|
|
161
161
|
}
|
|
162
162
|
continue;
|
|
163
163
|
}
|
|
@@ -233,7 +233,7 @@ class StatesController {
|
|
|
233
233
|
if (value === undefined || value === null) {
|
|
234
234
|
return;
|
|
235
235
|
}
|
|
236
|
-
|
|
236
|
+
this.adapter.setState(stateName, value, true);
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
/**
|
|
@@ -264,7 +264,7 @@ class StatesController {
|
|
|
264
264
|
return;
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
-
|
|
267
|
+
this.adapter.setState(stateName, value, true);
|
|
268
268
|
|
|
269
269
|
// Auto-Reset (false → nichts tun, true → nach timeout zurücksetzen)
|
|
270
270
|
// Wenn value=false (z.B. Stop-Aktion im simpleMoveStopState-Modus),
|
|
@@ -276,7 +276,7 @@ class StatesController {
|
|
|
276
276
|
if (value === true) {
|
|
277
277
|
this.timeOutCache[stateName] = this.adapter.setTimeout(() => {
|
|
278
278
|
delete this.timeOutCache[stateName];
|
|
279
|
-
this.adapter.
|
|
279
|
+
this.adapter.setState(stateName, false, true).catch((err) => {
|
|
280
280
|
this.adapter.log.debug(`setStateWithTimeout reset error for ${stateName}: ${err}`);
|
|
281
281
|
});
|
|
282
282
|
}, timeout);
|
|
@@ -133,8 +133,8 @@ class WebsocketController {
|
|
|
133
133
|
this.adapter.log.debug(`WebSocket closed – code: ${code}, reason: ${reason ? reason.toString() : 'none'}`);
|
|
134
134
|
|
|
135
135
|
try {
|
|
136
|
+
await this.adapter.setStateChangedAsync('info.connection', false, true);
|
|
136
137
|
if (this.adapter.statesController) {
|
|
137
|
-
this.adapter.setStateChanged('info.connection', false, true);
|
|
138
138
|
await this.adapter.statesController.setAllAvailableToFalse();
|
|
139
139
|
}
|
|
140
140
|
} catch (err) {
|
package/lib/z2mController.js
CHANGED
|
@@ -87,7 +87,7 @@ class Z2mController {
|
|
|
87
87
|
if (stateID === 'send_payload') {
|
|
88
88
|
try {
|
|
89
89
|
controlObj.payload = JSON.parse(stateVal);
|
|
90
|
-
|
|
90
|
+
this.adapter.setState(id, state.val, true);
|
|
91
91
|
} catch (error) {
|
|
92
92
|
// Fix 9: rawStr als String direkt als payload – wird in main.js via
|
|
93
93
|
// JSON.stringify() nochmals gewrappt → würde doppelt quoten.
|
|
@@ -122,7 +122,7 @@ class Z2mController {
|
|
|
122
122
|
if (deviceState.isOption) {
|
|
123
123
|
// set optionsValues 'Cache'
|
|
124
124
|
device.optionsValues[stateName] = state.val;
|
|
125
|
-
|
|
125
|
+
this.adapter.setState(id, state.val, true);
|
|
126
126
|
return;
|
|
127
127
|
}
|
|
128
128
|
|
|
@@ -130,7 +130,7 @@ class Z2mController {
|
|
|
130
130
|
const immediateAckRole = ['button'].includes(deviceState.role);
|
|
131
131
|
const immediateAckId = ['brightness_move', 'colortemp_move', 'brightness_step', 'effect'].includes(deviceState.id);
|
|
132
132
|
if (immediateAckRole || immediateAckId) {
|
|
133
|
-
|
|
133
|
+
this.adapter.setState(id, state.val, true);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
if (this.logCustomizations.debugDevices) {
|
package/main.js
CHANGED
|
@@ -71,7 +71,7 @@ class Zigbee2mqtt extends core.Adapter {
|
|
|
71
71
|
|
|
72
72
|
adapterInfo(this.config, this.log);
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
this.setState('info.connection', false, true);
|
|
75
75
|
|
|
76
76
|
const debugDevicesState = await this.getStateAsync('info.debugmessages');
|
|
77
77
|
if (debugDevicesState && debugDevicesState.val) {
|
|
@@ -109,6 +109,7 @@ class Zigbee2mqtt extends core.Adapter {
|
|
|
109
109
|
clientId: `ioBroker.zigbee2mqtt_${Math.random().toString(16).slice(2, 8)}`,
|
|
110
110
|
clean: true,
|
|
111
111
|
reconnectPeriod: 500,
|
|
112
|
+
connectTimeout: 10000,
|
|
112
113
|
};
|
|
113
114
|
|
|
114
115
|
if (this.config.externalMqttServerCredentials === true) {
|
|
@@ -130,6 +131,7 @@ class Zigbee2mqtt extends core.Adapter {
|
|
|
130
131
|
clientId: `ioBroker.zigbee2mqtt_${Math.random().toString(16).slice(2, 8)}`,
|
|
131
132
|
clean: true,
|
|
132
133
|
reconnectPeriod: 500,
|
|
134
|
+
connectTimeout: 10000,
|
|
133
135
|
});
|
|
134
136
|
}
|
|
135
137
|
|
|
@@ -156,18 +158,25 @@ class Zigbee2mqtt extends core.Adapter {
|
|
|
156
158
|
this.log.info('MQTT client reconnecting to Zigbee2MQTT...');
|
|
157
159
|
});
|
|
158
160
|
|
|
159
|
-
this.mqttClient.on('offline', () => {
|
|
160
|
-
(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
} catch (e) {
|
|
168
|
-
this.log.error(`MQTT offline setAllAvailableToFalse error: ${e}`);
|
|
161
|
+
this.mqttClient.on('offline', async () => {
|
|
162
|
+
this.log.warn('MQTT client offline – connection to Zigbee2MQTT lost.');
|
|
163
|
+
await this.setStateChangedAsync('info.connection', false, true).catch((e) =>
|
|
164
|
+
this.log.error(`MQTT offline setStateChangedAsync error: ${e}`)
|
|
165
|
+
);
|
|
166
|
+
try {
|
|
167
|
+
if (this.statesController) {
|
|
168
|
+
await this.statesController.setAllAvailableToFalse();
|
|
169
169
|
}
|
|
170
|
-
}
|
|
170
|
+
} catch (e) {
|
|
171
|
+
this.log.error(`MQTT offline setAllAvailableToFalse error: ${e}`);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
this.mqttClient.on('close', async () => {
|
|
176
|
+
this.log.debug('MQTT client connection closed.');
|
|
177
|
+
await this.setStateChangedAsync('info.connection', false, true).catch((e) =>
|
|
178
|
+
this.log.error(`MQTT close setStateChangedAsync error: ${e}`)
|
|
179
|
+
);
|
|
171
180
|
});
|
|
172
181
|
|
|
173
182
|
this.mqttClient.on('error', (err) => {
|
|
@@ -513,7 +522,7 @@ class Zigbee2mqtt extends core.Adapter {
|
|
|
513
522
|
async onUnload(callback) {
|
|
514
523
|
try {
|
|
515
524
|
if (['exmqtt', 'intmqtt'].includes(this.config.connectionType)) {
|
|
516
|
-
if (this.mqttClient &&
|
|
525
|
+
if (this.mqttClient && this.mqttClient.connected) {
|
|
517
526
|
try {
|
|
518
527
|
this.mqttClient.removeAllListeners();
|
|
519
528
|
this.mqttClient.end(true);
|
|
@@ -561,7 +570,7 @@ class Zigbee2mqtt extends core.Adapter {
|
|
|
561
570
|
this.log.error(e);
|
|
562
571
|
}
|
|
563
572
|
|
|
564
|
-
|
|
573
|
+
this.setState('info.connection', false, true);
|
|
565
574
|
|
|
566
575
|
// Schedule-Job beenden
|
|
567
576
|
const job = schedule.scheduledJobs['coordinatorCheck'];
|
|
@@ -586,14 +595,14 @@ class Zigbee2mqtt extends core.Adapter {
|
|
|
586
595
|
if (state && state.ack === false) {
|
|
587
596
|
if (id.endsWith('info.debugmessages')) {
|
|
588
597
|
this.logCustomizations.debugDevices = state.val != null ? String(state.val) : '';
|
|
589
|
-
|
|
598
|
+
this.setState(id, state.val, true);
|
|
590
599
|
return;
|
|
591
600
|
}
|
|
592
601
|
if (id.endsWith('info.logfilter')) {
|
|
593
602
|
this.logCustomizations.logfilter = state.val != null
|
|
594
603
|
? String(state.val).split(';').filter((x) => x)
|
|
595
604
|
: [];
|
|
596
|
-
|
|
605
|
+
this.setState(id, state.val, true);
|
|
597
606
|
return;
|
|
598
607
|
}
|
|
599
608
|
|
|
@@ -608,7 +617,7 @@ class Zigbee2mqtt extends core.Adapter {
|
|
|
608
617
|
}
|
|
609
618
|
|
|
610
619
|
if (['exmqtt', 'intmqtt'].includes(this.config.connectionType)) {
|
|
611
|
-
if (!this.mqttClient || this.mqttClient.
|
|
620
|
+
if (!this.mqttClient || !this.mqttClient.connected) {
|
|
612
621
|
this.log.warn(`Cannot publish state, MQTT client not connected. (${id})`);
|
|
613
622
|
return;
|
|
614
623
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.zigbee2mqtt",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "Zigbee2MQTT adapter for ioBroker",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Dennis Rathjen and Arthur Rupp",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@iobroker/adapter-core": "^3.3.2",
|
|
28
28
|
"@iobroker/dm-utils": "^3.0.17",
|
|
29
|
-
"aedes": "^
|
|
29
|
+
"aedes": "^0.51.3",
|
|
30
30
|
"aedes-persistence-nedb": "^2.0.3",
|
|
31
31
|
"mqtt": "^5.15.1",
|
|
32
32
|
"axios": "^1.14.0",
|