iobroker.zigbee2mqtt 1.0.0 → 2.1.1

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/lib/states.js CHANGED
@@ -274,17 +274,16 @@ const states = {
274
274
  },
275
275
  voltage: {
276
276
  id: 'voltage',
277
- name: 'Battery voltage',
277
+ name: 'Voltage',
278
278
  icon: undefined,
279
- role: 'battery.voltage',
279
+ role: 'value.voltage',
280
280
  write: false,
281
281
  read: true,
282
282
  type: 'number',
283
283
  unit: 'V',
284
- getter: payload => payload.voltage / 1000,
285
284
  def: 0,
286
285
  },
287
- ecozy_voltage: {
286
+ battery_voltage: {
288
287
  id: 'voltage',
289
288
  name: 'Battery voltage',
290
289
  icon: undefined,
@@ -293,9 +292,18 @@ const states = {
293
292
  read: true,
294
293
  type: 'number',
295
294
  unit: 'V',
296
- getter: payload => payload.voltage * 10,
297
295
  def: 0,
298
296
  },
297
+ energy: {
298
+ id: 'energy',
299
+ name: 'Sum of consumed energy',
300
+ icon: undefined,
301
+ role: 'value.power.consumption',
302
+ write: false,
303
+ read: true,
304
+ type: 'number',
305
+ unit: 'kWh'
306
+ },
299
307
  battery: {
300
308
  id: 'battery',
301
309
  prop: 'battery',
@@ -546,6 +554,17 @@ const states = {
546
554
  type: 'boolean',
547
555
  getter: payload => (payload.button_right === 'hold'),
548
556
  },
557
+ device_temperature: {
558
+ id: 'device_temperature',
559
+ name: 'Temperature of the device',
560
+ icon: undefined,
561
+ role: 'value.temperature',
562
+ write: false,
563
+ read: true,
564
+ type: 'number',
565
+ unit: '°C',
566
+ def: 0,
567
+ },
549
568
  temperature: {
550
569
  id: 'temperature',
551
570
  name: 'Temperature',
@@ -736,7 +755,7 @@ const states = {
736
755
  type: 'boolean',
737
756
  def: false,
738
757
  },
739
- smoke_detected2: { // for Heiman
758
+ smoke_detected2: { // for Heiman
740
759
  id: 'smoke',
741
760
  prop: 'smoke',
742
761
  name: 'Smoke leak detected',
@@ -747,7 +766,7 @@ const states = {
747
766
  type: 'boolean',
748
767
  def: false,
749
768
  },
750
- co_detected: { // for Heiman
769
+ co_detected: { // for Heiman
751
770
  id: 'carbon_monoxide',
752
771
  prop: 'carbon_monoxide',
753
772
  name: 'CO leak detected',
@@ -1074,11 +1093,11 @@ const states = {
1074
1093
  unit: 'V'
1075
1094
  },
1076
1095
  load_current: {
1077
- id: 'current',
1096
+ id: 'load_current',
1078
1097
  prop: 'current',
1079
1098
  name: 'Load current',
1080
1099
  icon: undefined,
1081
- role: 'value',
1100
+ role: 'value.current',
1082
1101
  write: false,
1083
1102
  read: true,
1084
1103
  type: 'number',
@@ -1232,12 +1251,15 @@ const states = {
1232
1251
  y: xy[1]
1233
1252
  };
1234
1253
  },
1235
- setterOpt: (value, options) => {
1236
- const hasTransitionTime = options && options.hasOwnProperty('transition_time');
1237
- const transitionTime = hasTransitionTime ? options.transition_time : 0;
1238
- return { ...options, transition: transitionTime };
1239
- },
1254
+ // setterOpt: (value, options) => {
1255
+ // const hasTransitionTime = options && options.hasOwnProperty('transition_time');
1256
+ // const transitionTime = hasTransitionTime ? options.transition_time : 0;
1257
+ // return { ...options, transition: transitionTime };
1258
+ // },
1240
1259
  getter: payload => {
1260
+ if (payload.color_mode != 'xy') {
1261
+ return undefined;
1262
+ }
1241
1263
  if (payload.color && payload.color.hasOwnProperty('x') && payload.color.hasOwnProperty('y')) {
1242
1264
  const colorval = rgb.cie_to_rgb(payload.color.x, payload.color.y);
1243
1265
  return '#' + utils.decimalToHex(colorval[0]) + utils.decimalToHex(colorval[1]) + utils.decimalToHex(colorval[2]);
@@ -2625,8 +2647,7 @@ const states = {
2625
2647
  max: 1,
2626
2648
  type: 'number',
2627
2649
  },
2628
- thermostat_keypad_lockout:
2629
- {
2650
+ thermostat_keypad_lockout: {
2630
2651
  id: 'keypad_lockout',
2631
2652
  name: 'Keypad Lockout',
2632
2653
  prop: 'keypad_lockout',
@@ -5844,8 +5865,7 @@ const states = {
5844
5865
  setter: (value, options) => {
5845
5866
  try {
5846
5867
  return JSON.parse(value);
5847
- }
5848
- catch (err) {
5868
+ } catch (err) {
5849
5869
  const effectjson = {
5850
5870
  colors: [{ r: 255, g: 0, b: 0 }, { r: 0, g: 255, b: 0 }, { r: 0, g: 0, b: 255 }],
5851
5871
  speed: 10,
@@ -6419,4 +6439,4 @@ module.exports = {
6419
6439
  states: states,
6420
6440
  unitLookup: unitLookup,
6421
6441
  nameLookup: nameLookup,
6422
- };
6442
+ };
@@ -1,15 +1,16 @@
1
1
  const utils = require('./utils');
2
2
  const incStatsQueue = [];
3
+ const timeOutCache = {};
3
4
 
4
5
  class StatesController {
5
- constructor(adapter, deviceCache, groupCache, debugDevices) {
6
+ constructor(adapter, deviceCache, groupCache, logCustomizations) {
6
7
  this.adapter = adapter;
7
8
  this.groupCache = groupCache;
8
9
  this.deviceCache = deviceCache;
9
- this.debugDevices = debugDevices;
10
+ this.logCustomizations = logCustomizations;
10
11
  }
11
12
 
12
- async processDeviceMessage(messageObj) {
13
+ processDeviceMessage(messageObj) {
13
14
  // Is payload present?
14
15
  if (messageObj.payload == '') {
15
16
  return;
@@ -18,19 +19,18 @@ class StatesController {
18
19
  const device = this.groupCache.concat(this.deviceCache).find(x => x.id == messageObj.topic);
19
20
  if (device) {
20
21
  try {
21
- this.setDeviceState(messageObj, device);
22
+ this.setDeviceStateSafely(messageObj, device);
22
23
  } catch (error) {
23
24
  this.adapter.log.error(error);
24
25
  }
25
- }
26
- else {
26
+ } else {
27
27
  incStatsQueue[incStatsQueue.length] = messageObj;
28
28
  this.adapter.log.debug(`Device: ${messageObj.topic} not found, queue state in incStatsQueue!`);
29
29
  }
30
30
  }
31
31
 
32
- async setDeviceState(messageObj, device) {
33
- if (this.debugDevices.includes(device.ieee_address)) {
32
+ async setDeviceStateSafely(messageObj, device) {
33
+ if (this.logCustomizations.debugDevices.includes(device.ieee_address)) {
34
34
  this.adapter.log.warn(`--->>> fromZ2M -> ${device.ieee_address} states: ${JSON.stringify(messageObj)}`);
35
35
  }
36
36
 
@@ -53,44 +53,49 @@ class StatesController {
53
53
  if (state.isEvent) {
54
54
  if (state.getter) {
55
55
  await this.setStateWithTimeoutAsync(stateName, state.getter(messageObj.payload), 300);
56
- }
57
- else {
56
+ } else {
58
57
  await this.setStateWithTimeoutAsync(stateName, value, 300);
59
58
  }
60
- }
61
- else {
59
+ } else {
62
60
  if (state.getter) {
63
- await this.setStateAsync(stateName, state.getter(messageObj.payload));
64
- }
65
- else {
66
- await this.setStateAsync(stateName, value);
61
+ await this.setStateChangedSafelyAsync(stateName, state.getter(messageObj.payload));
62
+ } else {
63
+ await this.setStateChangedSafelyAsync(stateName, value);
67
64
  }
68
65
  }
69
66
  } catch (err) {
70
- //this.adapter.log.warn(`Can not set ${stateName}`);
71
67
  incStatsQueue[incStatsQueue.length] = messageObj;
72
- this.adapter.log.debug(`Can not set ${stateName} for ${messageObj.topic}, queue state in incStatsQueue!`);
68
+ this.adapter.log.debug(`Can not set ${stateName}, queue state in incStatsQueue!`);
73
69
  }
74
70
  }
75
71
  }
76
72
  }
77
73
 
78
- async setStateAsync(stateName, value) {
74
+ async setStateSafelyAsync(stateName, value) {
79
75
  if (value !== undefined) {
80
76
  await this.adapter.setStateAsync(stateName, value, true);
81
77
  }
82
78
  }
83
79
 
80
+ async setStateChangedSafelyAsync(stateName, value) {
81
+ if (value !== undefined) {
82
+ await this.adapter.setStateChangedAsync(stateName, value, true);
83
+ }
84
+ }
85
+
84
86
  async setStateWithTimeoutAsync(stateName, value, timeout) {
85
87
  if (value !== undefined) {
86
88
  await this.adapter.setStateAsync(stateName, value, true);
87
- setTimeout(() => {
89
+ if (timeOutCache[stateName]) {
90
+ clearTimeout(timeOutCache[stateName]);
91
+ }
92
+ timeOutCache[stateName] = setTimeout(() => {
88
93
  this.adapter.setStateAsync(stateName, !value, true);
89
94
  }, timeout);
90
95
  }
91
96
  }
92
97
 
93
- async processQueue() {
98
+ processQueue() {
94
99
  const oldIncStatsQueue = [];
95
100
  utils.moveArray(incStatsQueue, oldIncStatsQueue);
96
101
  while (oldIncStatsQueue.length > 0) {
@@ -115,13 +120,19 @@ class StatesController {
115
120
  for (const device of this.deviceCache) {
116
121
  for (const state of device.states) {
117
122
  if (state.id == 'available') {
118
- await this.adapter.setStateAsync(`${device.ieee_address}.${state.id}`, false, true);
123
+ await this.adapter.setStateChangedAsync(`${device.ieee_address}.${state.id}`, false, true);
119
124
  }
120
125
  }
121
126
  }
122
127
  }
128
+
129
+ async allTimerClear() {
130
+ for (const timer in timeOutCache) {
131
+ clearTimeout(timeOutCache[timer]);
132
+ }
133
+ }
123
134
  }
124
135
 
125
136
  module.exports = {
126
137
  StatesController
127
- };
138
+ };
package/lib/utils.js CHANGED
@@ -106,12 +106,6 @@ function getDeviceIcon(definition) {
106
106
  return icon;
107
107
  }
108
108
 
109
- function removeDeviceByIeee(devices, ieee_address) {
110
- const idx = devices.findIndex(x => x.ieee_address == ieee_address);
111
- if (idx > -1) {
112
- devices.splice(idx, 1);
113
- }
114
- }
115
109
  function clearArray(array) {
116
110
  while (array.length > 0) {
117
111
  array.pop();
@@ -125,16 +119,15 @@ function moveArray(source, target) {
125
119
  }
126
120
 
127
121
  module.exports = {
128
- bulbLevelToAdapterLevel: bulbLevelToAdapterLevel,
129
- adapterLevelToBulbLevel: adapterLevelToBulbLevel,
130
- bytesArrayToWordArray: bytesArrayToWordArray,
131
- toMired: toMired,
132
- miredKelvinConversion: miredKelvinConversion,
133
- decimalToHex: decimalToHex,
134
- getZbId: getZbId,
135
- getAdId: getAdId,
136
- removeDeviceByIeee: removeDeviceByIeee,
137
- getDeviceIcon: getDeviceIcon,
138
- clearArray: clearArray,
139
- moveArray: moveArray,
140
- };
122
+ bulbLevelToAdapterLevel,
123
+ adapterLevelToBulbLevel,
124
+ bytesArrayToWordArray,
125
+ toMired,
126
+ miredKelvinConversion,
127
+ decimalToHex,
128
+ getZbId,
129
+ getAdId,
130
+ getDeviceIcon,
131
+ clearArray,
132
+ moveArray,
133
+ };
@@ -0,0 +1,84 @@
1
+ const WebSocket = require('ws');
2
+ let wsClient;
3
+ const wsHeartbeatIntervall = 5000;
4
+ const restartTimeout = 1000;
5
+ let ping;
6
+ let pingTimeout;
7
+ let autoRestartTimeout;
8
+
9
+ class WebsocketController {
10
+ constructor(adapter) {
11
+ this.adapter = adapter;
12
+ }
13
+
14
+ initWsClient() {
15
+ try {
16
+ wsClient = new WebSocket(`ws://${this.adapter.config.wsServerIP}:${this.adapter.config.wsServerPort}/api`);
17
+
18
+ wsClient.on('open', () => {
19
+ // Send ping to server
20
+ this.sendPingToServer();
21
+ // Start Heartbeat
22
+ this.wsHeartbeat();
23
+ });
24
+
25
+ wsClient.on('pong', () => {
26
+ this.wsHeartbeat();
27
+ });
28
+
29
+ wsClient.on('close', async () => {
30
+ clearTimeout(pingTimeout);
31
+ clearTimeout(ping);
32
+
33
+ if (wsClient.readyState === WebSocket.CLOSED) {
34
+ this.autoRestart();
35
+ }
36
+ });
37
+
38
+ wsClient.on('message', () => { });
39
+
40
+ wsClient.on('error', (err) => { this.adapter.log.debug(err); });
41
+
42
+ return wsClient;
43
+ } catch (err) {
44
+ this.adapter.log.error(err);
45
+ }
46
+ }
47
+
48
+ send(message) {
49
+ wsClient.send(message);
50
+ }
51
+
52
+ sendPingToServer() {
53
+ //this.logDebug('Send ping to server');
54
+ wsClient.ping();
55
+ ping = setTimeout(() => {
56
+ this.sendPingToServer();
57
+ }, wsHeartbeatIntervall);
58
+ }
59
+
60
+ wsHeartbeat() {
61
+ clearTimeout(pingTimeout);
62
+ pingTimeout = setTimeout(() => {
63
+ this.adapter.log.warn('Websocked connection timed out');
64
+ wsClient.terminate();
65
+ }, wsHeartbeatIntervall + 1000);
66
+ }
67
+
68
+ async autoRestart() {
69
+ this.adapter.log.warn(`Start try again in ${restartTimeout / 1000} seconds...`);
70
+ autoRestartTimeout = setTimeout(() => {
71
+ this.adapter.startWebsocket();
72
+ }, restartTimeout);
73
+ }
74
+
75
+ async allTimerClear() {
76
+ clearTimeout(pingTimeout);
77
+ clearTimeout(ping);
78
+ clearTimeout(autoRestartTimeout);
79
+ }
80
+ }
81
+
82
+ module.exports = {
83
+ WebsocketController
84
+ };
@@ -1,9 +1,9 @@
1
1
  class Z2mController {
2
- constructor(adapter, deviceCache, groupCache, logfilter) {
2
+ constructor(adapter, deviceCache, groupCache, logCustomizations) {
3
3
  this.adapter = adapter;
4
4
  this.groupCache = groupCache;
5
5
  this.deviceCache = deviceCache;
6
- this.logfilter = logfilter;
6
+ this.logCustomizations = logCustomizations;
7
7
  }
8
8
 
9
9
  async createZ2MMessage(id, state) {
@@ -57,7 +57,7 @@ class Z2mController {
57
57
 
58
58
  async proxyZ2MLogs(messageObj) {
59
59
  const logMessage = messageObj.payload.message;
60
- if (this.logfilter.some(x => logMessage.includes(x))) {
60
+ if (this.logCustomizations.logfilter.some(x => logMessage.includes(x))) {
61
61
  return;
62
62
  }
63
63
 
package/main.js CHANGED
@@ -7,7 +7,6 @@
7
7
  // The adapter-core module gives you access to the core ioBroker functions
8
8
  // you need to create an adapter
9
9
  const core = require('@iobroker/adapter-core');
10
- const NedbPersistence = require('aedes-persistence-nedb');
11
10
  const mqtt = require('mqtt');
12
11
  const checkConfig = require('./lib/check').checkConfig;
13
12
  const adapterInfo = require('./lib/messages').adapterInfo;
@@ -15,6 +14,8 @@ const zigbee2mqttInfo = require('./lib/messages').zigbee2mqttInfo;
15
14
  const Z2mController = require('./lib/z2mController').Z2mController;
16
15
  const DeviceController = require('./lib/deviceController').DeviceController;
17
16
  const StatesController = require('./lib/statesController').StatesController;
17
+ const WebsocketController = require('./lib/websocketController').WebsocketController;
18
+ const MqttServerController = require('./lib/mqttServerController').MqttServerController;
18
19
 
19
20
 
20
21
  let mqttClient;
@@ -22,16 +23,13 @@ let mqttClient;
22
23
  let deviceCache = [];
23
24
  // eslint-disable-next-line prefer-const
24
25
  let groupCache = [];
25
- let ping;
26
- let pingTimeout;
27
- let autoRestartTimeout;
28
- let checkAvailableTimout;
29
- let debugDevices = '';
30
- let logfilter = [];
26
+ const logCustomizations = { debugDevices: '', logfilter: [] };
31
27
  let showInfo = true;
32
28
  let statesController;
33
29
  let deviceController;
34
30
  let z2mController;
31
+ let websocketController;
32
+ let mqttServerController;
35
33
 
36
34
  class Zigbee2mqtt extends core.Adapter {
37
35
 
@@ -46,11 +44,9 @@ class Zigbee2mqtt extends core.Adapter {
46
44
  }
47
45
 
48
46
  async onReady() {
49
-
50
-
51
- statesController = new StatesController(this, deviceCache, groupCache, debugDevices);
52
- deviceController = new DeviceController(this, deviceCache, groupCache, this.config.useKelvin);
53
- z2mController = new Z2mController(this, deviceCache, groupCache, logfilter);
47
+ statesController = new StatesController(this, deviceCache, groupCache, logCustomizations);
48
+ deviceController = new DeviceController(this, deviceCache, groupCache, this.config);
49
+ z2mController = new Z2mController(this, deviceCache, groupCache, logCustomizations);
54
50
 
55
51
  // Initialize your adapter here
56
52
  adapterInfo(this.config, this.log);
@@ -59,39 +55,81 @@ class Zigbee2mqtt extends core.Adapter {
59
55
 
60
56
  const debugDevicesState = await this.getStateAsync('info.debugmessages');
61
57
  if (debugDevicesState && debugDevicesState.val) {
62
- debugDevices = String(debugDevicesState.val);
58
+ logCustomizations.debugDevices = String(debugDevicesState.val);
63
59
  }
64
60
 
65
61
  const logfilterState = await this.getStateAsync('info.logfilter');
66
62
  if (logfilterState && logfilterState.val) {
67
- logfilter = String(logfilterState.val).split(';').filter(x => x); // filter removes empty strings here
63
+ // @ts-ignore
64
+ logCustomizations.logfilter = String(logfilterState.val).split(';').filter(x => x); // filter removes empty strings here
68
65
  }
66
+ // MQTT
67
+ if (['exmqtt', 'intmqtt'].includes(this.config.connectionType)) {
68
+ // External MQTT-Server
69
+ if (this.config.connectionType == 'exmqtt') {
70
+ if (this.config.externalMqttServerIP == '') {
71
+ this.log.warn('Please configure the External MQTT-Server connection!');
72
+ return;
73
+ }
74
+ mqttClient = mqtt.connect(`mqtt://${this.config.externalMqttServerIP}:${this.config.externalMqttServerPort}`, { clientId: `ioBroker.zigbee2mqtt_${Math.random().toString(16).slice(2, 8)}`, clean: true, reconnectPeriod: 500 });
69
75
 
70
- if (this.config.useExternalMqtt == true) {
71
- mqttClient = mqtt.connect(`mqtt://${this.config.externalMqttServerIP}:${this.config.externalMqttServerPort}`, { clientId: `ioBroker.zigbee2mqtt_${Math.random().toString(16).slice(2, 8)}`, clean: true, reconnectPeriod: 500 });
72
- } else {
73
- const Aedes = require('aedes');
74
- const net = require('net');
75
- const db = new NedbPersistence({
76
- path: `${core.getAbsoluteInstanceDataDir(this)}/mqttData`,
77
- prefix: ''
76
+ }
77
+ // Internal MQTT-Server
78
+ else {
79
+ mqttServerController = new MqttServerController(this);
80
+ await mqttServerController.createMQTTServer();
81
+ await this.delay(1500);
82
+ mqttClient = mqtt.connect(`mqtt://${this.config.mqttServerIPBind}:${this.config.mqttServerPort}`, { clientId: `ioBroker.zigbee2mqtt_${Math.random().toString(16).slice(2, 8)}`, clean: true, reconnectPeriod: 500 });
83
+ }
84
+
85
+ // MQTT Client
86
+ mqttClient.on('connect', () => {
87
+ this.log.info(`Connect to Zigbee2MQTT over ${this.config.connectionType == 'exmqtt' ? 'external mqtt' : 'internal mqtt'} connection.`);
88
+ });
89
+
90
+ mqttClient.subscribe('zigbee2mqtt/#');
91
+
92
+ mqttClient.on('message', (topic, payload) => {
93
+ const newMessage = `{"payload":${payload.toString() == '' ? '"null"' : payload.toString()},"topic":"${topic.slice(topic.search('/') + 1)}"}`;
94
+ this.messageParse(newMessage);
78
95
  });
79
- // @ts-ignore
80
- const aedes = Aedes({ persistence: db });
81
- const mqttServer = net.createServer(aedes.handle);
82
- mqttServer.listen(this.config.mqttServerPort, this.config.mqttServerIPBind, () => { });
83
- mqttClient = mqtt.connect(`mqtt://${this.config.mqttServerIPBind}:${this.config.mqttServerPort}`, { clientId: 'ioBroker.zigbee2mqtt', clean: true, reconnectPeriod: 500 });
84
96
  }
97
+ // Websocket
98
+ else if (this.config.connectionType == 'ws') {
99
+ if (this.config.wsServerIP == '') {
100
+ this.log.warn('Please configure the Websoket connection!');
101
+ return;
102
+ }
85
103
 
86
- mqttClient.on('connect', () => { this.setStateAsync('info.connection', true, true); });
87
- mqttClient.subscribe('#');
88
- mqttClient.on('message', (topic, payload) => {
89
- const newMessage = `{"payload":${payload.toString() == '' ? '"null"' : payload.toString()},"topic":"${topic.slice(topic.search('/') + 1)}"}`;
90
- console.log(newMessage);
91
- this.messageParse(newMessage);
92
- });
104
+ // Dummy MQTT-Server
105
+ if (this.config.dummyMqtt == true) {
106
+ mqttServerController = new MqttServerController(this);
107
+ await mqttServerController.createDummyMQTTServer();
108
+ await this.delay(1500);
109
+ }
110
+
111
+ this.startWebsocket();
112
+ }
93
113
  }
94
114
 
115
+ startWebsocket() {
116
+ websocketController = new WebsocketController(this);
117
+ const wsClient = websocketController.initWsClient();
118
+
119
+ wsClient.on('open', () => {
120
+ this.log.info('Connect to Zigbee2MQTT over websocket connection.');
121
+ });
122
+
123
+ wsClient.on('message', (message) => {
124
+ this.messageParse(message);
125
+ });
126
+
127
+ wsClient.on('close', async () => {
128
+ this.setStateChangedAsync('info.connection', false, true);
129
+ await statesController.setAllAvailableToFalse();
130
+ this.log.warn('Websocket disconnectet');
131
+ });
132
+ }
95
133
 
96
134
  async messageParse(message) {
97
135
  const messageObj = JSON.parse(message);
@@ -107,6 +145,10 @@ class Zigbee2mqtt extends core.Adapter {
107
145
  }
108
146
  break;
109
147
  case 'bridge/state':
148
+ if (messageObj.payload.state != 'online') {
149
+ statesController.setAllAvailableToFalse();
150
+ }
151
+ this.setStateChangedAsync('info.connection', messageObj.payload.state == 'online', true);
110
152
  break;
111
153
  case 'bridge/devices':
112
154
  await deviceController.createDeviceDefinitions(messageObj.payload);
@@ -121,6 +163,10 @@ class Zigbee2mqtt extends core.Adapter {
121
163
  statesController.processQueue();
122
164
  break;
123
165
  case 'bridge/event':
166
+ console.log(JSON.stringify(messageObj));
167
+ deviceController.processRemoveEvent(messageObj);
168
+ break;
169
+ case 'bridge/response/device/remove':
124
170
  deviceController.processRemoveEvent(messageObj);
125
171
  break;
126
172
  case 'bridge/extensions':
@@ -174,10 +220,8 @@ class Zigbee2mqtt extends core.Adapter {
174
220
  async onUnload(callback) {
175
221
  try {
176
222
  await statesController.setAllAvailableToFalse();
177
- clearTimeout(ping);
178
- clearTimeout(pingTimeout);
179
- clearTimeout(autoRestartTimeout);
180
- clearTimeout(checkAvailableTimout);
223
+ await websocketController.allTimerClear();
224
+ await statesController.allTimerClear();
181
225
  callback();
182
226
  } catch (e) {
183
227
  callback();
@@ -187,18 +231,23 @@ class Zigbee2mqtt extends core.Adapter {
187
231
  async onStateChange(id, state) {
188
232
  if (state && state.ack == false) {
189
233
  if (id.includes('info.debugmessages')) {
190
- debugDevices = state.val;
234
+ logCustomizations.debugDevices = state.val;
191
235
  this.setState(id, state.val, true);
192
236
  return;
193
237
  }
194
238
  if (id.includes('info.logfilter')) {
195
- logfilter = state.val.split(';').filter(x => x); // filter removes empty strings here
239
+ logCustomizations.logfilter = state.val.split(';').filter(x => x); // filter removes empty strings here
196
240
  this.setState(id, state.val, true);
197
241
  return;
198
242
  }
199
243
 
200
244
  const message = await z2mController.createZ2MMessage(id, state) || { topic: '', payload: '' };
201
- mqttClient.publish('zigbee2mqtt/' + message.topic, JSON.stringify(message.payload));
245
+
246
+ if (['exmqtt', 'intmqtt'].includes(this.config.connectionType)) {
247
+ mqttClient.publish(`zigbee2mqtt/${message.topic}`, JSON.stringify(message.payload));
248
+ } else if (this.config.connectionType == 'ws') {
249
+ websocketController.send(JSON.stringify(message));
250
+ }
202
251
  }
203
252
  }
204
253
  }
@@ -213,4 +262,4 @@ if (require.main !== module) {
213
262
  } else {
214
263
  // otherwise start the instance directly
215
264
  new Zigbee2mqtt();
216
- }
265
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.zigbee2mqtt",
3
- "version": "1.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "Zigbee2MQTT adapter for ioBroker",
5
5
  "author": {
6
6
  "name": "Dennis Rathjen",
@@ -19,8 +19,6 @@
19
19
  "url": "https://github.com/o0shojo0o/ioBroker.zigbee2mqtt.git"
20
20
  },
21
21
  "dependencies": {
22
- "@alcalzone/release-script-plugin-iobroker": "^3.5.9",
23
- "@alcalzone/release-script-plugin-license": "^3.5.9",
24
22
  "@iobroker/adapter-core": "^2.6.7",
25
23
  "aedes": "^0.48.0",
26
24
  "aedes-persistence-nedb": "^2.0.3",
@@ -29,6 +27,8 @@
29
27
  "ws": "^8.9.0"
30
28
  },
31
29
  "devDependencies": {
30
+ "@alcalzone/release-script-plugin-iobroker": "^3.5.9",
31
+ "@alcalzone/release-script-plugin-license": "^3.5.9",
32
32
  "@alcalzone/release-script": "^3.5.9",
33
33
  "@iobroker/adapter-dev": "^1.1.0",
34
34
  "@iobroker/testing": "^4.1.0",
@@ -36,7 +36,7 @@
36
36
  "@types/chai": "^4.3.3",
37
37
  "@types/chai-as-promised": "^7.1.5",
38
38
  "@types/mocha": "^10.0.0",
39
- "@types/node": "^18.8.3",
39
+ "@types/node": "^18.11.0",
40
40
  "@types/proxyquire": "^1.3.28",
41
41
  "@types/sinon": "^10.0.13",
42
42
  "@types/sinon-chai": "^3.2.8",
@@ -45,7 +45,7 @@
45
45
  "eslint": "^8.25.0",
46
46
  "eslint-config-prettier": "^8.5.0",
47
47
  "eslint-plugin-prettier": "^4.2.1",
48
- "mocha": "^10.0.0",
48
+ "mocha": "^10.1.0",
49
49
  "prettier": "^2.7.1",
50
50
  "proxyquire": "^2.1.3",
51
51
  "sinon": "^14.0.1",