node-red-contrib-knx-ultimate 3.2.0 → 3.2.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/CHANGELOG.md +7 -1
- package/nodes/commonFunctions.js +0 -1
- package/nodes/hue-config.js +12 -6
- package/nodes/knxUltimate-config copy.html +456 -0
- package/nodes/knxUltimate-config copy.js +1939 -0
- package/nodes/knxUltimate-config.html +4 -9
- package/nodes/knxUltimate-config.js +128 -213
- package/nodes/knxUltimate.js +41 -32
- package/nodes/knxUltimateAlerter.js +11 -15
- package/nodes/knxUltimateAutoResponder.js +21 -13
- package/nodes/knxUltimateGarageDoorBarrierOpener.js +16 -8
- package/nodes/knxUltimateGlobalContext.js +10 -10
- package/nodes/knxUltimateHueBattery.js +8 -8
- package/nodes/knxUltimateHueButton.js +9 -9
- package/nodes/knxUltimateHueContactSensor.js +7 -7
- package/nodes/knxUltimateHueLight.js +26 -26
- package/nodes/knxUltimateHueLightSensor.js +8 -8
- package/nodes/knxUltimateHueMotion.js +7 -7
- package/nodes/knxUltimateHueScene.js +17 -9
- package/nodes/knxUltimateHueTapDial.js +13 -13
- package/nodes/knxUltimateHueTemperatureSensor.js +8 -8
- package/nodes/knxUltimateHueZigbeeConnectivity.js +8 -8
- package/nodes/knxUltimateHuedevice_software_update.js +8 -8
- package/nodes/knxUltimateLoadControl.js +24 -21
- package/nodes/knxUltimateLogger.js +8 -8
- package/nodes/knxUltimateSceneController.js +20 -13
- package/nodes/knxUltimateViewer.js +8 -8
- package/nodes/knxUltimateWatchDog.js +14 -14
- package/nodes/utils/http.js +0 -1
- package/nodes/utils/hueEngine.js +13 -6
- package/nodes/utils/payloadManipulation.js +2 -2
- package/nodes/utils/sysLogger.js +23 -60
- package/package.json +3 -3
package/nodes/knxUltimate.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
|
|
2
|
+
// 10/09/2024 Setup the color logger
|
|
3
|
+
loggerSetup = (options) => {
|
|
4
|
+
let clog = require("node-color-log").createNamedLogger(options.setPrefix);
|
|
5
|
+
clog.setLevel(options.loglevel);
|
|
6
|
+
clog.setDate(() => (new Date()).toLocaleString());
|
|
7
|
+
return clog;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
|
|
2
11
|
/* eslint-disable max-len */
|
|
3
12
|
module.exports = function (RED) {
|
|
4
13
|
const _ = require('lodash');
|
|
@@ -9,9 +18,9 @@ module.exports = function (RED) {
|
|
|
9
18
|
function knxUltimate(config) {
|
|
10
19
|
RED.nodes.createNode(this, config);
|
|
11
20
|
const node = this;
|
|
12
|
-
node.
|
|
21
|
+
node.serverKNX = RED.nodes.getNode(config.server);
|
|
13
22
|
// 11/11/2021 Is the node server disabled by the flow "disable" command?
|
|
14
|
-
if (node.
|
|
23
|
+
if (node.serverKNX === null) {
|
|
15
24
|
node.status({ fill: 'red', shape: 'dot', text: '[THE GATEWAY NODE HAS BEEN DISABLED]' });
|
|
16
25
|
return;
|
|
17
26
|
}
|
|
@@ -21,7 +30,7 @@ module.exports = function (RED) {
|
|
|
21
30
|
fill, shape, text, payload, GA, dpt, devicename,
|
|
22
31
|
}) => {
|
|
23
32
|
try {
|
|
24
|
-
if (node.
|
|
33
|
+
if (node.serverKNX === null) { node.status({ fill: 'red', shape: 'dot', text: '[NO GATEWAY SELECTED]' }); return; }
|
|
25
34
|
if (node.icountMessageInWindow == -999) return; // Locked out, doesn't change status.
|
|
26
35
|
const dDate = new Date();
|
|
27
36
|
// 30/08/2019 Display only the things selected in the config
|
|
@@ -32,11 +41,11 @@ module.exports = function (RED) {
|
|
|
32
41
|
node.status({ fill, shape, text: `${GA + payload + (node.listenallga === true ? ` ${devicename}` : '')} (${dDate.getDate()}, ${dDate.toLocaleTimeString()} ${text}` });
|
|
33
42
|
// 16/02/2020 signal errors to the server
|
|
34
43
|
if (fill.toUpperCase() === 'RED') {
|
|
35
|
-
if (node.
|
|
44
|
+
if (node.serverKNX) {
|
|
36
45
|
const oError = {
|
|
37
46
|
nodeid: node.id, topic: node.outputtopic, devicename, GA, text,
|
|
38
47
|
};
|
|
39
|
-
node.
|
|
48
|
+
node.serverKNX.reportToWatchdogCalledByKNXUltimateNode(oError);
|
|
40
49
|
}
|
|
41
50
|
}
|
|
42
51
|
// Validate the Address to advise the user. The address can be undefined, because the
|
|
@@ -119,7 +128,7 @@ module.exports = function (RED) {
|
|
|
119
128
|
node.passthrough = (typeof config.passthrough === 'undefined' ? 'no' : config.passthrough);
|
|
120
129
|
node.inputmessage = {}; // Stores the input message to be passed through
|
|
121
130
|
node.timerTTLInputMessage = null; // The stored node.inputmessage has a ttl.
|
|
122
|
-
node.sysLogger =
|
|
131
|
+
node.sysLogger = loggerSetup({ loglevel: node.serverKNX.loglevel, setPrefix: "knxUltimate.js" }); // 08/04/2021 new logger to adhere to the loglevel selected in the config-window
|
|
123
132
|
node.sendMsgToKNXCode = config.sendMsgToKNXCode || undefined;
|
|
124
133
|
node.receiveMsgFromKNXCode = config.receiveMsgFromKNXCode || undefined;
|
|
125
134
|
if (node.sendMsgToKNXCode === '') node.sendMsgToKNXCode = undefined
|
|
@@ -144,7 +153,7 @@ module.exports = function (RED) {
|
|
|
144
153
|
const blankSpacePosition = _ga.indexOf(" ");
|
|
145
154
|
if (blankSpacePosition > -1) _ga = _ga.substring(0, blankSpacePosition);
|
|
146
155
|
// Is there a GA in the server's exposedGAs?
|
|
147
|
-
const found = node.
|
|
156
|
+
const found = node.serverKNX.exposedGAs.find(a => a.ga === _ga);
|
|
148
157
|
if (found !== undefined) {
|
|
149
158
|
if (_dpt === undefined && found.dpt === undefined) {
|
|
150
159
|
const errM = 'knxUltimate: getGaValue: node ID:' + node.id + ' ' + 'No CSV file imported. Please provide the dpt manually';
|
|
@@ -175,7 +184,7 @@ module.exports = function (RED) {
|
|
|
175
184
|
if (blankSpacePosition > -1) _ga = _ga.substring(0, blankSpacePosition);
|
|
176
185
|
if (_dpt === undefined) {
|
|
177
186
|
// Try getting dpt from ETS CSV
|
|
178
|
-
const found = node.
|
|
187
|
+
const found = node.serverKNX.exposedGAs.find(a => a.ga === _ga);
|
|
179
188
|
if (found === undefined || found.dpt === undefined) {
|
|
180
189
|
const errM = 'knxUltimate: setGAValue: node ID:' + node.id + ' ' + 'No CSV file imported. Please provide the dpt manually';
|
|
181
190
|
RED.log.error(errM);
|
|
@@ -183,7 +192,7 @@ module.exports = function (RED) {
|
|
|
183
192
|
return;
|
|
184
193
|
}
|
|
185
194
|
}
|
|
186
|
-
node.
|
|
195
|
+
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
187
196
|
grpaddr: _ga, payload: _value, dpt: _dpt, outputtype: 'write', nodecallerid: node.id,
|
|
188
197
|
});
|
|
189
198
|
} catch (error) {
|
|
@@ -195,7 +204,7 @@ module.exports = function (RED) {
|
|
|
195
204
|
// Used in the KNX Function TAB
|
|
196
205
|
let self = function self(_value) {
|
|
197
206
|
try {
|
|
198
|
-
node.
|
|
207
|
+
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
199
208
|
grpaddr: node.topic, payload: _value, dpt: node.dpt, outputtype: 'write', nodecallerid: node.id,
|
|
200
209
|
});
|
|
201
210
|
} catch (error) {
|
|
@@ -208,7 +217,7 @@ module.exports = function (RED) {
|
|
|
208
217
|
let toggle = function toggle() {
|
|
209
218
|
if (node.currentPayload === true || node.currentPayload === false) {
|
|
210
219
|
try {
|
|
211
|
-
node.
|
|
220
|
+
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
212
221
|
grpaddr: node.topic, payload: !node.currentPayload, dpt: node.dpt, outputtype: 'write', nodecallerid: node.id,
|
|
213
222
|
});
|
|
214
223
|
} catch (error) {
|
|
@@ -257,7 +266,7 @@ module.exports = function (RED) {
|
|
|
257
266
|
|
|
258
267
|
node.on('input', (msg) => {
|
|
259
268
|
if (typeof msg === 'undefined') return;
|
|
260
|
-
if (!node.
|
|
269
|
+
if (!node.serverKNX) return; // 29/08/2019 Server not instantiate
|
|
261
270
|
|
|
262
271
|
// 11/01/2021 Accept properties change from msg
|
|
263
272
|
// *********************************
|
|
@@ -339,7 +348,7 @@ module.exports = function (RED) {
|
|
|
339
348
|
node.setNodeStatus({
|
|
340
349
|
fill: 'grey', shape: 'dot', text: 'Read', payload: '', GA: grpaddr, dpt: '', devicename: '',
|
|
341
350
|
});
|
|
342
|
-
node.
|
|
351
|
+
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
343
352
|
grpaddr, payload: '', dpt: '', outputtype: 'read', nodecallerid: node.id,
|
|
344
353
|
});
|
|
345
354
|
} else { // Listen all GAs
|
|
@@ -358,16 +367,16 @@ module.exports = function (RED) {
|
|
|
358
367
|
return;
|
|
359
368
|
}
|
|
360
369
|
}
|
|
361
|
-
node.
|
|
370
|
+
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
362
371
|
grpaddr, payload: '', dpt: '', outputtype: 'read', nodecallerid: node.id,
|
|
363
372
|
});
|
|
364
373
|
} else {
|
|
365
374
|
// Issue read to all group addresses
|
|
366
375
|
// 25/10/2019 the user is able not import the csv, so i need to check for it. This option should be unckecked by the knxUltimate html config, but..
|
|
367
|
-
if (typeof node.
|
|
376
|
+
if (typeof node.serverKNX.csv !== 'undefined') {
|
|
368
377
|
let delay = 0;
|
|
369
|
-
for (let index = 0; index < node.
|
|
370
|
-
const element = node.
|
|
378
|
+
for (let index = 0; index < node.serverKNX.csv.length; index++) {
|
|
379
|
+
const element = node.serverKNX.csv[index];
|
|
371
380
|
const grpaddr = element.ga;
|
|
372
381
|
// 29/12/2020 Protection over circular references (for example, if you link two Ultimate Nodes toghether with the same group address), to prevent infinite loops
|
|
373
382
|
if (msg.hasOwnProperty('knx')) {
|
|
@@ -378,7 +387,7 @@ module.exports = function (RED) {
|
|
|
378
387
|
});
|
|
379
388
|
}
|
|
380
389
|
} else {
|
|
381
|
-
node.
|
|
390
|
+
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
382
391
|
grpaddr, payload: '', dpt: '', outputtype: 'read', nodecallerid: node.id,
|
|
383
392
|
});
|
|
384
393
|
const t = setTimeout(() => { // 21/03/2022 fixed possible memory leak. Previously was setTimeout without "let t = ".
|
|
@@ -437,7 +446,7 @@ module.exports = function (RED) {
|
|
|
437
446
|
node.icountMessageInWindow += 1;
|
|
438
447
|
|
|
439
448
|
// OUTPUT: Send message to the bus (write/response)
|
|
440
|
-
if (node.
|
|
449
|
+
if (node.serverKNX.knxConnection) {
|
|
441
450
|
let { outputtype } = node;
|
|
442
451
|
let grpaddr = '';
|
|
443
452
|
let dpt = '';
|
|
@@ -465,8 +474,8 @@ module.exports = function (RED) {
|
|
|
465
474
|
// No datapoint set. If the CSV is loaded, try to get it from there.
|
|
466
475
|
if (!msg.hasOwnProperty('writeraw')) { // In raw mode, Datapoint is useless
|
|
467
476
|
// Get the datapoint from the CSV
|
|
468
|
-
if (typeof node.
|
|
469
|
-
const oGA = node.
|
|
477
|
+
if (typeof node.serverKNX.csv !== 'undefined') {
|
|
478
|
+
const oGA = node.serverKNX.csv.filter((sga) => sga.ga == grpaddr)[0];
|
|
470
479
|
if (oGA !== undefined) {
|
|
471
480
|
dpt = oGA.dpt;
|
|
472
481
|
} else {
|
|
@@ -513,9 +522,9 @@ module.exports = function (RED) {
|
|
|
513
522
|
if (msg.hasOwnProperty('writeraw') && msg.hasOwnProperty('writeraw') !== null) {
|
|
514
523
|
try {
|
|
515
524
|
if (msg.hasOwnProperty('bitlenght') && msg.bitlenght !== null) {
|
|
516
|
-
node.
|
|
525
|
+
node.serverKNX.knxConnection.writeRaw(grpaddr, msg.writeraw, msg.bitlenght);
|
|
517
526
|
} else {
|
|
518
|
-
node.
|
|
527
|
+
node.serverKNX.knxConnection.writeRaw(grpaddr, msg.writeraw);
|
|
519
528
|
}
|
|
520
529
|
node.setNodeStatus({
|
|
521
530
|
fill: 'green', shape: 'dot', text: 'RAW Write', payload: '', GA: grpaddr, dpt: '', devicename: '',
|
|
@@ -531,7 +540,7 @@ module.exports = function (RED) {
|
|
|
531
540
|
if (outputtype == 'response') {
|
|
532
541
|
try {
|
|
533
542
|
node.currentPayload = msg.payload;// 31/12/2019 Set the current value (because, if the node is a virtual device, then it'll never fire "GroupValue_Write" in the server node, causing the currentPayload to never update)
|
|
534
|
-
node.
|
|
543
|
+
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
535
544
|
grpaddr, payload: msg.payload, dpt, outputtype, nodecallerid: node.id,
|
|
536
545
|
});
|
|
537
546
|
node.setNodeStatus({
|
|
@@ -542,7 +551,7 @@ module.exports = function (RED) {
|
|
|
542
551
|
// 05/01/2021 Updates only the internal currentPayload value.
|
|
543
552
|
try {
|
|
544
553
|
node.currentPayload = msg.payload;
|
|
545
|
-
node.
|
|
554
|
+
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
546
555
|
grpaddr, payload: msg.payload, dpt, outputtype, nodecallerid: node.id,
|
|
547
556
|
});
|
|
548
557
|
node.setNodeStatus({
|
|
@@ -552,8 +561,8 @@ module.exports = function (RED) {
|
|
|
552
561
|
} else {
|
|
553
562
|
try {
|
|
554
563
|
node.currentPayload = msg.payload;// 31/12/2019 Set the current value (because, if the node is a virtual device, then it'll never fire "GroupValue_Write" in the server node, causing the currentPayload to never update)
|
|
555
|
-
// if (node.
|
|
556
|
-
node.
|
|
564
|
+
// if (node.serverKNX.linkStatus === "connected") {
|
|
565
|
+
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
557
566
|
grpaddr, payload: msg.payload, dpt, outputtype, nodecallerid: node.id,
|
|
558
567
|
});
|
|
559
568
|
node.setNodeStatus({
|
|
@@ -571,8 +580,8 @@ module.exports = function (RED) {
|
|
|
571
580
|
node.on('close', (done) => {
|
|
572
581
|
if (node.timerTTLInputMessage !== null) clearTimeout(node.timerTTLInputMessage);
|
|
573
582
|
node.inputmessage = {};
|
|
574
|
-
if (node.
|
|
575
|
-
node.
|
|
583
|
+
if (node.serverKNX) {
|
|
584
|
+
node.serverKNX.removeClient(node);
|
|
576
585
|
try {
|
|
577
586
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info(`knxUltimate: Close: node id ${node.id} with topic ${node.topic || ''} has been removed from the server.`);
|
|
578
587
|
} catch (error) { }
|
|
@@ -581,15 +590,15 @@ module.exports = function (RED) {
|
|
|
581
590
|
});
|
|
582
591
|
|
|
583
592
|
// On each deploy, add the node to the server list
|
|
584
|
-
if (node.
|
|
585
|
-
node.
|
|
593
|
+
if (node.serverKNX) {
|
|
594
|
+
node.serverKNX.addClient(node);
|
|
586
595
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info(`knxUltimate: addClient: node id ${node.id}` || '' + ` with topic ${node.topic || ''} has been added to the server.`);
|
|
587
596
|
// 05/11/2021 if the node is set to read from bus, issue a read.
|
|
588
597
|
// "node-input-initialread0": "No",
|
|
589
598
|
// "node-input-initialread1": "Leggi dal BUS KNX",
|
|
590
599
|
// "node-input-initialread2": "Leggi l'ultimo valore salvato su file prima della disconnessione.",
|
|
591
600
|
// "node-input-initialread3": "Leggi l'ultimo valore salvato su file prima della disconnessione. Se inesistente, leggi dal BUS KNX",
|
|
592
|
-
if (node.
|
|
601
|
+
if (node.serverKNX.linkStatus === 'connected' && node.initialread === 1 || node.initialread === 3) {
|
|
593
602
|
node.setNodeStatus({
|
|
594
603
|
fill: 'yellow', shape: 'dot', text: 'Get value from BUS.', payload: '', GA: node.topic || '', dpt: '', devicename: '',
|
|
595
604
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
|
|
2
|
+
|
|
2
3
|
module.exports = function (RED) {
|
|
3
4
|
function knxUltimateAlerter(config) {
|
|
4
5
|
const fs = require('fs');
|
|
@@ -9,7 +10,7 @@ module.exports = function (RED) {
|
|
|
9
10
|
|
|
10
11
|
RED.nodes.createNode(this, config);
|
|
11
12
|
const node = this;
|
|
12
|
-
node.
|
|
13
|
+
node.serverKNX = RED.nodes.getNode(config.server);
|
|
13
14
|
node.name = config.name || 'KNX Alerter';
|
|
14
15
|
node.listenallga = true; // Dont' remove this.
|
|
15
16
|
node.notifyreadrequest = false;
|
|
@@ -27,22 +28,17 @@ module.exports = function (RED) {
|
|
|
27
28
|
node.timerSend = null;
|
|
28
29
|
node.whentostart = config.whentostart === undefined ? 'ifnewalert' : config.whentostart;
|
|
29
30
|
node.timerinterval = (config.timerinterval === undefined || config.timerinterval == '') ? '2' : config.timerinterval;
|
|
31
|
+
|
|
30
32
|
if (config.initialreadGAInRules === undefined) {
|
|
31
33
|
node.initialread = true;
|
|
32
34
|
} else {
|
|
33
35
|
node.initialread = config.initialreadGAInRules !== '0';
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
try {
|
|
37
|
-
node.sysLogger = require('./utils/sysLogger.js').get({ loglevel: node.server.loglevel || 'error' }); // 08/04/2021 new logger to adhere to the loglevel selected in the config-window
|
|
38
|
-
} catch (error) {
|
|
39
|
-
node.sysLogger = 'error';
|
|
40
|
-
}
|
|
41
|
-
|
|
42
38
|
// Used to call the status update from the config node.
|
|
43
39
|
node.setNodeStatus = ({ fill, shape, text, payload, GA, dpt, devicename }) => {
|
|
44
40
|
try {
|
|
45
|
-
if (node.
|
|
41
|
+
if (node.serverKNX === null) return;
|
|
46
42
|
// Log only service statuses, not the GA values
|
|
47
43
|
if (dpt !== undefined) return;
|
|
48
44
|
if (dpt !== '') return;
|
|
@@ -159,7 +155,7 @@ module.exports = function (RED) {
|
|
|
159
155
|
|
|
160
156
|
// 24/04/2021 perform a read on all GA in the rule list. Called both from node.on("input") and knxUltimate-config
|
|
161
157
|
node.initialReadAllDevicesInRules = () => {
|
|
162
|
-
if (node.
|
|
158
|
+
if (node.serverKNX) {
|
|
163
159
|
let grpaddr = '';
|
|
164
160
|
for (let i = 0; i < node.rules.length; i++) {
|
|
165
161
|
// rule is { topic: rowRuleTopic, devicename: rowRuleDeviceName, longdevicename: rowRuleLongDeviceName}
|
|
@@ -170,7 +166,7 @@ module.exports = function (RED) {
|
|
|
170
166
|
// Check if it's a group address
|
|
171
167
|
// const ret = Address.KNXAddress.createFromString(grpaddr, Address.KNXAddress.TYPE_GROUP)
|
|
172
168
|
node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'Read', payload: '', GA: grpaddr, dpt: '', devicename: rule.devicename });
|
|
173
|
-
node.
|
|
169
|
+
node.serverKNX.sendKNXTelegramToKNXEngine({ grpaddr, payload: '', dpt: '', outputtype: 'read', nodecallerid: node.id });
|
|
174
170
|
} catch (error) {
|
|
175
171
|
node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'Not a KNX GA ' + error.message, payload: '', GA: grpaddr, dpt: '', devicename: rule.devicename });
|
|
176
172
|
}
|
|
@@ -216,8 +212,8 @@ module.exports = function (RED) {
|
|
|
216
212
|
|
|
217
213
|
node.on('close', function (done) {
|
|
218
214
|
clearTimeout(node.timerSend);
|
|
219
|
-
if (node.
|
|
220
|
-
node.
|
|
215
|
+
if (node.serverKNX) {
|
|
216
|
+
node.serverKNX.removeClient(node);
|
|
221
217
|
}
|
|
222
218
|
done();
|
|
223
219
|
});
|
|
@@ -276,10 +272,10 @@ module.exports = function (RED) {
|
|
|
276
272
|
node.sendNoMoreDevices();
|
|
277
273
|
|
|
278
274
|
// On each deploy, unsubscribe+resubscribe
|
|
279
|
-
if (node.
|
|
280
|
-
node.
|
|
275
|
+
if (node.serverKNX) {
|
|
276
|
+
node.serverKNX.removeClient(node);
|
|
281
277
|
if (node.topic !== '' || node.topicSave !== '') {
|
|
282
|
-
node.
|
|
278
|
+
node.serverKNX.addClient(node);
|
|
283
279
|
}
|
|
284
280
|
}
|
|
285
281
|
}
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
// 10/09/2024 Setup the color logger
|
|
2
|
+
loggerSetup = (options) => {
|
|
3
|
+
let clog = require("node-color-log").createNamedLogger(options.setPrefix);
|
|
4
|
+
clog.setLevel(options.loglevel);
|
|
5
|
+
clog.setDate(() => (new Date()).toLocaleString());
|
|
6
|
+
return clog;
|
|
7
|
+
}
|
|
8
|
+
|
|
1
9
|
module.exports = function (RED) {
|
|
2
10
|
const dptlib = require('knxultimate').dptlib;
|
|
3
11
|
const fs = require("fs");
|
|
@@ -33,7 +41,7 @@ module.exports = function (RED) {
|
|
|
33
41
|
function knxUltimateAutoResponder(config) {
|
|
34
42
|
RED.nodes.createNode(this, config)
|
|
35
43
|
const node = this
|
|
36
|
-
node.
|
|
44
|
+
node.serverKNX = RED.nodes.getNode(config.server)
|
|
37
45
|
node.topic = node.name
|
|
38
46
|
node.name = config.name === undefined ? 'Auto responder' : config.name
|
|
39
47
|
node.outputtopic = node.name
|
|
@@ -48,12 +56,12 @@ module.exports = function (RED) {
|
|
|
48
56
|
node.inputRBE = 'false' // Apply or not RBE to the input (Messages coming from BUS)
|
|
49
57
|
node.exposedGAs = [];
|
|
50
58
|
node.commandText = []; // Raw list Respond To
|
|
51
|
-
node.sysLogger =
|
|
59
|
+
node.sysLogger = loggerSetup({ loglevel: node.serverKNX.loglevel, setPrefix: "knxUltimateAutoResponder.js" }); // 08/04/2021 new logger to adhere to the loglevel selected in the config-window
|
|
52
60
|
|
|
53
61
|
// Used to call the status update from the config node.
|
|
54
62
|
node.setNodeStatus = ({ fill, shape, text, payload, GA, dpt, devicename }) => {
|
|
55
63
|
// try {
|
|
56
|
-
// if (node.
|
|
64
|
+
// if (node.serverKNX === null) { node.status({ fill: 'red', shape: 'dot', text: '[NO GATEWAY SELECTED]' }); return }
|
|
57
65
|
// GA = GA === undefined ? '' : GA
|
|
58
66
|
// payload = payload === undefined ? '' : payload
|
|
59
67
|
// payload = typeof payload === 'object' ? JSON.stringify(payload) : payload
|
|
@@ -64,7 +72,7 @@ module.exports = function (RED) {
|
|
|
64
72
|
}
|
|
65
73
|
|
|
66
74
|
node.saveExposedGAs = () => {
|
|
67
|
-
const sFile = path.join(node.
|
|
75
|
+
const sFile = path.join(node.serverKNX.userDir, "knxpersistvalues", "knxpersist" + node.id + ".json");
|
|
68
76
|
try {
|
|
69
77
|
if (node.exposedGAs.length > 0) {
|
|
70
78
|
fs.writeFileSync(sFile, JSON.stringify(node.exposedGAs));
|
|
@@ -75,7 +83,7 @@ module.exports = function (RED) {
|
|
|
75
83
|
}
|
|
76
84
|
}
|
|
77
85
|
node.loadExposedGAs = () => {
|
|
78
|
-
const sFile = path.join(node.
|
|
86
|
+
const sFile = path.join(node.serverKNX.userDir, "knxpersistvalues", "knxpersist" + node.id + ".json");
|
|
79
87
|
try {
|
|
80
88
|
node.exposedGAs = JSON.parse(fs.readFileSync(sFile, "utf8"));
|
|
81
89
|
} catch (err) {
|
|
@@ -96,11 +104,11 @@ module.exports = function (RED) {
|
|
|
96
104
|
|
|
97
105
|
|
|
98
106
|
// Add the ETS CSV file list to exposedGAs
|
|
99
|
-
if (node.
|
|
107
|
+
if (node.serverKNX.csv === undefined || node.serverKNX.csv === '' || node.serverKNX.csv.length === 0) {
|
|
100
108
|
node.status({ fill: 'grey', shape: 'ring', text: 'No ETS file imported', payload: '', dpt: '', devicename: '' });
|
|
101
109
|
//return;
|
|
102
110
|
} else {
|
|
103
|
-
node.
|
|
111
|
+
node.serverKNX.csv.forEach(element => {
|
|
104
112
|
const curGa = node.exposedGAs.find(a => a.address === element.ga);
|
|
105
113
|
if (curGa === undefined) {
|
|
106
114
|
node.exposedGAs.push({ address: element.ga, dpt: element.dpt, default: undefined, payload: undefined, enabled: false }); // "enabled" will be used to filter only the node.commandText directiver
|
|
@@ -198,7 +206,7 @@ module.exports = function (RED) {
|
|
|
198
206
|
if (retVal !== undefined) {
|
|
199
207
|
const dDate = new Date()
|
|
200
208
|
if (oFoundGA.address !== undefined && oFoundGA.dpt !== undefined && retVal !== undefined) {
|
|
201
|
-
node.
|
|
209
|
+
node.serverKNX.sendKNXTelegramToKNXEngine({ grpaddr: oFoundGA.address, payload: retVal, dpt: oFoundGA.dpt, outputtype: 'response', nodecallerid: node.id });
|
|
202
210
|
node.status({ fill: 'blue', shape: 'dot', text: 'Respond ' + oFoundGA.address + ' => ' + retVal + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ')' })
|
|
203
211
|
} else {
|
|
204
212
|
node.status({ fill: 'yellow', shape: 'ring', text: 'Issue responding ' + oFoundGA.address + ' => ' + retVal + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ')' })
|
|
@@ -221,16 +229,16 @@ module.exports = function (RED) {
|
|
|
221
229
|
}
|
|
222
230
|
|
|
223
231
|
node.exposedGAs = [];
|
|
224
|
-
if (node.
|
|
225
|
-
node.
|
|
232
|
+
if (node.serverKNX) {
|
|
233
|
+
node.serverKNX.removeClient(node)
|
|
226
234
|
}
|
|
227
235
|
done()
|
|
228
236
|
})
|
|
229
237
|
|
|
230
238
|
// On each deploy, unsubscribe+resubscribe
|
|
231
|
-
if (node.
|
|
232
|
-
node.
|
|
233
|
-
node.
|
|
239
|
+
if (node.serverKNX) {
|
|
240
|
+
node.serverKNX.removeClient(node)
|
|
241
|
+
node.serverKNX.addClient(node)
|
|
234
242
|
}
|
|
235
243
|
}
|
|
236
244
|
RED.nodes.registerType('knxUltimateAutoResponder', knxUltimateAutoResponder)
|
|
@@ -4,14 +4,22 @@ const _ = require('lodash');
|
|
|
4
4
|
const KNXUtils = require('knxultimate').KNXUtils;
|
|
5
5
|
const payloadRounder = require('./utils/payloadManipulation');
|
|
6
6
|
|
|
7
|
+
// 10/09/2024 Setup the color logger
|
|
8
|
+
loggerSetup = (options) => {
|
|
9
|
+
let clog = require("node-color-log").createNamedLogger(options.setPrefix);
|
|
10
|
+
clog.setLevel(options.loglevel);
|
|
11
|
+
clog.setDate(() => (new Date()).toLocaleString());
|
|
12
|
+
return clog;
|
|
13
|
+
}
|
|
14
|
+
|
|
7
15
|
module.exports = function (RED) {
|
|
8
16
|
|
|
9
17
|
function knxUltimateGarageDoorBarrierOpener(config) {
|
|
10
18
|
RED.nodes.createNode(this, config);
|
|
11
19
|
const node = this;
|
|
12
|
-
node.
|
|
20
|
+
node.serverKNX = RED.nodes.getNode(config.server);
|
|
13
21
|
// 11/11/2021 Is the node server disabled by the flow "disable" command?
|
|
14
|
-
if (node.
|
|
22
|
+
if (node.serverKNX === null) {
|
|
15
23
|
node.status({ fill: 'red', shape: 'dot', text: '[THE GATEWAY NODE HAS BEEN DISABLED]' });
|
|
16
24
|
return;
|
|
17
25
|
}
|
|
@@ -26,7 +34,7 @@ module.exports = function (RED) {
|
|
|
26
34
|
node.initialread = false;
|
|
27
35
|
node.listenallga = true; // Don't remove
|
|
28
36
|
node.outputtype = 'write';
|
|
29
|
-
node.sysLogger =
|
|
37
|
+
node.sysLogger = loggerSetup({ loglevel: node.serverKNX.loglevel, setPrefix: "knxUltimateGarageDoorOpener.js" }); // 08/04/2021 new logger to adhere to the loglevel selected in the config-window
|
|
30
38
|
|
|
31
39
|
// From KNX to the node
|
|
32
40
|
node.GACommand = config.GACommand === undefined ? "" : config.GACommand;
|
|
@@ -70,7 +78,7 @@ module.exports = function (RED) {
|
|
|
70
78
|
fill, shape, text, payload, GA, dpt, devicename,
|
|
71
79
|
}) => {
|
|
72
80
|
try {
|
|
73
|
-
if (node.
|
|
81
|
+
if (node.serverKNX === null) { node.status({ fill: 'red', shape: 'dot', text: '[NO GATEWAY SELECTED]' }); return; }
|
|
74
82
|
const dDate = new Date();
|
|
75
83
|
// 30/08/2019 Display only the things selected in the config
|
|
76
84
|
GA = (typeof GA === 'undefined' || GA === '') ? '' : `(${GA}) `;
|
|
@@ -97,7 +105,7 @@ module.exports = function (RED) {
|
|
|
97
105
|
node.setNodeStatus({
|
|
98
106
|
fill: 'yellow', shape: 'dot', text: status, payload: '',
|
|
99
107
|
});
|
|
100
|
-
node.
|
|
108
|
+
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
101
109
|
grpaddr: node.GAImpulse, payload: true, dpt: '1.001', outputtype: 'write', nodecallerid: node.id
|
|
102
110
|
});
|
|
103
111
|
if (node.timerMovement !== null) clearTimeout(node.timerMovement);
|
|
@@ -127,12 +135,12 @@ module.exports = function (RED) {
|
|
|
127
135
|
|
|
128
136
|
node.on('input', (msg) => {
|
|
129
137
|
if (typeof msg === 'undefined') return;
|
|
130
|
-
if (!node.
|
|
138
|
+
if (!node.serverKNX) return; // 29/08/2019 Server not instantiate
|
|
131
139
|
});
|
|
132
140
|
|
|
133
141
|
node.on('close', (done) => {
|
|
134
|
-
if (node.
|
|
135
|
-
node.
|
|
142
|
+
if (node.serverKNX) {
|
|
143
|
+
node.serverKNX.removeClient(node);
|
|
136
144
|
try {
|
|
137
145
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info(`knxUltimateGarageDoorBarrierOpener: Close: node id ${node.id} with topic ${node.topic || ''} has been removed from the server.`);
|
|
138
146
|
} catch (error) { }
|
|
@@ -29,7 +29,7 @@ module.exports = function (RED) {
|
|
|
29
29
|
function knxUltimateGlobalContext(config) {
|
|
30
30
|
RED.nodes.createNode(this, config)
|
|
31
31
|
const node = this
|
|
32
|
-
node.
|
|
32
|
+
node.serverKNX = RED.nodes.getNode(config.server)
|
|
33
33
|
node.topic = node.name
|
|
34
34
|
node.name = config.name === undefined ? 'KNXGlobalContext' : config.name
|
|
35
35
|
node.outputtopic = node.name
|
|
@@ -58,7 +58,7 @@ module.exports = function (RED) {
|
|
|
58
58
|
// Used to call the status update from the config node.
|
|
59
59
|
node.setNodeStatus = ({ fill, shape, text, payload, GA, dpt, devicename }) => {
|
|
60
60
|
try {
|
|
61
|
-
if (node.
|
|
61
|
+
if (node.serverKNX === null) { node.status({ fill: 'red', shape: 'dot', text: '[NO GATEWAY SELECTED]' }); return }
|
|
62
62
|
GA = GA === undefined ? '' : GA
|
|
63
63
|
payload = payload === undefined ? '' : payload
|
|
64
64
|
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload
|
|
@@ -71,7 +71,7 @@ module.exports = function (RED) {
|
|
|
71
71
|
// 02/12/2022 Expose the complete ETS CSV as well
|
|
72
72
|
if (node.exposeAsVariable !== 'exposeAsVariableNO') {
|
|
73
73
|
try {
|
|
74
|
-
node.
|
|
74
|
+
node.serverKNX.csv.forEach(element => {
|
|
75
75
|
node.exposedGAs.push({ address: element.ga, dpt: element.dpt, devicename: element.devicename, payload: undefined })
|
|
76
76
|
})
|
|
77
77
|
} catch (error) {
|
|
@@ -105,7 +105,7 @@ module.exports = function (RED) {
|
|
|
105
105
|
// 13/09/2021 retrieve the datapoint if not specified
|
|
106
106
|
if (element.hasOwnProperty('dpt') === false || element.dpt === undefined || element.dpt === '') {
|
|
107
107
|
try {
|
|
108
|
-
const sDPT = node.
|
|
108
|
+
const sDPT = node.serverKNX.csv.find(item => item.ga === element.address).dpt
|
|
109
109
|
element.dpt = sDPT
|
|
110
110
|
} catch (error) {
|
|
111
111
|
node.setNodeStatus({ fill: 'RED', shape: 'dot', text: 'Datapoint not found in CSV for ' + element.address, payload: '', GA: '', dpt: '', devicename: '' })
|
|
@@ -117,7 +117,7 @@ module.exports = function (RED) {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
node.setNodeStatus({ fill: 'green', shape: 'dot', text: 'Write', payload: element.payload, GA: element.address, dpt: element.dpt || '', devicename: '' })
|
|
120
|
-
node.
|
|
120
|
+
node.serverKNX.sendKNXTelegramToKNXEngine({ grpaddr: element.address, payload: element.payload, dpt: element.dpt || '', outputtype: 'write', nodecallerid: node.id })
|
|
121
121
|
}
|
|
122
122
|
oContext = null // 21/03/2022
|
|
123
123
|
node.goTimerGo()
|
|
@@ -167,16 +167,16 @@ module.exports = function (RED) {
|
|
|
167
167
|
node.on('close', function (done) {
|
|
168
168
|
if (node.timerExposedGAs !== null) clearTimeout(node.timerExposedGAs)
|
|
169
169
|
node.exposedGAs = []
|
|
170
|
-
if (node.
|
|
171
|
-
node.
|
|
170
|
+
if (node.serverKNX) {
|
|
171
|
+
node.serverKNX.removeClient(node)
|
|
172
172
|
}
|
|
173
173
|
done()
|
|
174
174
|
})
|
|
175
175
|
|
|
176
176
|
// On each deploy, unsubscribe+resubscribe
|
|
177
|
-
if (node.
|
|
178
|
-
node.
|
|
179
|
-
node.
|
|
177
|
+
if (node.serverKNX) {
|
|
178
|
+
node.serverKNX.removeClient(node)
|
|
179
|
+
node.serverKNX.addClient(node)
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
182
|
RED.nodes.registerType('knxUltimateGlobalContext', knxUltimateGlobalContext)
|
|
@@ -2,7 +2,7 @@ module.exports = function (RED) {
|
|
|
2
2
|
function knxUltimateHueBattery(config) {
|
|
3
3
|
RED.nodes.createNode(this, config);
|
|
4
4
|
const node = this;
|
|
5
|
-
node.
|
|
5
|
+
node.serverKNX = RED.nodes.getNode(config.server);
|
|
6
6
|
node.serverHue = RED.nodes.getNode(config.serverHue);
|
|
7
7
|
node.topic = node.name;
|
|
8
8
|
node.name = config.name === undefined ? 'Hue' : config.name;
|
|
@@ -69,7 +69,7 @@ module.exports = function (RED) {
|
|
|
69
69
|
knxMsgPayload.payload = _event.power_state.battery_level;
|
|
70
70
|
// Send to KNX bus
|
|
71
71
|
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) {
|
|
72
|
-
node.
|
|
72
|
+
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
73
73
|
grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id,
|
|
74
74
|
});
|
|
75
75
|
}
|
|
@@ -100,16 +100,16 @@ module.exports = function (RED) {
|
|
|
100
100
|
knxMsgPayload.payload = _level;
|
|
101
101
|
// Send to KNX bus
|
|
102
102
|
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) {
|
|
103
|
-
node.
|
|
103
|
+
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
104
104
|
grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'response', nodecallerid: node.id,
|
|
105
105
|
});
|
|
106
106
|
}
|
|
107
107
|
};
|
|
108
108
|
|
|
109
109
|
// On each deploy, unsubscribe+resubscribe
|
|
110
|
-
if (node.
|
|
111
|
-
node.
|
|
112
|
-
node.
|
|
110
|
+
if (node.serverKNX) {
|
|
111
|
+
node.serverKNX.removeClient(node);
|
|
112
|
+
node.serverKNX.addClient(node);
|
|
113
113
|
}
|
|
114
114
|
if (node.serverHue) {
|
|
115
115
|
node.serverHue.removeClient(node);
|
|
@@ -121,8 +121,8 @@ module.exports = function (RED) {
|
|
|
121
121
|
});
|
|
122
122
|
|
|
123
123
|
node.on('close', (done) => {
|
|
124
|
-
if (node.
|
|
125
|
-
node.
|
|
124
|
+
if (node.serverKNX) {
|
|
125
|
+
node.serverKNX.removeClient(node);
|
|
126
126
|
}
|
|
127
127
|
if (node.serverHue) {
|
|
128
128
|
node.serverHue.removeClient(node);
|