node-red-contrib-knx-ultimate 2.3.2 → 2.3.4
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 +6 -0
- package/nodes/hue-config.js +6 -3
- package/nodes/knxUltimateAlerter.html +7 -7
- package/nodes/knxUltimateAlerter.js +154 -154
- package/nodes/knxUltimateHueLight.html +362 -357
- package/nodes/knxUltimateHueLight.js +29 -28
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
**Version 2.3.4** - Jan 2024<br/>
|
|
10
|
+
- HUE Light: fixex tab "DIM/Brightness" inaccessible, when "KNX Brightness Status" was set to use the default knx behaviour.<br/>
|
|
11
|
+
|
|
12
|
+
**Version 2.3.3** - Jan 2024<br/>
|
|
13
|
+
- HUE Light: added a warning if you double click a node, with the node still querying the HUE Bridge for the device.<br/>
|
|
14
|
+
|
|
9
15
|
**Version 2.3.2** - Jan 2024<br/>
|
|
10
16
|
- HUE Light: minor fixes.
|
|
11
17
|
|
package/nodes/hue-config.js
CHANGED
|
@@ -207,8 +207,8 @@ module.exports = (RED) => {
|
|
|
207
207
|
shape: "ring",
|
|
208
208
|
text: "Ready :-)",
|
|
209
209
|
});
|
|
210
|
-
_node.currentHUEDevice = cloneDeep(oHUEDevice);
|
|
211
|
-
if (_node.initializingAtStart === true) _node.handleSendHUE(oHUEDevice);
|
|
210
|
+
_node.currentHUEDevice = cloneDeep(oHUEDevice); // Copy by Value and not by ref
|
|
211
|
+
if (_node.initializingAtStart === true) _node.handleSendHUE(oHUEDevice); // Pass by value
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
});
|
|
@@ -506,6 +506,9 @@ module.exports = (RED) => {
|
|
|
506
506
|
|
|
507
507
|
RED.httpAdmin.get("/knxUltimateGetLightObject", RED.auth.needsPermission("hue-config.read"), (req, res) => {
|
|
508
508
|
try {
|
|
509
|
+
if (node.hueAllResources === undefined) {
|
|
510
|
+
throw (new Error("Resource not yet loaded"));
|
|
511
|
+
}
|
|
509
512
|
const _lightId = req.query.id;
|
|
510
513
|
const oLight = node.hueAllResources.filter((a) => a.id === _lightId)[0];
|
|
511
514
|
// Infer some useful info, so the HTML part can avoid to query the server
|
|
@@ -527,7 +530,7 @@ module.exports = (RED) => {
|
|
|
527
530
|
}
|
|
528
531
|
res.json(oLight);
|
|
529
532
|
} catch (error) {
|
|
530
|
-
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error(`KNXUltimateHue: hueEngine: knxUltimateGetLightObject: error ${error.message}
|
|
533
|
+
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error(`KNXUltimateHue: hueEngine: knxUltimateGetLightObject: error ${error.message}.`);
|
|
531
534
|
res.json({});
|
|
532
535
|
}
|
|
533
536
|
});
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
// Scene configuration
|
|
61
61
|
var previousValueType = { value: "prev", label: this._("switch.previous"), hasValue: false };
|
|
62
62
|
function resizeRule(rule) {
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
|
|
64
|
+
}
|
|
65
65
|
$("#node-input-rule-container").css('min-height', '350px').css('min-width', '450px').editableList({
|
|
66
66
|
addItem: function (container, i, opt) { // row, index, data
|
|
67
67
|
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
var oTopicField = $("<input/>", { class: "rowRuleTopic", type: "text", placeholder: "GA or devicename", style: "width:20%; margin-left: 5px; text-align: left;" }).appendTo(row);
|
|
81
81
|
var finalspan = $('<span/>', { style: "" }).appendTo(row);
|
|
82
82
|
finalspan.append(' <span class="node-input-rule-index"></span> ');
|
|
83
|
-
var orowRuleDeviceName = $('<input/>', {
|
|
83
|
+
var orowRuleDeviceName = $('<input/>', { maxlength: "14", class: "rowRuleDeviceName", type: "text", style: "width:30%; margin-left: 0px; text-align: left;font-style: italic;", placeholder: "Name (max 14 chars)" }).appendTo(row);
|
|
84
84
|
var orowRuleLongDeviceName = $('<input/>', { class: "rowRuleLongDeviceName", type: "text", style: "width:45%; margin-left: 0px; text-align: left;", placeholder: "Long name" }).appendTo(row);
|
|
85
85
|
|
|
86
86
|
oTopicField.on("change", function () {
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
var sDevName = ui.item.label.split("#")[1].trim();
|
|
111
111
|
try {
|
|
112
112
|
sDevName = sDevName.substr(sDevName.indexOf(")") + 1).trim();
|
|
113
|
-
orowRuleDeviceName.val(sDevName.substr(0,14));
|
|
113
|
+
orowRuleDeviceName.val(sDevName.substr(0, 14));
|
|
114
114
|
orowRuleLongDeviceName.val(sDevName);
|
|
115
115
|
} catch (error) {
|
|
116
116
|
}
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
oTopicField.val(rule.topic);
|
|
122
122
|
orowRuleDeviceName.val(rule.devicename);
|
|
123
123
|
orowRuleLongDeviceName.val(rule.longdevicename);
|
|
124
|
-
oTopicField.change();
|
|
124
|
+
oTopicField.change();
|
|
125
125
|
|
|
126
126
|
},
|
|
127
127
|
removeItem: function (opt) {
|
|
@@ -197,8 +197,8 @@
|
|
|
197
197
|
<div class="form-row">
|
|
198
198
|
<label for="node-input-whentostart"><i class="fa fa-repeat"></i> <span data-i18n="knxUltimateAlerter.properties.node-input-whentostart"></span> </label>
|
|
199
199
|
<select id="node-input-whentostart">
|
|
200
|
-
<option value="manualstart"
|
|
201
|
-
<option value="ifnewalert"
|
|
200
|
+
<option value="manualstart">Start alert cycle manually via incoming message></option>
|
|
201
|
+
<option value="ifnewalert">Start the alert cycle with each new alerted device</option>
|
|
202
202
|
</select>
|
|
203
203
|
</div>
|
|
204
204
|
|
|
@@ -1,103 +1,103 @@
|
|
|
1
1
|
|
|
2
2
|
module.exports = function (RED) {
|
|
3
3
|
function knxUltimateAlerter(config) {
|
|
4
|
-
const fs = require('fs')
|
|
5
|
-
const path = require('path')
|
|
6
|
-
const mkdirp = require('mkdirp')
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const mkdirp = require('mkdirp');
|
|
7
7
|
// const Address = require('./../KNXEngine/src/protocol/KNXAddress')
|
|
8
8
|
// const KnxConstants = require('./../KNXEngine/src/protocol/KNXConstants')
|
|
9
9
|
|
|
10
|
-
RED.nodes.createNode(this, config)
|
|
11
|
-
const node = this
|
|
12
|
-
node.server = RED.nodes.getNode(config.server)
|
|
13
|
-
node.name = config.name || 'KNX Alerter'
|
|
14
|
-
node.listenallga = true // Dont' remove this.
|
|
15
|
-
node.notifyreadrequest = false
|
|
16
|
-
node.notifyresponse = true
|
|
17
|
-
node.notifywrite = true // Dont' remove this.
|
|
18
|
-
node.initialread = false
|
|
19
|
-
node.outputtype = 'write'
|
|
20
|
-
node.outputRBE = 'false'
|
|
21
|
-
node.inputRBE = 'false'
|
|
22
|
-
node.rules = config.rules || [{}]
|
|
23
|
-
node.isalertnode = true // Signal to config node, that this is a node scene controller
|
|
24
|
-
node.userDir = path.join(RED.settings.userDir, 'knxultimatestorage') // 09/03/2020 Storage of ttsultimate (otherwise, at each upgrade to a newer version, the node path is wiped out and recreated, loosing all custom files)
|
|
25
|
-
node.alertedDevices = []
|
|
26
|
-
node.curIndexAlertedDevice = 0
|
|
27
|
-
node.timerSend = null
|
|
28
|
-
node.whentostart = config.whentostart === undefined ? 'ifnewalert' : config.whentostart
|
|
29
|
-
node.timerinterval = (config.timerinterval === undefined || config.timerinterval == '') ? '2' : config.timerinterval
|
|
10
|
+
RED.nodes.createNode(this, config);
|
|
11
|
+
const node = this;
|
|
12
|
+
node.server = RED.nodes.getNode(config.server);
|
|
13
|
+
node.name = config.name || 'KNX Alerter';
|
|
14
|
+
node.listenallga = true; // Dont' remove this.
|
|
15
|
+
node.notifyreadrequest = false;
|
|
16
|
+
node.notifyresponse = true;
|
|
17
|
+
node.notifywrite = true; // Dont' remove this.
|
|
18
|
+
node.initialread = false;
|
|
19
|
+
node.outputtype = 'write';
|
|
20
|
+
node.outputRBE = 'false';
|
|
21
|
+
node.inputRBE = 'false';
|
|
22
|
+
node.rules = config.rules || [{}];
|
|
23
|
+
node.isalertnode = true; // Signal to config node, that this is a node scene controller
|
|
24
|
+
node.userDir = path.join(RED.settings.userDir, 'knxultimatestorage'); // 09/03/2020 Storage of ttsultimate (otherwise, at each upgrade to a newer version, the node path is wiped out and recreated, loosing all custom files)
|
|
25
|
+
node.alertedDevices = [];
|
|
26
|
+
node.curIndexAlertedDevice = 0;
|
|
27
|
+
node.timerSend = null;
|
|
28
|
+
node.whentostart = config.whentostart === undefined ? 'ifnewalert' : config.whentostart;
|
|
29
|
+
node.timerinterval = (config.timerinterval === undefined || config.timerinterval == '') ? '2' : config.timerinterval;
|
|
30
30
|
if (config.initialreadGAInRules === undefined) {
|
|
31
|
-
node.initialread = true
|
|
31
|
+
node.initialread = true;
|
|
32
32
|
} else {
|
|
33
|
-
node.initialread = config.initialreadGAInRules !== '0'
|
|
33
|
+
node.initialread = config.initialreadGAInRules !== '0';
|
|
34
34
|
}
|
|
35
35
|
|
|
36
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
|
|
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
38
|
} catch (error) {
|
|
39
|
-
node.sysLogger = 'error'
|
|
39
|
+
node.sysLogger = 'error';
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// Used to call the status update from the config node.
|
|
43
43
|
node.setNodeStatus = ({ fill, shape, text, payload, GA, dpt, devicename }) => {
|
|
44
44
|
try {
|
|
45
|
-
if (node.server === null) return
|
|
45
|
+
if (node.server === null) return;
|
|
46
46
|
// Log only service statuses, not the GA values
|
|
47
|
-
if (dpt !== undefined) return
|
|
48
|
-
if (dpt !== '') return
|
|
47
|
+
if (dpt !== undefined) return;
|
|
48
|
+
if (dpt !== '') return;
|
|
49
49
|
|
|
50
|
-
const dDate = new Date()
|
|
50
|
+
const dDate = new Date();
|
|
51
51
|
// 30/08/2019 Display only the things selected in the config
|
|
52
|
-
GA = (typeof GA === 'undefined' || GA == '') ? '' : '(' + GA + ') '
|
|
53
|
-
devicename = devicename || ''
|
|
54
|
-
dpt = (typeof dpt === 'undefined' || dpt == '') ? '' : ' DPT' + dpt
|
|
55
|
-
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload
|
|
56
|
-
node.status({ fill, shape, text: GA + payload + (node.listenallga === true ? ' ' + devicename : '') + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ' ' + text })
|
|
52
|
+
GA = (typeof GA === 'undefined' || GA == '') ? '' : '(' + GA + ') ';
|
|
53
|
+
devicename = devicename || '';
|
|
54
|
+
dpt = (typeof dpt === 'undefined' || dpt == '') ? '' : ' DPT' + dpt;
|
|
55
|
+
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload;
|
|
56
|
+
node.status({ fill, shape, text: GA + payload + (node.listenallga === true ? ' ' + devicename : '') + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ' ' + text });
|
|
57
57
|
} catch (error) {
|
|
58
58
|
}
|
|
59
|
-
}
|
|
59
|
+
};
|
|
60
60
|
|
|
61
61
|
// Used to call the status update from the config node.
|
|
62
62
|
node.setLocalStatus = ({ fill, shape, text, payload, GA, dpt, devicename }) => {
|
|
63
|
-
const dDate = new Date()
|
|
63
|
+
const dDate = new Date();
|
|
64
64
|
// 30/08/2019 Display only the things selected in the config
|
|
65
|
-
GA = (typeof GA === 'undefined' || GA == '') ? '' : '(' + GA + ') '
|
|
66
|
-
devicename = devicename || ''
|
|
67
|
-
dpt = (typeof dpt === 'undefined' || dpt == '') ? '' : ' DPT' + dpt
|
|
65
|
+
GA = (typeof GA === 'undefined' || GA == '') ? '' : '(' + GA + ') ';
|
|
66
|
+
devicename = devicename || '';
|
|
67
|
+
dpt = (typeof dpt === 'undefined' || dpt == '') ? '' : ' DPT' + dpt;
|
|
68
68
|
try {
|
|
69
|
-
node.status({ fill, shape, text: GA + payload + (node.listenallga === true ? ' ' + devicename : '') + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ' ' + text })
|
|
69
|
+
node.status({ fill, shape, text: GA + payload + (node.listenallga === true ? ' ' + devicename : '') + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ' ' + text });
|
|
70
70
|
} catch (error) {
|
|
71
71
|
}
|
|
72
|
-
}
|
|
72
|
+
};
|
|
73
73
|
|
|
74
74
|
// This function is called by the knx-ultimate config node, to output a msg.payload.
|
|
75
75
|
node.handleSend = msg => {
|
|
76
76
|
try {
|
|
77
|
-
if (!msg.knx.dpt.startsWith('1.')) return
|
|
77
|
+
if (!msg.knx.dpt.startsWith('1.')) return;
|
|
78
78
|
} catch (error) {
|
|
79
|
-
return
|
|
79
|
+
return;
|
|
80
80
|
}
|
|
81
|
-
let bFound = false // 24/04/2021 true if the cycle below found a match, otherwise false
|
|
81
|
+
let bFound = false; // 24/04/2021 true if the cycle below found a match, otherwise false
|
|
82
82
|
|
|
83
83
|
// Update the node.rules with the values taken from the file, if any, otherwise leave the default value
|
|
84
84
|
for (let i = 0; i < node.rules.length; i++) {
|
|
85
85
|
// rule is { topic: rowRuleTopic, devicename: rowRuleDeviceName, longdevicename: rowRuleLongDeviceName}
|
|
86
|
-
var rule = node.rules[i]
|
|
86
|
+
var rule = node.rules[i];
|
|
87
87
|
if (msg.topic === rule.topic) {
|
|
88
|
-
if (msg.payload
|
|
89
|
-
bFound = true
|
|
88
|
+
if (msg.payload === true) {
|
|
89
|
+
bFound = true;
|
|
90
90
|
// Add the device to the array of alertedDevices
|
|
91
|
-
const oTrovato = node.alertedDevices.find(a => a.topic === rule.topic)
|
|
91
|
+
const oTrovato = node.alertedDevices.find(a => a.topic === rule.topic);
|
|
92
92
|
if (oTrovato === undefined) {
|
|
93
|
-
node.alertedDevices.unshift({ topic: rule.topic, devicename: rule.devicename, longdevicename: rule.longdevicename }) // Add to the begin of array
|
|
94
|
-
if (node.whentostart === 'ifnewalert') node.send([null, null, node.getThirdPinMSG()])
|
|
93
|
+
node.alertedDevices.unshift({ topic: rule.topic, devicename: rule.devicename, longdevicename: rule.longdevicename }); // Add to the begin of array
|
|
94
|
+
if (node.whentostart === 'ifnewalert') node.send([null, null, node.getThirdPinMSG()]);
|
|
95
95
|
}
|
|
96
|
-
node.setLocalStatus({ fill: 'red', shape: 'dot', text: 'Alert', payload: '', GA: msg.topic, dpt: '', devicename: rule.devicename })
|
|
96
|
+
node.setLocalStatus({ fill: 'red', shape: 'dot', text: 'Alert', payload: '', GA: msg.topic, dpt: '', devicename: rule.devicename });
|
|
97
97
|
} else {
|
|
98
98
|
// Remove the device from the array
|
|
99
|
-
node.alertedDevices = node.alertedDevices.filter(a => a.topic !== msg.topic)
|
|
100
|
-
node.setLocalStatus({ fill: 'green', shape: 'dot', text: 'Restore', payload: '', GA: msg.topic, dpt: '', devicename: rule.devicename })
|
|
99
|
+
node.alertedDevices = node.alertedDevices.filter(a => a.topic !== msg.topic);
|
|
100
|
+
node.setLocalStatus({ fill: 'green', shape: 'dot', text: 'Restore', payload: '', GA: msg.topic, dpt: '', devicename: rule.devicename });
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
}
|
|
@@ -105,182 +105,182 @@ module.exports = function (RED) {
|
|
|
105
105
|
// If there's some device to alert, stop current timer and restart
|
|
106
106
|
// This allow the last alerted device to be outputted immediately
|
|
107
107
|
if (bFound && node.whentostart === 'ifnewalert' && node.alertedDevices.length > 0) {
|
|
108
|
-
clearTimeout(node.timerSend)
|
|
108
|
+
clearTimeout(node.timerSend);
|
|
109
109
|
// Send directly the second and third message PIN
|
|
110
|
-
node.send([null, node.getSecondPinMSG(), null])
|
|
111
|
-
node.curIndexAlertedDevice = 0 // Restart form the beginning
|
|
112
|
-
node.startTimer()
|
|
110
|
+
node.send([null, node.getSecondPinMSG(), null]);
|
|
111
|
+
node.curIndexAlertedDevice = 0; // Restart form the beginning
|
|
112
|
+
node.startTimer();
|
|
113
113
|
}
|
|
114
|
-
}
|
|
114
|
+
};
|
|
115
115
|
|
|
116
116
|
// Get the msg to be outputted on second PIN
|
|
117
117
|
node.getSecondPinMSG = () => {
|
|
118
118
|
if (node.alertedDevices.length > 0) {
|
|
119
|
-
const msg = {}
|
|
120
|
-
let sRet = ''
|
|
121
|
-
let sRetLong = ''
|
|
122
|
-
let sTopic = ''
|
|
119
|
+
const msg = {};
|
|
120
|
+
let sRet = '';
|
|
121
|
+
let sRetLong = '';
|
|
122
|
+
let sTopic = '';
|
|
123
123
|
node.alertedDevices.forEach(function (item) {
|
|
124
|
-
sTopic += item.topic + ', '
|
|
125
|
-
if (item.devicename !== undefined && item.devicename !== '') sRet += item.devicename + ', '
|
|
126
|
-
if (item.longdevicename !== undefined && item.longdevicename !== '') sRetLong += item.longdevicename + ', '
|
|
127
|
-
})
|
|
128
|
-
sTopic = sTopic.slice(0, -2)
|
|
129
|
-
if (sRet.length > 2) sRet = sRet.slice(0, -2)
|
|
130
|
-
if (sRetLong.length > 2) sRetLong = sRetLong.slice(0, -2)
|
|
131
|
-
msg.topic = sTopic
|
|
132
|
-
msg.devicename = sRet
|
|
133
|
-
msg.longdevicename = sRetLong
|
|
134
|
-
msg.count = node.alertedDevices.length
|
|
135
|
-
msg.payload = true
|
|
136
|
-
return msg
|
|
124
|
+
sTopic += item.topic + ', ';
|
|
125
|
+
if (item.devicename !== undefined && item.devicename !== '') sRet += item.devicename + ', ';
|
|
126
|
+
if (item.longdevicename !== undefined && item.longdevicename !== '') sRetLong += item.longdevicename + ', ';
|
|
127
|
+
});
|
|
128
|
+
sTopic = sTopic.slice(0, -2);
|
|
129
|
+
if (sRet.length > 2) sRet = sRet.slice(0, -2);
|
|
130
|
+
if (sRetLong.length > 2) sRetLong = sRetLong.slice(0, -2);
|
|
131
|
+
msg.topic = sTopic;
|
|
132
|
+
msg.devicename = sRet;
|
|
133
|
+
msg.longdevicename = sRetLong;
|
|
134
|
+
msg.count = node.alertedDevices.length;
|
|
135
|
+
msg.payload = true;
|
|
136
|
+
return msg;
|
|
137
137
|
}
|
|
138
|
-
}
|
|
138
|
+
};
|
|
139
139
|
|
|
140
140
|
// Get the msg to be outputted on third PIN
|
|
141
141
|
node.getThirdPinMSG = () => {
|
|
142
142
|
if (node.alertedDevices.length > 0) {
|
|
143
|
-
const msg = {}
|
|
144
|
-
let sRet = ''
|
|
145
|
-
let sRetLong = ''
|
|
146
|
-
let sTopic = ''
|
|
147
|
-
const item = node.alertedDevices[0] // Pick the last alerted device
|
|
148
|
-
sTopic = item.topic
|
|
149
|
-
if (item.devicename !== undefined && item.devicename !== '') sRet = item.devicename
|
|
150
|
-
if (item.longdevicename !== undefined && item.longdevicename !== '') sRetLong = item.longdevicename
|
|
151
|
-
msg.topic = sTopic
|
|
152
|
-
msg.devicename = sRet
|
|
153
|
-
msg.longdevicename = sRetLong
|
|
154
|
-
msg.count = node.alertedDevices.length
|
|
155
|
-
msg.payload = true
|
|
156
|
-
return msg
|
|
143
|
+
const msg = {};
|
|
144
|
+
let sRet = '';
|
|
145
|
+
let sRetLong = '';
|
|
146
|
+
let sTopic = '';
|
|
147
|
+
const item = node.alertedDevices[0]; // Pick the last alerted device
|
|
148
|
+
sTopic = item.topic;
|
|
149
|
+
if (item.devicename !== undefined && item.devicename !== '') sRet = item.devicename;
|
|
150
|
+
if (item.longdevicename !== undefined && item.longdevicename !== '') sRetLong = item.longdevicename;
|
|
151
|
+
msg.topic = sTopic;
|
|
152
|
+
msg.devicename = sRet;
|
|
153
|
+
msg.longdevicename = sRetLong;
|
|
154
|
+
msg.count = node.alertedDevices.length;
|
|
155
|
+
msg.payload = true;
|
|
156
|
+
return msg;
|
|
157
157
|
}
|
|
158
|
-
}
|
|
158
|
+
};
|
|
159
159
|
|
|
160
160
|
// 24/04/2021 perform a read on all GA in the rule list. Called both from node.on("input") and knxUltimate-config
|
|
161
161
|
node.initialReadAllDevicesInRules = () => {
|
|
162
162
|
if (node.server) {
|
|
163
|
-
let grpaddr = ''
|
|
163
|
+
let grpaddr = '';
|
|
164
164
|
for (let i = 0; i < node.rules.length; i++) {
|
|
165
165
|
// rule is { topic: rowRuleTopic, devicename: rowRuleDeviceName, longdevicename: rowRuleLongDeviceName}
|
|
166
|
-
const rule = node.rules[i]
|
|
166
|
+
const rule = node.rules[i];
|
|
167
167
|
// READ: Send a Read request to the bus
|
|
168
|
-
grpaddr = rule.topic
|
|
168
|
+
grpaddr = rule.topic;
|
|
169
169
|
try {
|
|
170
170
|
// Check if it's a group address
|
|
171
171
|
// const ret = Address.KNXAddress.createFromString(grpaddr, Address.KNXAddress.TYPE_GROUP)
|
|
172
|
-
node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'Read', payload: '', GA: grpaddr, dpt: '', devicename: rule.devicename })
|
|
173
|
-
node.server.writeQueueAdd({ grpaddr, payload: '', dpt: '', outputtype: 'read', nodecallerid: node.id })
|
|
172
|
+
node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'Read', payload: '', GA: grpaddr, dpt: '', devicename: rule.devicename });
|
|
173
|
+
node.server.writeQueueAdd({ grpaddr, payload: '', dpt: '', outputtype: 'read', nodecallerid: node.id });
|
|
174
174
|
} catch (error) {
|
|
175
|
-
node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'Not a KNX GA ' + error.message, payload: '', GA: grpaddr, dpt: '', devicename: rule.devicename })
|
|
175
|
+
node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'Not a KNX GA ' + error.message, payload: '', GA: grpaddr, dpt: '', devicename: rule.devicename });
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
} else {
|
|
179
|
-
node.setLocalStatus({ fill: 'red', shape: 'ring', text: 'No gateway selected. Unable to read from KNX bus', payload: '', GA: '', dpt: '', devicename: '' })
|
|
179
|
+
node.setLocalStatus({ fill: 'red', shape: 'ring', text: 'No gateway selected. Unable to read from KNX bus', payload: '', GA: '', dpt: '', devicename: '' });
|
|
180
180
|
}
|
|
181
|
-
}
|
|
181
|
+
};
|
|
182
182
|
|
|
183
183
|
node.on('input', function (msg) {
|
|
184
|
-
if (typeof msg === 'undefined') return
|
|
184
|
+
if (typeof msg === 'undefined') return;
|
|
185
185
|
if (msg.hasOwnProperty('start')) {
|
|
186
|
-
clearTimeout(node.timerSend)
|
|
187
|
-
node.curIndexAlertedDevice = 0 // Restart form the beginning
|
|
186
|
+
clearTimeout(node.timerSend);
|
|
187
|
+
node.curIndexAlertedDevice = 0; // Restart form the beginning
|
|
188
188
|
if (node.alertedDevices.length > 0) {
|
|
189
|
-
node.send([null, node.getSecondPinMSG(), node.getThirdPinMSG()])
|
|
190
|
-
node.startTimer()
|
|
189
|
+
node.send([null, node.getSecondPinMSG(), node.getThirdPinMSG()]);
|
|
190
|
+
node.startTimer();
|
|
191
191
|
} else {
|
|
192
192
|
// Nothing more to output
|
|
193
|
-
node.sendNoMoreDevices()
|
|
193
|
+
node.sendNoMoreDevices();
|
|
194
194
|
}
|
|
195
|
-
return
|
|
195
|
+
return;
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
// 24/04/2021 if payload is read or the Telegram type is set to "read", do a read
|
|
199
199
|
if ((msg.hasOwnProperty('readstatus') && msg.readstatus === true)) {
|
|
200
|
-
node.initialReadAllDevicesInRules()
|
|
201
|
-
return
|
|
200
|
+
node.initialReadAllDevicesInRules();
|
|
201
|
+
return;
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
if (msg.topic === undefined) {
|
|
205
|
-
node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'ERROR: You must provide a msg.topic', payload: '', GA: '', dpt: '', devicename: '' })
|
|
206
|
-
return
|
|
205
|
+
node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'ERROR: You must provide a msg.topic', payload: '', GA: '', dpt: '', devicename: '' });
|
|
206
|
+
return;
|
|
207
207
|
}
|
|
208
208
|
if (msg.payload === undefined) {
|
|
209
|
-
node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'ERROR: You must provide payload (true/false)', payload: '', GA: '', dpt: '', devicename: '' })
|
|
210
|
-
return
|
|
209
|
+
node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'ERROR: You must provide payload (true/false)', payload: '', GA: '', dpt: '', devicename: '' });
|
|
210
|
+
return;
|
|
211
211
|
}
|
|
212
|
-
msg.knx = { dpt: '1.001' }
|
|
213
|
-
node.handleSend(msg)
|
|
214
|
-
})
|
|
212
|
+
msg.knx = { dpt: '1.001' };
|
|
213
|
+
node.handleSend(msg);
|
|
214
|
+
});
|
|
215
215
|
|
|
216
216
|
node.on('close', function (done) {
|
|
217
|
-
clearTimeout(node.timerSend)
|
|
217
|
+
clearTimeout(node.timerSend);
|
|
218
218
|
if (node.server) {
|
|
219
|
-
node.server.removeClient(node)
|
|
219
|
+
node.server.removeClient(node);
|
|
220
220
|
}
|
|
221
|
-
done()
|
|
222
|
-
})
|
|
221
|
+
done();
|
|
222
|
+
});
|
|
223
223
|
|
|
224
224
|
node.handleTimer = () => {
|
|
225
225
|
if (node.alertedDevices.length > 0) {
|
|
226
|
-
const count = node.alertedDevices.length
|
|
226
|
+
const count = node.alertedDevices.length;
|
|
227
227
|
if (node.curIndexAlertedDevice > count - 1) {
|
|
228
|
-
node.curIndexAlertedDevice = 0
|
|
228
|
+
node.curIndexAlertedDevice = 0;
|
|
229
229
|
if (node.whentostart === 'manualstart') {
|
|
230
|
-
node.curIndexAlertedDevice = 0 // Restart form the beginning
|
|
231
|
-
return
|
|
230
|
+
node.curIndexAlertedDevice = 0; // Restart form the beginning
|
|
231
|
+
return;
|
|
232
232
|
}
|
|
233
233
|
}
|
|
234
234
|
// Create output message
|
|
235
235
|
try {
|
|
236
|
-
const curDev = node.alertedDevices[node.curIndexAlertedDevice] // is { topic: rule.topic, devicename: rule.devicename }
|
|
237
|
-
const msg = {}
|
|
238
|
-
msg.topic = curDev.topic
|
|
239
|
-
msg.count = count
|
|
240
|
-
msg.devicename = curDev.devicename
|
|
241
|
-
msg.longdevicename = curDev.longdevicename
|
|
242
|
-
msg.payload = true
|
|
243
|
-
node.send([msg, null, null])
|
|
236
|
+
const curDev = node.alertedDevices[node.curIndexAlertedDevice]; // is { topic: rule.topic, devicename: rule.devicename }
|
|
237
|
+
const msg = {};
|
|
238
|
+
msg.topic = curDev.topic;
|
|
239
|
+
msg.count = count;
|
|
240
|
+
msg.devicename = curDev.devicename;
|
|
241
|
+
msg.longdevicename = curDev.longdevicename;
|
|
242
|
+
msg.payload = true;
|
|
243
|
+
node.send([msg, null, null]);
|
|
244
244
|
} catch (error) {
|
|
245
245
|
}
|
|
246
|
-
node.curIndexAlertedDevice += 1
|
|
246
|
+
node.curIndexAlertedDevice += 1;
|
|
247
247
|
// Restart timer
|
|
248
|
-
node.startTimer()
|
|
248
|
+
node.startTimer();
|
|
249
249
|
} else {
|
|
250
250
|
// Nothing more to output
|
|
251
|
-
node.sendNoMoreDevices()
|
|
251
|
+
node.sendNoMoreDevices();
|
|
252
252
|
}
|
|
253
|
-
}
|
|
253
|
+
};
|
|
254
254
|
|
|
255
255
|
// Start timer
|
|
256
256
|
node.startTimer = () => {
|
|
257
|
-
clearTimeout(node.timerSend)
|
|
257
|
+
clearTimeout(node.timerSend);
|
|
258
258
|
node.timerSend = setTimeout(() => {
|
|
259
|
-
node.handleTimer()
|
|
260
|
-
}, node.timerinterval * 1000)
|
|
261
|
-
}
|
|
259
|
+
node.handleTimer();
|
|
260
|
+
}, node.timerinterval * 1000);
|
|
261
|
+
};
|
|
262
262
|
|
|
263
263
|
// As soon as there no more devices..
|
|
264
264
|
node.sendNoMoreDevices = () => {
|
|
265
|
-
const msg = {}
|
|
266
|
-
msg.topic = ''
|
|
267
|
-
msg.count = 0
|
|
268
|
-
msg.devicename = ''
|
|
269
|
-
msg.longdevicename = ''
|
|
270
|
-
msg.payload = false
|
|
271
|
-
node.send([msg, msg, msg])
|
|
272
|
-
}
|
|
265
|
+
const msg = {};
|
|
266
|
+
msg.topic = '';
|
|
267
|
+
msg.count = 0;
|
|
268
|
+
msg.devicename = '';
|
|
269
|
+
msg.longdevicename = '';
|
|
270
|
+
msg.payload = false;
|
|
271
|
+
node.send([msg, msg, msg]);
|
|
272
|
+
};
|
|
273
273
|
|
|
274
274
|
// Init
|
|
275
|
-
node.sendNoMoreDevices()
|
|
275
|
+
node.sendNoMoreDevices();
|
|
276
276
|
|
|
277
277
|
// On each deploy, unsubscribe+resubscribe
|
|
278
278
|
if (node.server) {
|
|
279
|
-
node.server.removeClient(node)
|
|
279
|
+
node.server.removeClient(node);
|
|
280
280
|
if (node.topic !== '' || node.topicSave !== '') {
|
|
281
|
-
node.server.addClient(node)
|
|
281
|
+
node.server.addClient(node);
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
284
|
}
|
|
285
|
-
RED.nodes.registerType('knxUltimateAlerter', knxUltimateAlerter)
|
|
286
|
-
}
|
|
285
|
+
RED.nodes.registerType('knxUltimateAlerter', knxUltimateAlerter);
|
|
286
|
+
};
|