iobroker.zwavews 0.0.3
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 +21 -0
- package/README.md +63 -0
- package/admin/i18n/de/translations.json +35 -0
- package/admin/i18n/en/translations.json +36 -0
- package/admin/i18n/es/translations.json +35 -0
- package/admin/i18n/fr/translations.json +35 -0
- package/admin/i18n/it/translations.json +35 -0
- package/admin/i18n/nl/translations.json +35 -0
- package/admin/i18n/pl/translations.json +36 -0
- package/admin/i18n/pt/translations.json +35 -0
- package/admin/i18n/ru/translations.json +35 -0
- package/admin/i18n/uk/translations.json +35 -0
- package/admin/i18n/zh-cn/translations.json +35 -0
- package/admin/jsonConfig.json +347 -0
- package/admin/zwavews.png +0 -0
- package/io-package.json +246 -0
- package/lib/adapter-config.d.ts +19 -0
- package/lib/constants.js +25 -0
- package/lib/helper.js +540 -0
- package/lib/messages.js +49 -0
- package/lib/mqttServerController.js +78 -0
- package/lib/statesController.js +84 -0
- package/lib/utils.js +205 -0
- package/lib/websocketController.js +131 -0
- package/main.js +407 -0
- package/package.json +75 -0
package/lib/helper.js
ADDED
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
const utils = require("./utils");
|
|
2
|
+
const constant = require("./constants");
|
|
3
|
+
const {isObject} = require("./utils");
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
options:
|
|
7
|
+
write //set common write variable to true
|
|
8
|
+
forceIndex //instead of trying to find names for array entries, use the index as the name
|
|
9
|
+
channelName //set name of the root channel
|
|
10
|
+
preferedArrayName //set key to use this as an array entry name
|
|
11
|
+
autoCast (true false) // make JSON.parse to parse numbers correctly
|
|
12
|
+
descriptions: Object of names for state keys
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
class Helper {
|
|
18
|
+
/**
|
|
19
|
+
*
|
|
20
|
+
* @param adapter
|
|
21
|
+
* @param alreadyCreatedObjects
|
|
22
|
+
*/
|
|
23
|
+
constructor(adapter, alreadyCreatedObjects = {}) {
|
|
24
|
+
this.adapter = adapter;
|
|
25
|
+
this.alreadyCreatedObjects = alreadyCreatedObjects;
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
* @param path
|
|
32
|
+
* @param element
|
|
33
|
+
* @param options
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
*
|
|
39
|
+
* @param nodeIdOriginal
|
|
40
|
+
* @param element
|
|
41
|
+
*/
|
|
42
|
+
async createNode(nodeIdOriginal, element) {
|
|
43
|
+
try {
|
|
44
|
+
let nodeId = utils.formatNodeId(nodeIdOriginal);
|
|
45
|
+
|
|
46
|
+
if (element == null) {
|
|
47
|
+
this.adapter.log.debug(`Cannot extract NodeId: ${nodeId}`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
await this.adapter.setObjectNotExistsAsync(nodeId, {
|
|
52
|
+
type: "device",
|
|
53
|
+
common: {
|
|
54
|
+
name: element.name ?? element.label,
|
|
55
|
+
statusStates: {
|
|
56
|
+
onlineId: `${nodeId}.ready`,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
native: {},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
await this.createReadyStatus(nodeId);
|
|
63
|
+
|
|
64
|
+
const valuesOnly = element.values ?? null;
|
|
65
|
+
delete element.values;
|
|
66
|
+
await this.parse(`${nodeId}.info`, element);
|
|
67
|
+
|
|
68
|
+
if (valuesOnly != null && typeof valuesOnly === "object" && valuesOnly.length > 0) {
|
|
69
|
+
for (const v of valuesOnly) {
|
|
70
|
+
let parsePath = `${nodeId}.${v.commandClassName}`;
|
|
71
|
+
let metadata = v.metadata || {};
|
|
72
|
+
|
|
73
|
+
if (constant.noInfoDP.includes(v.commandClassName)) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (constant.noInfoDP.includes(v.propertyName)) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!this.alreadyCreatedObjects[parsePath]) {
|
|
81
|
+
this.alreadyCreatedObjects[parsePath] = {};
|
|
82
|
+
|
|
83
|
+
await this.adapter.setObjectNotExistsAsync(parsePath, {
|
|
84
|
+
type: "channel",
|
|
85
|
+
common: {
|
|
86
|
+
name: metadata.label || "",
|
|
87
|
+
},
|
|
88
|
+
native: {},
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
parsePath = `${nodeId}.${v.commandClassName}.${v.propertyName
|
|
93
|
+
.replace(/[^\p{L}\p{N}\s]/gu, "")
|
|
94
|
+
.replace(/\s+/g, " ")
|
|
95
|
+
.trim()}`;
|
|
96
|
+
|
|
97
|
+
if (v?.propertyKeyName) {
|
|
98
|
+
parsePath = `${parsePath}.${v.propertyKeyName
|
|
99
|
+
.replace(/[^\p{L}\p{N}\s]/gu, "")
|
|
100
|
+
.replace(/\s+/g, " ")
|
|
101
|
+
.trim()}`;
|
|
102
|
+
|
|
103
|
+
if (constant.RGB.includes(v.propertyKeyName)) {
|
|
104
|
+
parsePath = utils.replaceLastDot(parsePath);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (this.isObject(v.value)) { // da gibts ein object mit value
|
|
109
|
+
parsePath = `${parsePath}_value`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const nam_id = v.label ?? v.propertyName;
|
|
113
|
+
|
|
114
|
+
metadata.value = v.value; // add value for resolution
|
|
115
|
+
const val = this.resolveCommandClassValue(metadata) ?? 0;
|
|
116
|
+
let typeDp = metadata.type === "timeout" ? "number" : metadata.type;
|
|
117
|
+
|
|
118
|
+
if (constant.mixedType.includes(nam_id)) {
|
|
119
|
+
typeDp = "mixed";
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const common = {
|
|
123
|
+
id: nam_id,
|
|
124
|
+
name: nam_id,
|
|
125
|
+
write: metadata.writeable,
|
|
126
|
+
read: metadata.readable,
|
|
127
|
+
desc: metadata.label,
|
|
128
|
+
type: typeDp,
|
|
129
|
+
min: metadata?.min,
|
|
130
|
+
max: metadata?.max,
|
|
131
|
+
def: v.default ?? (typeDp === "boolean" ? false : metadata?.min),
|
|
132
|
+
unit: metadata?.unit ?? "",
|
|
133
|
+
role: this.getRole(val, metadata.writeable, parsePath),
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
if (metadata?.states) {
|
|
137
|
+
common.states = metadata?.states;
|
|
138
|
+
}
|
|
139
|
+
const native = {
|
|
140
|
+
valueId : { commandClass: v.commandClass,
|
|
141
|
+
endpoint: v.endpoint,
|
|
142
|
+
property: v.property
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
if (v?.propertyKey) {
|
|
147
|
+
native.valueId.propertyKey = v.propertyKey;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
await this.adapter.setObjectNotExistsAsync(parsePath, {
|
|
151
|
+
type: "state",
|
|
152
|
+
common,
|
|
153
|
+
native,
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
if (common.write === true) {
|
|
157
|
+
this.adapter.subscribeStates(parsePath);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
this.alreadyCreatedObjects[parsePath] = { };
|
|
161
|
+
|
|
162
|
+
this.adapter.setState(parsePath, val, true);
|
|
163
|
+
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
} catch (error) {
|
|
167
|
+
this.adapter.log.error(`Cannot create node ${nodeIdOriginal} : ${error}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
*
|
|
177
|
+
* @param path
|
|
178
|
+
* @param element
|
|
179
|
+
* @param options
|
|
180
|
+
*/
|
|
181
|
+
async parse(path, element, options = { write: false }) {
|
|
182
|
+
let parsePath = path;
|
|
183
|
+
|
|
184
|
+
if (element == null) {
|
|
185
|
+
this.adapter.log.debug(`Cannot extract empty: ${parsePath}`);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (typeof element === "string" || typeof element === "number" || typeof element === "boolean") {
|
|
190
|
+
let val = element ?? 0;
|
|
191
|
+
|
|
192
|
+
if (!this.alreadyCreatedObjects[parsePath]) {
|
|
193
|
+
try {
|
|
194
|
+
let common = {};
|
|
195
|
+
if (typeof element === "string" || typeof element === "number") {
|
|
196
|
+
common = {
|
|
197
|
+
id: parsePath,
|
|
198
|
+
name: parsePath,
|
|
199
|
+
role: this.getRole(element, options.write),
|
|
200
|
+
type: typeof element,
|
|
201
|
+
write: options.write,
|
|
202
|
+
read: true,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
await this.adapter.setObjectNotExistsAsync(parsePath, {
|
|
206
|
+
type: "state",
|
|
207
|
+
common,
|
|
208
|
+
native: { },
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
if (common.write === true) {
|
|
212
|
+
this.adapter.subscribeStates(parsePath);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
this.alreadyCreatedObjects[parsePath] = {};
|
|
216
|
+
} catch (error) {
|
|
217
|
+
this.adapter.log.error(error);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
this.adapter.setState(parsePath, val, true);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
options.channelName = utils.getLastSegment(parsePath);
|
|
225
|
+
|
|
226
|
+
if (!this.alreadyCreatedObjects[parsePath]) {
|
|
227
|
+
try {
|
|
228
|
+
await this.adapter.setObjectNotExistsAsync(parsePath, {
|
|
229
|
+
type: "channel",
|
|
230
|
+
common: {
|
|
231
|
+
name: options.channelName || ""
|
|
232
|
+
},
|
|
233
|
+
native: {},
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
this.alreadyCreatedObjects[parsePath] = { };
|
|
237
|
+
delete options.channelName;
|
|
238
|
+
} catch (error) {
|
|
239
|
+
this.adapter.log.error(error);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (Array.isArray(element)) {
|
|
244
|
+
await this.extractArray(element, "", parsePath, options);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// info schleife
|
|
249
|
+
|
|
250
|
+
for (const key of Object.keys(element)) {
|
|
251
|
+
let fullPath = `${parsePath}.${key}`;
|
|
252
|
+
let value = element[key];
|
|
253
|
+
|
|
254
|
+
if (Array.isArray(value)) {
|
|
255
|
+
try {
|
|
256
|
+
if (!constant.noInfoDP.includes(key)) {
|
|
257
|
+
await this.extractArray(element, key, parsePath, options);
|
|
258
|
+
}
|
|
259
|
+
} catch (error) {
|
|
260
|
+
this.adapter.log.error(`extractArray ${error}`);
|
|
261
|
+
}
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const isObj = this.isObject(value);
|
|
266
|
+
|
|
267
|
+
if (isObj) {
|
|
268
|
+
if (Object.keys(value).length > 0) {
|
|
269
|
+
options.write = false;
|
|
270
|
+
await this.parse(fullPath, value, options);
|
|
271
|
+
}
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
switch (key) {
|
|
276
|
+
case "ready":
|
|
277
|
+
fullPath = fullPath.replace(".info.", ".");
|
|
278
|
+
break;
|
|
279
|
+
case "status":
|
|
280
|
+
fullPath = fullPath.replace(".info.", ".");
|
|
281
|
+
if (utils.isNumeric(value)) {
|
|
282
|
+
value = utils.getStatusText(value);
|
|
283
|
+
}
|
|
284
|
+
break;
|
|
285
|
+
default:
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (!this.alreadyCreatedObjects[fullPath]) {
|
|
290
|
+
const objectName = options.descriptions?.[key] || key;
|
|
291
|
+
let type = typeof value === "string" ? "mixed" : (value != null ? typeof value : "mixed");
|
|
292
|
+
|
|
293
|
+
if (constant.mixedType.includes(key)) {
|
|
294
|
+
type = "mixed";
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const common = {
|
|
298
|
+
id: objectName,
|
|
299
|
+
name: objectName,
|
|
300
|
+
role: this.getRole(value, options, key),
|
|
301
|
+
type,
|
|
302
|
+
write: options.write,
|
|
303
|
+
read: true,
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
await this.adapter.setObjectNotExistsAsync(fullPath, {
|
|
307
|
+
type: "state",
|
|
308
|
+
common,
|
|
309
|
+
native: { },
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
if (options.write === true) {
|
|
313
|
+
this.adapter.subscribeStates(fullPath);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
this.alreadyCreatedObjects[fullPath] = { };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
try {
|
|
320
|
+
if (value !== undefined) {
|
|
321
|
+
this.adapter.setState(fullPath, value, true);
|
|
322
|
+
}
|
|
323
|
+
} catch (err) {
|
|
324
|
+
this.adapter.log.warn(`ERROR ${value} ${JSON.stringify(err)}`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
*
|
|
332
|
+
* @param value
|
|
333
|
+
*/
|
|
334
|
+
isObject(value) {
|
|
335
|
+
return value !== null && typeof value === "object";
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
*
|
|
340
|
+
* @param element
|
|
341
|
+
* @param key
|
|
342
|
+
* @param path
|
|
343
|
+
* @param options
|
|
344
|
+
*/
|
|
345
|
+
async extractArray(element, key, path, options) {
|
|
346
|
+
try {
|
|
347
|
+
const array = key ? element[key] : element;
|
|
348
|
+
|
|
349
|
+
for (let i = 0; i < array.length; i++) {
|
|
350
|
+
const arrayElement = array[i];
|
|
351
|
+
const index = (i + 1).toString().padStart(2, "0");
|
|
352
|
+
|
|
353
|
+
if (typeof arrayElement === "string") {
|
|
354
|
+
if (key == undefined || key === "") {
|
|
355
|
+
key = arrayElement;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
await this.parse(
|
|
359
|
+
`${path}.${key}.${arrayElement}`,
|
|
360
|
+
arrayElement,
|
|
361
|
+
options,
|
|
362
|
+
);
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
await this.parse(`${path}.${key}`, arrayElement, options);
|
|
367
|
+
}
|
|
368
|
+
} catch (error) {
|
|
369
|
+
this.adapter.log.error(`Cannot extract array ${path}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
*
|
|
375
|
+
* @param element
|
|
376
|
+
* @param options
|
|
377
|
+
* @param dpName
|
|
378
|
+
*/
|
|
379
|
+
getRole(element, options, dpName) {
|
|
380
|
+
const write = options.write;
|
|
381
|
+
const hasStates =
|
|
382
|
+
element && typeof element === "object" && element.states !== undefined;
|
|
383
|
+
|
|
384
|
+
if (constant.timeKey.includes(dpName)) {
|
|
385
|
+
// check ob es sich um ein timestamp handelt
|
|
386
|
+
return "value.time";
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (typeof element === "boolean" && !write) {
|
|
390
|
+
return "indicator";
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (hasStates) {
|
|
394
|
+
if (element.type == "boolean") {
|
|
395
|
+
delete element.states;
|
|
396
|
+
return "button";
|
|
397
|
+
}
|
|
398
|
+
return "switch";
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (typeof element === "boolean" && !write) {
|
|
402
|
+
return "indicator";
|
|
403
|
+
}
|
|
404
|
+
if (typeof element === "boolean" && write) {
|
|
405
|
+
return "switch";
|
|
406
|
+
}
|
|
407
|
+
if (typeof element === "number" && !write) {
|
|
408
|
+
return "value";
|
|
409
|
+
}
|
|
410
|
+
if (typeof element === "number" && write) {
|
|
411
|
+
return "level";
|
|
412
|
+
}
|
|
413
|
+
if (typeof element === "string") {
|
|
414
|
+
return "text";
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return "state";
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
*
|
|
421
|
+
* @param element
|
|
422
|
+
*/
|
|
423
|
+
resolveCommandClassValue(element) {
|
|
424
|
+
const type = element.type;
|
|
425
|
+
|
|
426
|
+
if (type === "any" || type === "color") {
|
|
427
|
+
element.type = "mixed";
|
|
428
|
+
return typeof element.value === "object"
|
|
429
|
+
? JSON.stringify(element.value)
|
|
430
|
+
: element.value;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (type.includes("string")) {
|
|
434
|
+
element.type = "mixed";
|
|
435
|
+
if (element.writeable === false) {
|
|
436
|
+
let v = element.value ?? element.min ?? 0;
|
|
437
|
+
if (Array.isArray(v) && v.length) {
|
|
438
|
+
v = JSON.stringify(v);
|
|
439
|
+
}
|
|
440
|
+
return v;
|
|
441
|
+
}
|
|
442
|
+
return element.value ?? element.min ?? 0;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (type.includes("buffer")) {
|
|
446
|
+
element.type = "mixed";
|
|
447
|
+
if (element.writeable === false) {
|
|
448
|
+
let v = element.value ?? element.min ?? 0;
|
|
449
|
+
if (Array.isArray(v) && v.length) {
|
|
450
|
+
v = v[0];
|
|
451
|
+
}
|
|
452
|
+
return v;
|
|
453
|
+
}
|
|
454
|
+
return element.value ?? element.min ?? 0;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (type === "duration") {
|
|
458
|
+
element.type = "mixed";
|
|
459
|
+
let v = element.value ?? element.min ?? 0;
|
|
460
|
+
if (typeof v === "object") {
|
|
461
|
+
if (v?.unit) {
|
|
462
|
+
element.unit = v.unit;
|
|
463
|
+
}
|
|
464
|
+
v = 0;
|
|
465
|
+
}
|
|
466
|
+
return v;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (type === "number") {
|
|
470
|
+
if (element?.value) {
|
|
471
|
+
return utils.isNumeric(element.value) ? element.value : 0;
|
|
472
|
+
}
|
|
473
|
+
return element.value ?? element.min;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
return element.readable === false
|
|
477
|
+
? false
|
|
478
|
+
: (element.value ?? (type === "boolean" ? false : (element.min ?? 0)));
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
*
|
|
484
|
+
* @param nodeId
|
|
485
|
+
*/
|
|
486
|
+
async createReadyStatus(nodeId) {
|
|
487
|
+
// leg die status direkt auch an
|
|
488
|
+
let common = {
|
|
489
|
+
id: 'ready',
|
|
490
|
+
name: 'ready',
|
|
491
|
+
role: 'indicator',
|
|
492
|
+
type: 'boolean',
|
|
493
|
+
write: false,
|
|
494
|
+
read: true,
|
|
495
|
+
};
|
|
496
|
+
await this.adapter.setObjectNotExistsAsync(`${nodeId}.ready`, {
|
|
497
|
+
type: "state",
|
|
498
|
+
common,
|
|
499
|
+
native: {},
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
common = {
|
|
503
|
+
id: 'status',
|
|
504
|
+
name: 'status',
|
|
505
|
+
role: 'text',
|
|
506
|
+
type: 'mixed',
|
|
507
|
+
write: false,
|
|
508
|
+
read: true,
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
await this.adapter.setObjectNotExistsAsync(`${nodeId}.status`, {
|
|
512
|
+
type: "state",
|
|
513
|
+
common,
|
|
514
|
+
native: {},
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
*
|
|
519
|
+
* @param nodeId
|
|
520
|
+
* @param element
|
|
521
|
+
*/
|
|
522
|
+
async updateDevice(nodeId, element) {
|
|
523
|
+
const obj = await this.adapter.getObjectAsync(nodeId);
|
|
524
|
+
if (obj) {
|
|
525
|
+
const newName = element.name || element.productLabel || element.manufacturer || element.newValue;
|
|
526
|
+
|
|
527
|
+
if (obj.common?.name !== newName) {
|
|
528
|
+
obj.common = obj.common ?? {};
|
|
529
|
+
obj.common.name = newName;
|
|
530
|
+
|
|
531
|
+
await this.adapter.setObjectAsync(nodeId, obj);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
module.exports = {
|
|
539
|
+
Helper: Helper,
|
|
540
|
+
};
|
package/lib/messages.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @param config
|
|
4
|
+
* @param log
|
|
5
|
+
*/
|
|
6
|
+
async function adapterInfo(config, log) {
|
|
7
|
+
log.info(
|
|
8
|
+
"================================= Adapter Config =================================",
|
|
9
|
+
);
|
|
10
|
+
log.info(`|| zwaveWS Frontend Scheme: ${config.webUIScheme}`);
|
|
11
|
+
log.info(`|| zwaveWS Frontend Server: ${config.webUIServer}`);
|
|
12
|
+
log.info(`|| zwaveWS Frontend Port: ${config.webUIPort}`);
|
|
13
|
+
log.info(`|| zwaveWS Connection Type: ${config.connectionType}`);
|
|
14
|
+
if (config.connectionType == "ws") {
|
|
15
|
+
log.info(`|| zwaveWS Websocket Scheme: ${config.wsScheme}`);
|
|
16
|
+
log.info(`|| zwaveWS Websocket Server: ${config.wsServerIP}`);
|
|
17
|
+
log.info(`|| zwaveWS Websocket Port: ${config.wsServerPort}`);
|
|
18
|
+
log.info(
|
|
19
|
+
`|| zwaveWS Websocket Auth-Token: ${config.wsTokenEnabled ? "use" : "unused"}`,
|
|
20
|
+
);
|
|
21
|
+
log.info(
|
|
22
|
+
`|| zwaveWS Websocket Dummy MQTT-Server: ${config.dummyMqtt ? "activated" : "deactivated"}`,
|
|
23
|
+
);
|
|
24
|
+
if (config.dummyMqtt == true) {
|
|
25
|
+
log.info(`|| zwaveWS Dummy MQTT IP-Bind: ${config.mqttServerIPBind}`);
|
|
26
|
+
log.info(`|| zwaveWS Dummy MQTT Port: ${config.mqttServerPort}`);
|
|
27
|
+
}
|
|
28
|
+
} else if (config.connectionType == "exmqtt") {
|
|
29
|
+
log.info(
|
|
30
|
+
`|| zwaveWS Externanl MQTT Server: ${config.externalMqttServerIP}`,
|
|
31
|
+
);
|
|
32
|
+
log.info(
|
|
33
|
+
`|| zwaveWS Externanl MQTT Port: ${config.externalMqttServerPort}`,
|
|
34
|
+
);
|
|
35
|
+
log.info(
|
|
36
|
+
`|| zwaveWS Externanl MQTT Credentials: ${config.externalMqttServerCredentials ? "use" : "unused"}`,
|
|
37
|
+
);
|
|
38
|
+
} else if (config.connectionType == "intmqtt") {
|
|
39
|
+
log.info(`|| zwaveWS Internal MQTT IP-Bind: ${config.mqttServerIPBind}`);
|
|
40
|
+
log.info(`|| zwaveWS Internal MQTT Port: ${config.mqttServerPort}`);
|
|
41
|
+
}
|
|
42
|
+
log.info(
|
|
43
|
+
"==================================================================================",
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = {
|
|
48
|
+
adapterInfo,
|
|
49
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const core = require("@iobroker/adapter-core");
|
|
2
|
+
const Aedes = require("aedes");
|
|
3
|
+
const net = require("net");
|
|
4
|
+
let mqttServer;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
class MqttServerController {
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
* @param adapter
|
|
13
|
+
*/
|
|
14
|
+
constructor(adapter) {
|
|
15
|
+
this.adapter = adapter;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
async createMQTTServer() {
|
|
22
|
+
try {
|
|
23
|
+
const NedbPersistence = require("aedes-persistence-nedb");
|
|
24
|
+
const db = new NedbPersistence({
|
|
25
|
+
path: `${core.getAbsoluteInstanceDataDir(this.adapter)}/mqttData`,
|
|
26
|
+
prefix: "",
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const aedes = Aedes({ persistence: db });
|
|
30
|
+
mqttServer = net.createServer(aedes.handle);
|
|
31
|
+
mqttServer.listen(
|
|
32
|
+
this.adapter.config.mqttServerPort,
|
|
33
|
+
this.adapter.config.mqttServerIPBind,
|
|
34
|
+
() => {
|
|
35
|
+
this.adapter.log.info(
|
|
36
|
+
`Statring MQTT-Server on IP ${this.adapter.config.mqttServerIPBind} and Port ${this.adapter.config.mqttServerPort}`,
|
|
37
|
+
);
|
|
38
|
+
},
|
|
39
|
+
);
|
|
40
|
+
} catch (err) {
|
|
41
|
+
this.adapter.log.error(err);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
*
|
|
47
|
+
*/
|
|
48
|
+
async createDummyMQTTServer() {
|
|
49
|
+
try {
|
|
50
|
+
const aedes = Aedes();
|
|
51
|
+
mqttServer = net.createServer(aedes.handle);
|
|
52
|
+
mqttServer.listen(
|
|
53
|
+
this.adapter.config.mqttServerPort,
|
|
54
|
+
this.adapter.config.mqttServerIPBind,
|
|
55
|
+
() => {
|
|
56
|
+
this.adapter.log.info(
|
|
57
|
+
`Statring DummyMQTT-Server on IP ${this.adapter.config.mqttServerIPBind} and Port ${this.adapter.config.mqttServerPort}`,
|
|
58
|
+
);
|
|
59
|
+
},
|
|
60
|
+
);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
this.adapter.log.error(err);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
*
|
|
68
|
+
*/
|
|
69
|
+
closeServer() {
|
|
70
|
+
if (mqttServer && !mqttServer.closed()) {
|
|
71
|
+
mqttServer.close();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = {
|
|
77
|
+
MqttServerController,
|
|
78
|
+
};
|