iobroker.zigbee2mqtt 3.0.10 → 3.0.14
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/LICENSE +1 -1
- package/README.md +17 -245
- package/io-package.json +54 -42
- package/lib/check.js +6 -0
- package/lib/colors.js +26 -6
- package/lib/deviceController.js +66 -12
- package/lib/exposes.js +61 -50
- package/lib/imageController.js +52 -3
- package/lib/messages.js +10 -0
- package/lib/mqttServerController.js +20 -6
- package/lib/nonGenericDevicesExtension.js +6 -2
- package/lib/rgb.js +75 -30
- package/lib/statesController.js +53 -0
- package/lib/utils.js +54 -7
- package/lib/websocketController.js +29 -0
- package/lib/z2mController.js +19 -0
- package/main.js +8 -10
- package/package.json +3 -7
package/lib/rgb.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
2
|
/*
|
|
3
3
|
With these functions you can convert the CIE color space to the RGB color space and vice versa.
|
|
4
4
|
|
|
@@ -44,7 +44,11 @@ const colors = require('./colors.js');
|
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
46
|
* Converts CIE color space to RGB color space
|
|
47
|
-
*
|
|
47
|
+
*
|
|
48
|
+
* @param x
|
|
49
|
+
* @param y
|
|
50
|
+
* @param brightness
|
|
51
|
+
* @returns {Array} Array that contains the color values for red, green and blue
|
|
48
52
|
*/
|
|
49
53
|
function cie_to_rgb(x, y, brightness) {
|
|
50
54
|
//Set to maximum brightness if no custom value was given (Not the slick ECMAScript 6 way for compatibility reasons)
|
|
@@ -54,17 +58,12 @@ function cie_to_rgb(x, y, brightness) {
|
|
|
54
58
|
|
|
55
59
|
const z = 1.0 - x - y;
|
|
56
60
|
const Y = (brightness / 254).toFixed(2);
|
|
57
|
-
// @ts-ignore
|
|
58
61
|
const X = (Y / y) * x;
|
|
59
|
-
// @ts-ignore
|
|
60
62
|
const Z = (Y / y) * z;
|
|
61
63
|
|
|
62
64
|
//Convert to RGB using Wide RGB D65 conversion
|
|
63
|
-
// @ts-ignore
|
|
64
65
|
let red = X * 1.656492 - Y * 0.354851 - Z * 0.255038;
|
|
65
|
-
// @ts-ignore
|
|
66
66
|
let green = -X * 0.707196 + Y * 1.655397 + Z * 0.036152;
|
|
67
|
-
// @ts-ignore
|
|
68
67
|
let blue = X * 0.051713 - Y * 0.121364 + Z * 1.01153;
|
|
69
68
|
|
|
70
69
|
//If red, green or blue is larger than 1.0 set it back to the maximum of 1.0
|
|
@@ -109,10 +108,11 @@ function cie_to_rgb(x, y, brightness) {
|
|
|
109
108
|
|
|
110
109
|
/**
|
|
111
110
|
* Converts RGB color space to CIE color space
|
|
112
|
-
*
|
|
113
|
-
* @param {
|
|
114
|
-
* @param {
|
|
115
|
-
* @
|
|
111
|
+
*
|
|
112
|
+
* @param {number} red
|
|
113
|
+
* @param {number} green
|
|
114
|
+
* @param {number} blue
|
|
115
|
+
* @returns {Array} Array that contains the CIE color values for x and y
|
|
116
116
|
*/
|
|
117
117
|
function rgb_to_cie(red, green, blue) {
|
|
118
118
|
// Apply a gamma correction to the RGB values, which makes the color more vivid and more the like the color displayed on the screen of your device
|
|
@@ -129,21 +129,23 @@ function rgb_to_cie(red, green, blue) {
|
|
|
129
129
|
let x = (X / (X + Y + Z)).toFixed(4);
|
|
130
130
|
let y = (Y / (X + Y + Z)).toFixed(4);
|
|
131
131
|
|
|
132
|
-
// @ts-ignore
|
|
133
132
|
if (isNaN(x)) {
|
|
134
|
-
// @ts-ignore
|
|
135
133
|
x = 0;
|
|
136
134
|
}
|
|
137
135
|
|
|
138
|
-
// @ts-ignore
|
|
139
136
|
if (isNaN(y)) {
|
|
140
|
-
// @ts-ignore
|
|
141
137
|
y = 0;
|
|
142
138
|
}
|
|
143
139
|
|
|
144
140
|
return [x, y];
|
|
145
141
|
}
|
|
146
142
|
|
|
143
|
+
/**
|
|
144
|
+
*
|
|
145
|
+
* @param h
|
|
146
|
+
* @param s
|
|
147
|
+
* @param v
|
|
148
|
+
*/
|
|
147
149
|
function hsvToRGB(h, s, v) {
|
|
148
150
|
h = (h % 360) / 360;
|
|
149
151
|
s = s / 100;
|
|
@@ -187,6 +189,13 @@ function hsvToRGB(h, s, v) {
|
|
|
187
189
|
};
|
|
188
190
|
}
|
|
189
191
|
|
|
192
|
+
/**
|
|
193
|
+
*
|
|
194
|
+
* @param r
|
|
195
|
+
* @param g
|
|
196
|
+
* @param b
|
|
197
|
+
* @param numeric
|
|
198
|
+
*/
|
|
190
199
|
function rgbToHSV(r, g, b, numeric) {
|
|
191
200
|
if (arguments.length === 1) {
|
|
192
201
|
(g = r.g), (b = r.b), (r = r.r);
|
|
@@ -215,21 +224,26 @@ function rgbToHSV(r, g, b, numeric) {
|
|
|
215
224
|
h /= 6 * d;
|
|
216
225
|
break;
|
|
217
226
|
}
|
|
218
|
-
if (numeric)
|
|
219
|
-
|
|
220
|
-
|
|
227
|
+
if (numeric) {
|
|
228
|
+
return {
|
|
229
|
+
|
|
221
230
|
h: Math.round(h * 360),
|
|
222
231
|
s: Math.round(s * 100),
|
|
223
232
|
v: Math.round(v * 100),
|
|
224
233
|
};
|
|
225
|
-
|
|
226
|
-
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
|
|
227
237
|
h: (h * 360).toFixed(3),
|
|
228
238
|
s: (s * 100).toFixed(3),
|
|
229
239
|
v: (v * 100).toFixed(3),
|
|
230
|
-
|
|
231
|
-
}
|
|
240
|
+
};
|
|
241
|
+
}
|
|
232
242
|
|
|
243
|
+
/**
|
|
244
|
+
*
|
|
245
|
+
* @param value
|
|
246
|
+
*/
|
|
233
247
|
function colorArrayFromString(value) {
|
|
234
248
|
if (typeof value === 'string') {
|
|
235
249
|
const rv = [];
|
|
@@ -241,6 +255,10 @@ function colorArrayFromString(value) {
|
|
|
241
255
|
return [{ r: 0, g: 128, b: 255 }];
|
|
242
256
|
}
|
|
243
257
|
|
|
258
|
+
/**
|
|
259
|
+
*
|
|
260
|
+
* @param payload
|
|
261
|
+
*/
|
|
244
262
|
function colorStringFromRGBArray(payload) {
|
|
245
263
|
const rv = [];
|
|
246
264
|
payload.forEach((element) => {
|
|
@@ -249,6 +267,12 @@ function colorStringFromRGBArray(payload) {
|
|
|
249
267
|
return rv.toString();
|
|
250
268
|
}
|
|
251
269
|
|
|
270
|
+
/**
|
|
271
|
+
*
|
|
272
|
+
* @param h
|
|
273
|
+
* @param s
|
|
274
|
+
* @param v
|
|
275
|
+
*/
|
|
252
276
|
function hsv_to_cie(h, s, v) {
|
|
253
277
|
const rgb = hsvToRGB(h, s, v);
|
|
254
278
|
return rgb_to_cie(rgb.r, rgb.g, rgb.b);
|
|
@@ -256,20 +280,35 @@ function hsv_to_cie(h, s, v) {
|
|
|
256
280
|
|
|
257
281
|
function rgb_to_rgbstring(element) {
|
|
258
282
|
let col = '#';
|
|
259
|
-
if (element && element.hasOwnProperty('r'))
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
283
|
+
if (element && element.hasOwnProperty('r')) {
|
|
284
|
+
col = col + element.r.toString(16).padStart(2, '0');
|
|
285
|
+
} else {
|
|
286
|
+
col = `${col }00`;
|
|
287
|
+
}
|
|
288
|
+
if (element && element.hasOwnProperty('g')) {
|
|
289
|
+
col = col + element.g.toString(16).padStart(2, '0');
|
|
290
|
+
} else {
|
|
291
|
+
col = `${col }00`;
|
|
292
|
+
}
|
|
293
|
+
if (element && element.hasOwnProperty('b')) {
|
|
294
|
+
col = col + element.b.toString(16).padStart(2, '0');
|
|
295
|
+
} else {
|
|
296
|
+
col = `${col }00`;
|
|
297
|
+
}
|
|
265
298
|
return col;
|
|
266
299
|
}
|
|
267
300
|
|
|
301
|
+
/**
|
|
302
|
+
*
|
|
303
|
+
* @param h
|
|
304
|
+
* @param s
|
|
305
|
+
* @param b
|
|
306
|
+
*/
|
|
268
307
|
function hsbToRGB(h, s, b) {
|
|
269
308
|
const br = Math.round(b * 2.55);
|
|
270
309
|
if (s == 0) {
|
|
271
310
|
return [br, br, br];
|
|
272
|
-
}
|
|
311
|
+
}
|
|
273
312
|
const hue = h % 360;
|
|
274
313
|
const f = hue % 60;
|
|
275
314
|
const p = Math.round(b * (100 - s) * 0.0255);
|
|
@@ -289,10 +328,16 @@ function hsbToRGB(h, s, b) {
|
|
|
289
328
|
case 5:
|
|
290
329
|
return [br, p, q];
|
|
291
330
|
}
|
|
292
|
-
|
|
331
|
+
|
|
293
332
|
return false;
|
|
294
333
|
}
|
|
295
334
|
|
|
335
|
+
/**
|
|
336
|
+
*
|
|
337
|
+
* @param h
|
|
338
|
+
* @param s
|
|
339
|
+
* @param v
|
|
340
|
+
*/
|
|
296
341
|
function hsvToRGBString(h, s, v) {
|
|
297
342
|
return rgb_to_rgbstring(hsvToRGB(h, s, v));
|
|
298
343
|
}
|
package/lib/statesController.js
CHANGED
|
@@ -2,7 +2,18 @@ const utils = require('./utils');
|
|
|
2
2
|
const incStatsQueue = [];
|
|
3
3
|
const timeOutCache = {};
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
5
8
|
class StatesController {
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @param adapter
|
|
12
|
+
* @param deviceCache
|
|
13
|
+
* @param groupCache
|
|
14
|
+
* @param logCustomizations
|
|
15
|
+
* @param createCache
|
|
16
|
+
*/
|
|
6
17
|
constructor(adapter, deviceCache, groupCache, logCustomizations, createCache) {
|
|
7
18
|
this.adapter = adapter;
|
|
8
19
|
this.groupCache = groupCache;
|
|
@@ -11,6 +22,10 @@ class StatesController {
|
|
|
11
22
|
this.createCache = createCache;
|
|
12
23
|
}
|
|
13
24
|
|
|
25
|
+
/**
|
|
26
|
+
*
|
|
27
|
+
* @param messageObj
|
|
28
|
+
*/
|
|
14
29
|
processDeviceMessage(messageObj) {
|
|
15
30
|
// Is payload present?
|
|
16
31
|
if (messageObj.payload == '') {
|
|
@@ -30,6 +45,11 @@ class StatesController {
|
|
|
30
45
|
}
|
|
31
46
|
}
|
|
32
47
|
|
|
48
|
+
/**
|
|
49
|
+
*
|
|
50
|
+
* @param messageObj
|
|
51
|
+
* @param device
|
|
52
|
+
*/
|
|
33
53
|
async setDeviceStateSafely(messageObj, device) {
|
|
34
54
|
if (this.logCustomizations.debugDevices.includes(device.ieee_address)) {
|
|
35
55
|
this.adapter.log.warn(`--->>> fromZ2M -> ${device.ieee_address} states: ${JSON.stringify(messageObj)}`);
|
|
@@ -142,6 +162,11 @@ class StatesController {
|
|
|
142
162
|
} else {
|
|
143
163
|
await this.setStateChangedSafelyAsync(stateName, state.getter(messageObj.payload));
|
|
144
164
|
}
|
|
165
|
+
|
|
166
|
+
// publish the action into action dp
|
|
167
|
+
if (state.prop && state.prop == 'action') {
|
|
168
|
+
await this.setStateSafelyAsync(`${device.ieee_address}.action`, messageObj.payload.action);
|
|
169
|
+
}
|
|
145
170
|
} catch (err) {
|
|
146
171
|
incStatsQueue[incStatsQueue.length] = messageObj;
|
|
147
172
|
this.adapter.log.debug(`Can not set ${stateName}, queue state in incStatsQueue!`);
|
|
@@ -149,6 +174,11 @@ class StatesController {
|
|
|
149
174
|
}
|
|
150
175
|
}
|
|
151
176
|
|
|
177
|
+
/**
|
|
178
|
+
*
|
|
179
|
+
* @param stateName
|
|
180
|
+
* @param value
|
|
181
|
+
*/
|
|
152
182
|
async setStateSafelyAsync(stateName, value) {
|
|
153
183
|
if (value === undefined || value === null) {
|
|
154
184
|
return;
|
|
@@ -156,6 +186,11 @@ class StatesController {
|
|
|
156
186
|
await this.adapter.setStateAsync(stateName, value, true);
|
|
157
187
|
}
|
|
158
188
|
|
|
189
|
+
/**
|
|
190
|
+
*
|
|
191
|
+
* @param stateName
|
|
192
|
+
* @param value
|
|
193
|
+
*/
|
|
159
194
|
async setStateChangedSafelyAsync(stateName, value) {
|
|
160
195
|
if (value === undefined || value === null) {
|
|
161
196
|
return;
|
|
@@ -163,6 +198,12 @@ class StatesController {
|
|
|
163
198
|
await this.adapter.setStateChangedAsync(stateName, value, true);
|
|
164
199
|
}
|
|
165
200
|
|
|
201
|
+
/**
|
|
202
|
+
*
|
|
203
|
+
* @param stateName
|
|
204
|
+
* @param value
|
|
205
|
+
* @param timeout
|
|
206
|
+
*/
|
|
166
207
|
async setStateWithTimeoutAsync(stateName, value, timeout) {
|
|
167
208
|
if (value === undefined || value === null) {
|
|
168
209
|
return;
|
|
@@ -177,6 +218,9 @@ class StatesController {
|
|
|
177
218
|
}, timeout);
|
|
178
219
|
}
|
|
179
220
|
|
|
221
|
+
/**
|
|
222
|
+
*
|
|
223
|
+
*/
|
|
180
224
|
processQueue() {
|
|
181
225
|
const oldIncStatsQueue = [];
|
|
182
226
|
utils.moveArray(incStatsQueue, oldIncStatsQueue);
|
|
@@ -185,6 +229,9 @@ class StatesController {
|
|
|
185
229
|
}
|
|
186
230
|
}
|
|
187
231
|
|
|
232
|
+
/**
|
|
233
|
+
*
|
|
234
|
+
*/
|
|
188
235
|
async subscribeWritableStates() {
|
|
189
236
|
await this.adapter.unsubscribeObjectsAsync('*');
|
|
190
237
|
for (const device of this.groupCache.concat(this.deviceCache)) {
|
|
@@ -199,6 +246,9 @@ class StatesController {
|
|
|
199
246
|
this.adapter.subscribeStates('info.coordinator_check');
|
|
200
247
|
}
|
|
201
248
|
|
|
249
|
+
/**
|
|
250
|
+
*
|
|
251
|
+
*/
|
|
202
252
|
async setAllAvailableToFalse() {
|
|
203
253
|
const availableStates = await this.adapter.getStatesAsync('*.available');
|
|
204
254
|
for (const availableState in availableStates) {
|
|
@@ -206,6 +256,9 @@ class StatesController {
|
|
|
206
256
|
}
|
|
207
257
|
}
|
|
208
258
|
|
|
259
|
+
/**
|
|
260
|
+
*
|
|
261
|
+
*/
|
|
209
262
|
async allTimerClear() {
|
|
210
263
|
for (const timer in timeOutCache) {
|
|
211
264
|
clearTimeout(timeOutCache[timer]);
|
package/lib/utils.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Converts a bulb level of range [0...254] to an adapter level of range [0...100]
|
|
3
|
+
*
|
|
4
|
+
* @param bulbLevel
|
|
3
5
|
*/
|
|
4
6
|
function bulbLevelToAdapterLevel(bulbLevel) {
|
|
5
7
|
// Convert from bulb levels [0...254] to adapter levels [0...100]:
|
|
@@ -19,14 +21,16 @@ function bulbLevelToAdapterLevel(bulbLevel) {
|
|
|
19
21
|
if (bulbLevel >= 2) {
|
|
20
22
|
// Perform linear mapping of range [2...254] to [1...100]
|
|
21
23
|
return Math.round(((bulbLevel - 2) * 99) / 252) + 1;
|
|
22
|
-
}
|
|
24
|
+
}
|
|
23
25
|
// The bulb is considered off. Even a bulb level of "1" is considered as off.
|
|
24
26
|
return 0;
|
|
25
|
-
|
|
27
|
+
// else
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
/**
|
|
29
31
|
* Converts an adapter level of range [0...100] to a bulb level of range [0...254]
|
|
32
|
+
*
|
|
33
|
+
* @param adapterLevel
|
|
30
34
|
*/
|
|
31
35
|
function adapterLevelToBulbLevel(adapterLevel) {
|
|
32
36
|
// Convert from adapter levels [0...100] to bulb levels [0...254].
|
|
@@ -35,13 +39,17 @@ function adapterLevelToBulbLevel(adapterLevel) {
|
|
|
35
39
|
if (adapterLevel) {
|
|
36
40
|
// Perform linear mapping of range [1...100] to [2...254]
|
|
37
41
|
return Math.round(((adapterLevel - 1) * 252) / 99) + 2;
|
|
38
|
-
}
|
|
42
|
+
}
|
|
39
43
|
// Switch the bulb off. Some bulbs need "0" (IKEA), others "1" (HUE), and according to the
|
|
40
44
|
// ZigBee docs "1" is the "minimum possible level"... we choose "0" here which seems to work.
|
|
41
45
|
return 0;
|
|
42
|
-
|
|
46
|
+
// else
|
|
43
47
|
}
|
|
44
48
|
|
|
49
|
+
/**
|
|
50
|
+
*
|
|
51
|
+
* @param ba
|
|
52
|
+
*/
|
|
45
53
|
function bytesArrayToWordArray(ba) {
|
|
46
54
|
const wa = [];
|
|
47
55
|
for (let i = 0; i < ba.length; i++) {
|
|
@@ -52,6 +60,10 @@ function bytesArrayToWordArray(ba) {
|
|
|
52
60
|
|
|
53
61
|
// If the value is greater than 1000, kelvin is assumed.
|
|
54
62
|
// If smaller, it is assumed to be mired.
|
|
63
|
+
/**
|
|
64
|
+
*
|
|
65
|
+
* @param t
|
|
66
|
+
*/
|
|
55
67
|
function toMired(t) {
|
|
56
68
|
let miredValue = t;
|
|
57
69
|
if (t > 1000) {
|
|
@@ -60,12 +72,19 @@ function toMired(t) {
|
|
|
60
72
|
return miredValue;
|
|
61
73
|
}
|
|
62
74
|
|
|
75
|
+
/**
|
|
76
|
+
*
|
|
77
|
+
* @param t
|
|
78
|
+
*/
|
|
63
79
|
function miredKelvinConversion(t) {
|
|
64
80
|
return Math.round(1000000 / t);
|
|
65
81
|
}
|
|
66
82
|
|
|
67
83
|
/**
|
|
68
84
|
* Converts a decimal number to a hex string with zero-padding
|
|
85
|
+
*
|
|
86
|
+
* @param decimal
|
|
87
|
+
* @param padding
|
|
69
88
|
*/
|
|
70
89
|
function decimalToHex(decimal, padding) {
|
|
71
90
|
let hex = Number(decimal).toString(16);
|
|
@@ -78,32 +97,60 @@ function decimalToHex(decimal, padding) {
|
|
|
78
97
|
return hex;
|
|
79
98
|
}
|
|
80
99
|
|
|
100
|
+
/**
|
|
101
|
+
*
|
|
102
|
+
* @param adapterDevId
|
|
103
|
+
*/
|
|
81
104
|
function getZbId(adapterDevId) {
|
|
82
105
|
const idx = adapterDevId.indexOf('group');
|
|
83
|
-
if (idx > 0)
|
|
84
|
-
|
|
106
|
+
if (idx > 0) {
|
|
107
|
+
return adapterDevId.substr(idx + 6);
|
|
108
|
+
}
|
|
109
|
+
return `0x${ adapterDevId.split('.')[2]}`;
|
|
85
110
|
}
|
|
86
111
|
|
|
112
|
+
/**
|
|
113
|
+
*
|
|
114
|
+
* @param adapter
|
|
115
|
+
* @param id
|
|
116
|
+
*/
|
|
87
117
|
function getAdId(adapter, id) {
|
|
88
|
-
return adapter.namespace
|
|
118
|
+
return `${adapter.namespace }.${ id.split('.')[2]}`; // iobroker device id
|
|
89
119
|
}
|
|
90
120
|
|
|
121
|
+
/**
|
|
122
|
+
*
|
|
123
|
+
* @param array
|
|
124
|
+
*/
|
|
91
125
|
function clearArray(array) {
|
|
92
126
|
while (array.length > 0) {
|
|
93
127
|
array.pop();
|
|
94
128
|
}
|
|
95
129
|
}
|
|
96
130
|
|
|
131
|
+
/**
|
|
132
|
+
*
|
|
133
|
+
* @param source
|
|
134
|
+
* @param target
|
|
135
|
+
*/
|
|
97
136
|
function moveArray(source, target) {
|
|
98
137
|
while (source.length > 0) {
|
|
99
138
|
target.push(source.shift());
|
|
100
139
|
}
|
|
101
140
|
}
|
|
102
141
|
|
|
142
|
+
/**
|
|
143
|
+
*
|
|
144
|
+
* @param item
|
|
145
|
+
*/
|
|
103
146
|
function isObject(item) {
|
|
104
147
|
return typeof item === 'object' && !Array.isArray(item) && item !== null;
|
|
105
148
|
}
|
|
106
149
|
|
|
150
|
+
/**
|
|
151
|
+
*
|
|
152
|
+
* @param item
|
|
153
|
+
*/
|
|
107
154
|
function isJson(item) {
|
|
108
155
|
let value = typeof item !== 'string' ? JSON.stringify(item) : item;
|
|
109
156
|
try {
|
|
@@ -6,11 +6,21 @@ let ping;
|
|
|
6
6
|
let pingTimeout;
|
|
7
7
|
let autoRestartTimeout;
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
*/
|
|
9
12
|
class WebsocketController {
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
* @param adapter
|
|
16
|
+
*/
|
|
10
17
|
constructor(adapter) {
|
|
11
18
|
this.adapter = adapter;
|
|
12
19
|
}
|
|
13
20
|
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
14
24
|
initWsClient() {
|
|
15
25
|
try {
|
|
16
26
|
let wsURL = `${this.adapter.config.wsScheme}://${this.adapter.config.wsServerIP}:${this.adapter.config.wsServerPort}/api`;
|
|
@@ -53,6 +63,10 @@ class WebsocketController {
|
|
|
53
63
|
}
|
|
54
64
|
}
|
|
55
65
|
|
|
66
|
+
/**
|
|
67
|
+
*
|
|
68
|
+
* @param message
|
|
69
|
+
*/
|
|
56
70
|
send(message) {
|
|
57
71
|
if (wsClient.readyState !== WebSocket.OPEN) {
|
|
58
72
|
this.adapter.log.warn('Cannot set State, no websocket connection to Zigbee2MQTT!');
|
|
@@ -61,6 +75,9 @@ class WebsocketController {
|
|
|
61
75
|
wsClient.send(message);
|
|
62
76
|
}
|
|
63
77
|
|
|
78
|
+
/**
|
|
79
|
+
*
|
|
80
|
+
*/
|
|
64
81
|
sendPingToServer() {
|
|
65
82
|
//this.logDebug('Send ping to server');
|
|
66
83
|
wsClient.ping();
|
|
@@ -69,6 +86,9 @@ class WebsocketController {
|
|
|
69
86
|
}, wsHeartbeatIntervall);
|
|
70
87
|
}
|
|
71
88
|
|
|
89
|
+
/**
|
|
90
|
+
*
|
|
91
|
+
*/
|
|
72
92
|
wsHeartbeat() {
|
|
73
93
|
clearTimeout(pingTimeout);
|
|
74
94
|
pingTimeout = setTimeout(() => {
|
|
@@ -77,6 +97,9 @@ class WebsocketController {
|
|
|
77
97
|
}, wsHeartbeatIntervall + 3000);
|
|
78
98
|
}
|
|
79
99
|
|
|
100
|
+
/**
|
|
101
|
+
*
|
|
102
|
+
*/
|
|
80
103
|
async autoRestart() {
|
|
81
104
|
this.adapter.log.warn(`Start try again in ${restartTimeout / 1000} seconds...`);
|
|
82
105
|
autoRestartTimeout = setTimeout(() => {
|
|
@@ -84,12 +107,18 @@ class WebsocketController {
|
|
|
84
107
|
}, restartTimeout);
|
|
85
108
|
}
|
|
86
109
|
|
|
110
|
+
/**
|
|
111
|
+
*
|
|
112
|
+
*/
|
|
87
113
|
closeConnection() {
|
|
88
114
|
if (wsClient && wsClient.readyState !== WebSocket.CLOSED) {
|
|
89
115
|
wsClient.close();
|
|
90
116
|
}
|
|
91
117
|
}
|
|
92
118
|
|
|
119
|
+
/**
|
|
120
|
+
*
|
|
121
|
+
*/
|
|
93
122
|
async allTimerClear() {
|
|
94
123
|
clearTimeout(pingTimeout);
|
|
95
124
|
clearTimeout(ping);
|
package/lib/z2mController.js
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
*/
|
|
1
4
|
class Z2mController {
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @param adapter
|
|
8
|
+
* @param deviceCache
|
|
9
|
+
* @param groupCache
|
|
10
|
+
* @param logCustomizations
|
|
11
|
+
*/
|
|
2
12
|
constructor(adapter, deviceCache, groupCache, logCustomizations) {
|
|
3
13
|
this.adapter = adapter;
|
|
4
14
|
this.groupCache = groupCache;
|
|
@@ -6,6 +16,11 @@ class Z2mController {
|
|
|
6
16
|
this.logCustomizations = logCustomizations;
|
|
7
17
|
}
|
|
8
18
|
|
|
19
|
+
/**
|
|
20
|
+
*
|
|
21
|
+
* @param id
|
|
22
|
+
* @param state
|
|
23
|
+
*/
|
|
9
24
|
async createZ2MMessage(id, state) {
|
|
10
25
|
const splitedID = id.split('.');
|
|
11
26
|
if (splitedID.length < 4) {
|
|
@@ -114,6 +129,10 @@ class Z2mController {
|
|
|
114
129
|
return controlObj;
|
|
115
130
|
}
|
|
116
131
|
|
|
132
|
+
/**
|
|
133
|
+
*
|
|
134
|
+
* @param messageObj
|
|
135
|
+
*/
|
|
117
136
|
async proxyZ2MLogs(messageObj) {
|
|
118
137
|
const logMessage = messageObj.payload.message;
|
|
119
138
|
if (this.logCustomizations.logfilter.some((x) => logMessage.includes(x))) {
|
package/main.js
CHANGED
|
@@ -68,8 +68,7 @@ class Zigbee2mqtt extends core.Adapter {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
const logfilterState = await this.getStateAsync('info.logfilter');
|
|
71
|
-
if (logfilterState && logfilterState.val) {
|
|
72
|
-
// @ts-ignore
|
|
71
|
+
if (logfilterState && logfilterState.val) {
|
|
73
72
|
logCustomizations.logfilter = String(logfilterState.val)
|
|
74
73
|
.split(';')
|
|
75
74
|
.filter((x) => x); // filter removes empty strings here
|
|
@@ -111,9 +110,8 @@ class Zigbee2mqtt extends core.Adapter {
|
|
|
111
110
|
`mqtt://${this.config.externalMqttServerIP}:${this.config.externalMqttServerPort}`,
|
|
112
111
|
mqttClientOptions
|
|
113
112
|
);
|
|
114
|
-
}
|
|
113
|
+
} else {
|
|
115
114
|
// Internal MQTT-Server
|
|
116
|
-
else {
|
|
117
115
|
mqttServerController = new MqttServerController(this);
|
|
118
116
|
await mqttServerController.createMQTTServer();
|
|
119
117
|
await this.delay(1500);
|
|
@@ -137,9 +135,8 @@ class Zigbee2mqtt extends core.Adapter {
|
|
|
137
135
|
const newMessage = `{"payload":${payload.toString() == '' ? '"null"' : payload.toString()},"topic":"${topic.slice(topic.search('/') + 1)}"}`;
|
|
138
136
|
this.messageParse(newMessage);
|
|
139
137
|
});
|
|
140
|
-
}
|
|
138
|
+
} else if (this.config.connectionType == 'ws') {
|
|
141
139
|
// Websocket
|
|
142
|
-
else if (this.config.connectionType == 'ws') {
|
|
143
140
|
if (this.config.wsServerIP == '') {
|
|
144
141
|
this.log.warn('Please configure the Websoket connection!');
|
|
145
142
|
return;
|
|
@@ -316,9 +313,8 @@ class Zigbee2mqtt extends core.Adapter {
|
|
|
316
313
|
} catch (e) {
|
|
317
314
|
this.log.error(e);
|
|
318
315
|
}
|
|
319
|
-
}
|
|
316
|
+
} else if (this.config.connectionType == 'ws') {
|
|
320
317
|
// Websocket
|
|
321
|
-
else if (this.config.connectionType == 'ws') {
|
|
322
318
|
try {
|
|
323
319
|
if (websocketController) {
|
|
324
320
|
websocketController.closeConnection();
|
|
@@ -352,6 +348,8 @@ class Zigbee2mqtt extends core.Adapter {
|
|
|
352
348
|
this.log.error(e);
|
|
353
349
|
}
|
|
354
350
|
|
|
351
|
+
this.setState('info.connection', false, true);
|
|
352
|
+
|
|
355
353
|
callback();
|
|
356
354
|
}
|
|
357
355
|
|
|
@@ -382,8 +380,8 @@ class Zigbee2mqtt extends core.Adapter {
|
|
|
382
380
|
if (require.main !== module) {
|
|
383
381
|
// Export the constructor in compact mode
|
|
384
382
|
/**
|
|
385
|
-
|
|
386
|
-
|
|
383
|
+
* @param {Partial<core.AdapterOptions>} [options]
|
|
384
|
+
*/
|
|
387
385
|
module.exports = (options) => new Zigbee2mqtt(options);
|
|
388
386
|
} else {
|
|
389
387
|
// otherwise start the instance directly
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.zigbee2mqtt",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.14",
|
|
4
4
|
"description": "Zigbee2MQTT adapter for ioBroker",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Dennis Rathjen and Arthur Rupp",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"mqtt": "^5.14.1",
|
|
32
32
|
"net": "^1.0.2",
|
|
33
33
|
"node-schedule": "^2.1.1",
|
|
34
|
-
"sharp": "^0.
|
|
34
|
+
"sharp": "^0.33.5",
|
|
35
35
|
"ws": "^8.18.3"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
@@ -43,12 +43,8 @@
|
|
|
43
43
|
"@iobroker/testing": "^5.2.2",
|
|
44
44
|
"@iobroker/eslint-config": "^2.1.0",
|
|
45
45
|
"@tsconfig/node14": "^14.1.8",
|
|
46
|
-
"@types/node": "^
|
|
46
|
+
"@types/node": "^25.0.3",
|
|
47
47
|
"@types/node-schedule": "^2.1.8",
|
|
48
|
-
"eslint": "^9.39.1",
|
|
49
|
-
"eslint-config-prettier": "^10.1.8",
|
|
50
|
-
"eslint-plugin-prettier": "^5.5.4",
|
|
51
|
-
"prettier": "^3.6.2",
|
|
52
48
|
"typescript": "~5.9.2"
|
|
53
49
|
},
|
|
54
50
|
"main": "main.js",
|