node-red-contrib-knx-ultimate 2.3.3 → 2.3.5

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 CHANGED
@@ -6,6 +6,12 @@
6
6
 
7
7
  # CHANGELOG
8
8
 
9
+ **Version 2.3.5** - Jan 2024<br/>
10
+ - HUE Light: fixed multi HUE Bridge GUI issue.<br/>
11
+
12
+ **Version 2.3.4** - Jan 2024<br/>
13
+ - HUE Light: fixex tab "DIM/Brightness" inaccessible, when "KNX Brightness Status" was set to use the default knx behaviour.<br/>
14
+
9
15
  **Version 2.3.3** - Jan 2024<br/>
10
16
  - HUE Light: added a warning if you double click a node, with the node still querying the HUE Bridge for the device.<br/>
11
17
 
@@ -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
  });
@@ -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/>', { 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);
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" data-i18n="knxUltimateAlerter.selectlists.manualstart"></option>
201
- <option value="ifnewalert" data-i18n="knxUltimateAlerter.selectlists.ifnewalert"></option>
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 == true) {
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
+ };
@@ -361,7 +361,7 @@
361
361
  <input type="text" id="node-input-nameshort_release" style="width:200px;margin-left: 5px; text-align: left;">
362
362
  </div>
363
363
  <div class="form-row">
364
- <label style="width:100px;"><i class="fa fa-play-circle-o"></i> Switch Status</label>
364
+ <label style="width:100px;"><i class="fa fa-question-circle"></i> Switch Status</label>
365
365
 
366
366
  <label for="node-input-GAshort_releaseStatus" style="width:20px;">GA</label>
367
367
  <input type="text" id="node-input-GAshort_releaseStatus" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
@@ -141,14 +141,14 @@
141
141
  getDPT("232.600", "#node-input-dptLightColorState");
142
142
  getGroupAddress("#node-input-GALightColorState", "#node-input-nameLightColorState", "#node-input-dptLightColorState", " 232.600");
143
143
 
144
- getDPT("3.007", "#node-input-dptLightHSV");
145
- getGroupAddress("#node-input-GALightHSV", "#node-input-nameLightHSV", "#node-input-dptLightHSV", " 3.007");
144
+ getDPT("3.007", "#node-input-dptLightKelvinDIM");
145
+ getGroupAddress("#node-input-GALightKelvinDIM", "#node-input-nameLightKelvinDIM", "#node-input-dptLightKelvinDIM", " 3.007");
146
146
 
147
- getDPT("5.001", "#node-input-dptLightHSVPercentage");
148
- getGroupAddress("#node-input-GALightHSVPercentage", "#node-input-nameLightHSVPercentage", "#node-input-dptLightHSVPercentage", " 5.001");
147
+ getDPT("5.001", "#node-input-dptLightKelvinPercentage");
148
+ getGroupAddress("#node-input-GALightKelvinPercentage", "#node-input-nameLightKelvinPercentage", "#node-input-dptLightKelvinPercentage", " 5.001");
149
149
 
150
- getDPT("5.001", "#node-input-dptLightHSVState");
151
- getGroupAddress("#node-input-GALightHSVState", "#node-input-nameLightHSVState", "#node-input-dptLightHSVState", " 5.001");
150
+ getDPT("5.001", "#node-input-dptLightKelvinPercentageState");
151
+ getGroupAddress("#node-input-GALightKelvinPercentageState", "#node-input-nameLightKelvinPercentageState", "#node-input-dptLightKelvinPercentageState", " 5.001");
152
152
 
153
153
  getDPT("1.", "#node-input-dptLightBlink");
154
154
  getGroupAddress("#node-input-GALightBlink", "#node-input-nameLightBlink", "#node-input-dptLightBlink", " 1.");
@@ -173,15 +173,13 @@
173
173
 
174
174
 
175
175
  // Get the HUE capabilities to enable/disable UI parts
176
+ var getJsonPromise;
176
177
  if ($("#node-input-hueDevice").val() === '') {
177
178
  $("#tabs").hide();
178
179
  } else {
179
- $.getJSON("knxUltimateGetLightObject?id=" + $("#node-input-hueDevice").val().split("#")[0] + "&" + { _: new Date().getTime() }, (data) => {
180
+ if (getJsonPromise !== undefined) getJsonPromise.abort();
181
+ getJsonPromise = $.getJSON("knxUltimateGetLightObject?id=" + $("#node-input-hueDevice").val().split("#")[0] + "&" + { _: new Date().getTime() }, (data) => {
180
182
  let oLight = data;
181
- if (JSON.stringify(data) === "{}") {
182
- $("#mainWindow").hide();
183
- RED.notify("Please close and reload this window in few seconds. Still querying the HUE Bridge.", { type: "warning", timeout: 8000 });
184
- }
185
183
  // Check if grouped, to hide/show the "Get current" buttons
186
184
  if (oLight.type === "grouped_light") {
187
185
  $("#tabs").tabs("enable", "#tabs-4");
@@ -310,6 +308,7 @@
310
308
  $("#node-input-specifySwitchOnBrightness").val(node.specifySwitchOnBrightness).trigger('change');
311
309
  $("#node-input-enableDayNightLighting").val(node.enableDayNightLighting).trigger('change');
312
310
  });
311
+ setTimeout(function () { if (getJsonPromise !== undefined) getJsonPromise.abort(); }, 10000);
313
312
  }
314
313
  // Show/Hide the div of the color at swich on
315
314
  if (node.specifySwitchOnBrightness === "yes") {
@@ -560,7 +559,7 @@
560
559
  $("#node-input-hueDevice").val(ui.item.hueDevice + "#light");
561
560
  }
562
561
  onEditPrepare(node);
563
- $("#tabs").show();
562
+ //$("#tabs").show();
564
563
  },
565
564
  });
566
565
  }
@@ -594,17 +593,25 @@
594
593
  GALightColorState: { value: "" },
595
594
  dptLightColorState: { value: "" },
596
595
 
597
- nameLightHSV: { value: "" },
598
- GALightHSV: { value: "" },
599
- dptLightHSV: { value: "" },
596
+ nameLightKelvinDIM: { value: "" },
597
+ GALightKelvinDIM: { value: "" },
598
+ dptLightKelvinDIM: { value: "" },
599
+
600
+ nameLightKelvinPercentage: { value: "" },
601
+ GALightKelvinPercentage: { value: "" },
602
+ dptLightKelvinPercentage: { value: "" },
600
603
 
601
- nameLightHSVPercentage: { value: "" },
602
- GALightHSVPercentage: { value: "" },
603
- dptLightHSVPercentage: { value: "" },
604
+ nameLightKelvinPercentageState: { value: "" },
605
+ GALightKelvinPercentageState: { value: "" },
606
+ dptLightKelvinPercentageState: { value: "" },
604
607
 
605
- nameLightHSVState: { value: "" },
606
- GALightHSVState: { value: "" },
607
- dptLightHSVState: { value: "" },
608
+ nameLightKelvin: { value: "" },
609
+ GALightKelvin: { value: "" },
610
+ dptLightKelvin: { value: "" },
611
+
612
+ nameLightKelvinState: { value: "" },
613
+ GALightKelvinState: { value: "" },
614
+ dptLightKelvinState: { value: "" },
608
615
 
609
616
  nameLightBrightness: { value: "" },
610
617
  GALightBrightness: { value: "" },
@@ -626,14 +633,6 @@
626
633
  GADaylightSensor: { value: "" },
627
634
  dptDaylightSensor: { value: "" },
628
635
 
629
- nameLightKelvin: { value: "" },
630
- GALightKelvin: { value: "" },
631
- dptLightKelvin: { value: "" },
632
-
633
- nameLightKelvinState: { value: "" },
634
- GALightKelvinState: { value: "" },
635
- dptLightKelvinState: { value: "" },
636
-
637
636
  specifySwitchOnBrightness: { value: "temperature" },
638
637
  colorAtSwitchOnDayTime: { value: '{"kelvin":3000, "brightness":100 }' },
639
638
 
@@ -781,12 +780,12 @@
781
780
 
782
781
  //#region color_temperature_mode
783
782
  // ----------------------------
784
- if ($("#node-input-GALightHSVPercentage").val !== '') {
783
+ if ($("#node-input-GALightKelvinPercentage").val !== '') {
785
784
 
786
785
  // color_temperature_mode: relative
787
786
  sYaml += ' color_temperature_mode: relative' + '\n';
788
- sYaml += ' color_temperature_address: "' + $("#node-input-GALightHSVPercentage").val() + '"\n';
789
- sYaml += $("#node-input-GALightHSVState").val() != '' ? ' color_temperature_state_address: "' + $("#node-input-GALightHSVState").val() + '"' + "\n" : '';
787
+ sYaml += ' color_temperature_address: "' + $("#node-input-GALightKelvinPercentage").val() + '"\n';
788
+ sYaml += $("#node-input-GALightKelvinPercentageState").val() != '' ? ' color_temperature_state_address: "' + $("#node-input-GALightKelvinPercentageState").val() + '"' + "\n" : '';
790
789
  sYaml += ' min_kelvin: 2200' + '\n';
791
790
  sYaml += ' max_kelvin: 6500' + '\n';
792
791
 
@@ -899,7 +898,7 @@
899
898
  <input type="text" id="node-input-nameLightSwitch" style="width:190px;margin-left: 5px; text-align: left;">
900
899
  </div>
901
900
  <div class="form-row">
902
- <label for="node-input-nameLightState" style="width:110px;"><i class="fa fa-play-circle-o"></i> Status</label>
901
+ <label for="node-input-nameLightState" style="width:110px;"><i class="fa fa-question-circle"></i> Status</label>
903
902
 
904
903
  <label for="node-input-GALightState" style="width:20px;">GA</label>
905
904
  <input type="text" id="node-input-GALightState" placeholder="Ex: 1/1/1"
@@ -947,8 +946,7 @@
947
946
  </div>
948
947
 
949
948
  <div class="form-row">
950
- <label for="node-input-nameLightBrightnessState" style="width:110px;"><i class="fa fa-play-circle-o"></i>
951
- Status</label>
949
+ <label for="node-input-nameLightBrightnessState" style="width:110px;"><i class="fa fa-question-circle"></i> Status</label>
952
950
 
953
951
  <label for="node-input-GALightBrightnessState" style="width:20px;"><span
954
952
  data-i18n="knxUltimateHueLight.node-input-GALightState"></span></label>
@@ -989,32 +987,32 @@
989
987
  <div id="tabs-3">
990
988
  <p>
991
989
  <div class="form-row">
992
- <label for="node-input-nameLightHSV" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control dim</label>
990
+ <label for="node-input-nameLightKelvinDIM" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control dim</label>
993
991
 
994
- <label for="node-input-GALightHSV" style="width:20px;">GA</label>
995
- <input type="text" id="node-input-GALightHSV" placeholder="Ex: 1/1/1"
992
+ <label for="node-input-GALightKelvinDIM" style="width:20px;">GA</label>
993
+ <input type="text" id="node-input-GALightKelvinDIM" placeholder="Ex: 1/1/1"
996
994
  style="width:70px;margin-left: 5px; text-align: left;">
997
995
 
998
- <label for="node-input-dptLightHSV" style="width:40px; margin-left: 0px; text-align: right;">DPT</label>
999
- <select id="node-input-dptLightHSV" style="width:140px;"></select>
996
+ <label for="node-input-dptLightKelvinDIM" style="width:40px; margin-left: 0px; text-align: right;">DPT</label>
997
+ <select id="node-input-dptLightKelvinDIM" style="width:140px;"></select>
1000
998
 
1001
- <label for="node-input-nameLightHSV" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
1002
- <input type="text" id="node-input-nameLightHSV" style="width:190px;margin-left: 5px; text-align: left;">
999
+ <label for="node-input-nameLightKelvinDIM" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
1000
+ <input type="text" id="node-input-nameLightKelvinDIM" style="width:190px;margin-left: 5px; text-align: left;">
1003
1001
  </div>
1004
1002
  <div class="form-row">
1005
- <label for="node-input-nameLightHSVPercentage" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control
1003
+ <label for="node-input-nameLightKelvinPercentage" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control
1006
1004
  %</label>
1007
1005
 
1008
- <label for="node-input-GALightHSVPercentage" style="width:20px;">GA</label>
1009
- <input type="text" id="node-input-GALightHSVPercentage" placeholder="Ex: 1/1/1"
1006
+ <label for="node-input-GALightKelvinPercentage" style="width:20px;">GA</label>
1007
+ <input type="text" id="node-input-GALightKelvinPercentage" placeholder="Ex: 1/1/1"
1010
1008
  style="width:70px;margin-left: 5px; text-align: left;">
1011
1009
 
1012
- <label for="node-input-dptLightHSVPercentage" style="width:40px; margin-left: 0px; text-align: right;">DPT</label>
1013
- <select id="node-input-dptLightHSVPercentage" style="width:140px;"></select>
1010
+ <label for="node-input-dptLightKelvinPercentage" style="width:40px; margin-left: 0px; text-align: right;">DPT</label>
1011
+ <select id="node-input-dptLightKelvinPercentage" style="width:140px;"></select>
1014
1012
 
1015
- <label for="node-input-nameLightHSVPercentage"
1013
+ <label for="node-input-nameLightKelvinPercentage"
1016
1014
  style="width:50px; margin-left: 0px; text-align: right;">Name</label>
1017
- <input type="text" id="node-input-nameLightHSVPercentage" style="width:190px;margin-left: 5px; text-align: left;">
1015
+ <input type="text" id="node-input-nameLightKelvinPercentage" style="width:190px;margin-left: 5px; text-align: left;">
1018
1016
  </div>
1019
1017
  <div class="form-row">
1020
1018
  <label for="node-input-nameLightKelvin" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control
@@ -1031,21 +1029,21 @@
1031
1029
  <input type="text" id="node-input-nameLightKelvin" style="width:190px;margin-left: 5px; text-align: left;">
1032
1030
  </div>
1033
1031
  <div class="form-row">
1034
- <label for="node-input-nameLightHSVState" style="width:110px;"><i class="fa fa-play-circle-o"></i> Status
1032
+ <label for="node-input-nameLightKelvinPercentageState" style="width:110px;"><i class="fa fa-question-circle"></i> Status
1035
1033
  %</label>
1036
1034
 
1037
- <label for="node-input-GALightHSVState" style="width:20px;">GA</label>
1038
- <input type="text" id="node-input-GALightHSVState" placeholder="Ex: 1/1/1"
1035
+ <label for="node-input-GALightKelvinPercentageState" style="width:20px;">GA</label>
1036
+ <input type="text" id="node-input-GALightKelvinPercentageState" placeholder="Ex: 1/1/1"
1039
1037
  style="width:70px;margin-left: 5px; text-align: left;">
1040
1038
 
1041
- <label for="node-input-dptLightHSVState" style="width:40px; margin-left: 0px; text-align: right;">DPT</label>
1042
- <select id="node-input-dptLightHSVState" style="width:140px;"></select>
1039
+ <label for="node-input-dptLightKelvinPercentageState" style="width:40px; margin-left: 0px; text-align: right;">DPT</label>
1040
+ <select id="node-input-dptLightKelvinPercentageState" style="width:140px;"></select>
1043
1041
 
1044
- <label for="node-input-nameLightHSVState" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
1045
- <input type="text" id="node-input-nameLightHSVState" style="width:190px;margin-left: 5px; text-align: left;">
1042
+ <label for="node-input-nameLightKelvinPercentageState" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
1043
+ <input type="text" id="node-input-nameLightKelvinPercentageState" style="width:190px;margin-left: 5px; text-align: left;">
1046
1044
  </div>
1047
1045
  <div class="form-row">
1048
- <label for="node-input-nameLightKelvinState" style="width:110px;"><i class="fa fa-play-circle-o"></i> Status
1046
+ <label for="node-input-nameLightKelvinState" style="width:110px;"><i class="fa fa-question-circle"></i> Status
1049
1047
  Kelvin</label>
1050
1048
 
1051
1049
  <label for="node-input-GALightKelvinState" style="width:20px;">GA</label>
@@ -1085,8 +1083,7 @@
1085
1083
  <input type="text" id="node-input-nameLightColor" style="width:190px;margin-left: 5px; text-align: left;">
1086
1084
  </div>
1087
1085
  <div class="form-row">
1088
- <label for="node-input-nameLightColorState" style="width:110px;"><i class="fa fa-play-circle-o"></i>
1089
- Status</label>
1086
+ <label for="node-input-nameLightColorState" style="width:110px;"><i class="fa fa-question-circle"></i> Status</label>
1090
1087
 
1091
1088
  <label for="node-input-GALightColorState" style="width:20px;"><span
1092
1089
  data-i18n="knxUltimateHueLight.node-input-GALightState"></span></label>
@@ -1142,7 +1139,7 @@
1142
1139
  <div id="tabs-6">
1143
1140
  <p>
1144
1141
  <div class="form-row">
1145
- <label style="width:260px;" for="node-input-readStatusAtStartup"><i class="fa fa-play-circle"></i> Read status at
1142
+ <label style="width:260px;" for="node-input-readStatusAtStartup"><i class="fa fa-question-circle"></i> Read status at
1146
1143
  startup</label>
1147
1144
  <select id="node-input-readStatusAtStartup">
1148
1145
  <option value="no">No</option>
@@ -13,6 +13,22 @@ module.exports = function (RED) {
13
13
  const node = this;
14
14
  node.server = RED.nodes.getNode(config.server);
15
15
  node.serverHue = RED.nodes.getNode(config.serverHue);
16
+
17
+ // Convert for backward compatibility
18
+ if (config.nameLightKelvinDIM === undefined) {
19
+ config.nameLightKelvinDIM = config.nameLightHSV;
20
+ config.GALightKelvinDIM = config.GALightHSV;
21
+ config.dptLightKelvinDIM = config.dptLightHSV;
22
+
23
+ config.nameLightKelvinPercentage = config.nameLightHSVPercentage;
24
+ config.GALightKelvinPercentage = config.GALightHSVPercentage;
25
+ config.dptLightKelvinPercentage = config.dptLightHSVPercentage;
26
+
27
+ config.nameLightKelvinPercentageState = config.nameLightHSVState;
28
+ config.GALightKelvinPercentageState = config.GALightHSVState;
29
+ config.dptLightKelvinPercentageState = config.dptLightHSVState;
30
+ }
31
+
16
32
  node.topic = node.name;
17
33
  node.name = config.name === undefined ? "Hue" : config.name;
18
34
  node.outputtopic = node.name;
@@ -283,22 +299,22 @@ module.exports = function (RED) {
283
299
  });
284
300
 
285
301
  break;
286
- case config.GALightHSV:
287
- if (config.dptLightHSV === "3.007") {
302
+ case config.GALightKelvinDIM:
303
+ if (config.dptLightKelvinDIM === "3.007") {
288
304
  // MDT smartbutton will dim the color temperature
289
305
  // { decr_incr: 1, data: 1 } : Start increasing until { decr_incr: 0, data: 0 } is received.
290
306
  // { decr_incr: 0, data: 1 } : Start decreasing until { decr_incr: 0, data: 0 } is received.
291
- msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightHSV));
307
+ msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightKelvinDIM));
292
308
  node.hueDimmingTunableWhite(msg.payload.decr_incr, msg.payload.data, 5000);
293
309
  node.setNodeStatusHue({
294
310
  fill: "green", shape: "dot", text: "KNX->HUE", payload: JSON.stringify(msg.payload),
295
311
  });
296
312
  }
297
313
  break;
298
- case config.GALightHSVPercentage:
299
- if (config.dptLightHSVPercentage === "5.001") {
314
+ case config.GALightKelvinPercentage:
315
+ if (config.dptLightKelvinPercentage === "5.001") {
300
316
  // 0-100% tunable white
301
- msg.payload = 100 - dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightHSVPercentage));
317
+ msg.payload = 100 - dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightKelvinPercentage));
302
318
  // msg.payload = msg.payload <= 0 ? 1 : msg.payload
303
319
  const retMirek = hueColorConverter.ColorConverter.scale(msg.payload, [0, 100], [153, 500]);
304
320
  msg.payload = retMirek;
@@ -456,9 +472,9 @@ module.exports = function (RED) {
456
472
  ret = node.currentHUEDevice.color.xy;
457
473
  if (ret !== undefined) node.updateKNXLightColorState(node.currentHUEDevice.color, "response");
458
474
  break;
459
- case config.GALightHSVState:
475
+ case config.GALightKelvinPercentageState:
460
476
  ret = node.currentHUEDevice.color_temperature.mirek;
461
- if (ret !== undefined) node.updateKNXLightHSVState(ret, "response");
477
+ if (ret !== undefined) node.updateKNXLightKelvinPercentageState(ret, "response");
462
478
  break;
463
479
  case config.GALightBrightnessState:
464
480
  ret = node.currentHUEDevice.dimming.brightness;
@@ -591,7 +607,7 @@ module.exports = function (RED) {
591
607
  // DIM UP
592
608
  if (node.timerStepDimTunableWhite !== undefined) clearInterval(node.timerStepDimTunableWhite);
593
609
  node.timerStepDimTunableWhite = setInterval(() => {
594
- node.updateKNXLightHSVState(node.brightnessStepTunableWhite); // Unnecessary, but necessary to set the KNX Status in real time.
610
+ node.updateKNXLightKelvinPercentageState(node.brightnessStepTunableWhite); // Unnecessary, but necessary to set the KNX Status in real time.
595
611
  node.brightnessStepTunableWhite += numStepTunableWhite; // *2 to speed up the things
596
612
  if (node.brightnessStepTunableWhite > maxDimLevelLightTunableWhite) node.brightnessStepTunableWhite = maxDimLevelLightTunableWhite;
597
613
  const hueTelegram = { color_temperature: { mirek: node.brightnessStepTunableWhite }, dynamics: { duration: _dimSpeedInMillisecsTunableWhite } };
@@ -608,7 +624,7 @@ module.exports = function (RED) {
608
624
  // DIM DOWN
609
625
  if (node.timerStepDimTunableWhite !== undefined) clearInterval(node.timerStepDimTunableWhite);
610
626
  node.timerStepDimTunableWhite = setInterval(() => {
611
- node.updateKNXLightHSVState(node.brightnessStepTunableWhite); // Unnecessary, but necessary to set the KNX Status in real time.
627
+ node.updateKNXLightKelvinPercentageState(node.brightnessStepTunableWhite); // Unnecessary, but necessary to set the KNX Status in real time.
612
628
  node.brightnessStepTunableWhite -= numStepTunableWhite; // *2 to speed up the things
613
629
  if (node.brightnessStepTunableWhite < minDimLevelLightTunableWhite) node.brightnessStepTunableWhite = minDimLevelLightTunableWhite;
614
630
  const hueTelegram = { color_temperature: { mirek: node.brightnessStepTunableWhite }, dynamics: { duration: _dimSpeedInMillisecsTunableWhite } };
@@ -626,7 +642,8 @@ module.exports = function (RED) {
626
642
 
627
643
  node.handleSendHUE = (_event) => {
628
644
  try {
629
- if (_event.id === node.hueDevice) {
645
+ let deviceByRef = cloneDeep(_event);
646
+ if (deviceByRef.id === node.hueDevice) {
630
647
  if (node.currentHUEDevice === undefined || node.serverHue === null || node.serverHue === undefined) {
631
648
  node.setNodeStatusHue({
632
649
  fill: "red",
@@ -638,7 +655,7 @@ module.exports = function (RED) {
638
655
  }
639
656
 
640
657
  // Output the msg to the flow
641
- node.send(_event);
658
+ node.send(deviceByRef);
642
659
 
643
660
  // // DEBUG testing enable/disable HTML UI Tabs
644
661
  //delete _event.dimming;
@@ -648,51 +665,51 @@ module.exports = function (RED) {
648
665
 
649
666
  // As grouped_light doesn't contain all requested properties, i find the first light in the group, and use this below in the code
650
667
  // If the event type is grouped light, and there are missing properties, i infer these missing properties from the first light in the group!
651
- if ((_event.color !== undefined || _event.dimming !== undefined || _event.color_temperature !== undefined) && _event.type === 'grouped_light') {
668
+ if ((deviceByRef.color !== undefined || deviceByRef.dimming !== undefined || deviceByRef.color_temperature !== undefined) && deviceByRef.type === 'grouped_light') {
652
669
  try {
653
- const firstLightInGroup = node.serverHue.getFirstLightInGroup(_event.id);
670
+ const firstLightInGroup = node.serverHue.getFirstLightInGroup(deviceByRef.id);
654
671
  if (firstLightInGroup !== null && firstLightInGroup !== undefined) {
655
- if (_event.color === undefined) {
656
- _event.color = firstLightInGroup.color;
672
+ if (deviceByRef.color === undefined) {
673
+ deviceByRef.color = firstLightInGroup.color;
657
674
  }
658
- if (_event.color_temperature === undefined) {
659
- _event.color_temperature = firstLightInGroup.color_temperature;
675
+ if (deviceByRef.color_temperature === undefined) {
676
+ deviceByRef.color_temperature = firstLightInGroup.color_temperature;
660
677
  }
661
678
  }
662
679
  } catch (error) { }
663
680
  }
664
681
 
665
- if (_event.on !== undefined) {
666
- node.updateKNXLightState(_event.on.on);
682
+ if (deviceByRef.on !== undefined) {
683
+ node.updateKNXLightState(deviceByRef.on.on);
667
684
  // In case of switch off, set the dim to zero
668
- if (_event.on.on === false && (config.updateKNXBrightnessStatusOnHUEOnOff === undefined || config.updateKNXBrightnessStatusOnHUEOnOff === "onhueoff")) {
685
+ if (deviceByRef.on.on === false && (config.updateKNXBrightnessStatusOnHUEOnOff === undefined || config.updateKNXBrightnessStatusOnHUEOnOff === "onhueoff")) {
669
686
  node.updateKNXBrightnessState(0);
670
- if (_event.dimming !== undefined) delete _event.dimming; // Remove event.dimming, because has beem handled by this function and i don't want the function below to take care of it.
671
- } else if (_event.on.on === true && node.currentHUEDevice.on.on === false) {
687
+ if (deviceByRef.dimming !== undefined) delete deviceByRef.dimming; // Remove event.dimming, because has beem handled by this function and i don't want the function below to take care of it.
688
+ } else if (deviceByRef.on.on === true && node.currentHUEDevice.on.on === false) {
672
689
  // Turn on always update the dimming KNX Status value as well.
673
690
  let brightVal = 50;
674
691
  if (node.currentHUEDevice.dimming !== undefined && node.currentHUEDevice.dimming.brightness !== undefined) brightVal = node.currentHUEDevice.dimming.brightness;
675
692
  node.updateKNXBrightnessState(brightVal);
676
693
  }
677
- node.currentHUEDevice.on.on = _event.on.on;
694
+ node.currentHUEDevice.on.on = deviceByRef.on.on;
678
695
  }
679
696
 
680
- if (_event.color !== undefined) { // fixed https://github.com/Supergiovane/node-red-contrib-knx-ultimate/issues/287
681
- node.updateKNXLightColorState(_event.color);
682
- node.currentHUEDevice.color = _event.color;
697
+ if (deviceByRef.color !== undefined) { // fixed https://github.com/Supergiovane/node-red-contrib-knx-ultimate/issues/287
698
+ node.updateKNXLightColorState(deviceByRef.color);
699
+ node.currentHUEDevice.color = deviceByRef.color;
683
700
  }
684
701
 
685
- if (_event.dimming !== undefined && _event.dimming.brightness !== undefined) {
702
+ if (deviceByRef.dimming !== undefined && deviceByRef.dimming.brightness !== undefined) {
686
703
  // Once upon n a time, the light transmit the brightness value of 0.39.
687
704
  // To avoid wrongly turn light state on, exit
688
- if (_event.dimming.brightness < 1) _event.dimming.brightness = 0;
689
- if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false && _event.dimming.brightness === 0) {
705
+ if (deviceByRef.dimming.brightness < 1) deviceByRef.dimming.brightness = 0;
706
+ if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false && deviceByRef.dimming.brightness === 0) {
690
707
  // Do nothing, because the light is off and the dimming also is 0
691
708
  } else {
692
- if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false && (_event.on === undefined || (_event.on !== undefined && _event.on.on === true))) node.updateKNXLightState(_event.dimming.brightness > 0);
693
- node.updateKNXBrightnessState(_event.dimming.brightness);
709
+ if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false && (deviceByRef.on === undefined || (deviceByRef.on !== undefined && deviceByRef.on.on === true))) node.updateKNXLightState(deviceByRef.dimming.brightness > 0);
710
+ node.updateKNXBrightnessState(deviceByRef.dimming.brightness);
694
711
  // If the brightness reaches zero, the hue lamp "on" property must be set to zero as well
695
- if (_event.dimming.brightness === 0 && node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === true) {
712
+ if (deviceByRef.dimming.brightness === 0 && node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === true) {
696
713
  node.serverHue.hueManager.writeHueQueueAdd(
697
714
  node.hueDevice,
698
715
  { on: { on: false } },
@@ -700,13 +717,13 @@ module.exports = function (RED) {
700
717
  );
701
718
  node.currentHUEDevice.on.on = false;
702
719
  }
703
- node.currentHUEDevice.dimming.brightness = _event.dimming.brightness;
720
+ node.currentHUEDevice.dimming.brightness = deviceByRef.dimming.brightness;
704
721
  }
705
722
  }
706
- if (_event.color_temperature !== undefined && _event.color_temperature.mirek !== undefined) {
707
- node.updateKNXLightHSVState(_event.color_temperature.mirek);
708
- node.updateKNXLightKelvinState(_event.color_temperature.mirek);
709
- node.currentHUEDevice.color_temperature.mirek = _event.color_temperature.mirek;
723
+ if (deviceByRef.color_temperature !== undefined && deviceByRef.color_temperature.mirek !== undefined) {
724
+ node.updateKNXLightKelvinPercentageState(deviceByRef.color_temperature.mirek);
725
+ node.updateKNXLightKelvinState(deviceByRef.color_temperature.mirek);
726
+ node.currentHUEDevice.color_temperature.mirek = deviceByRef.color_temperature.mirek;
710
727
  }
711
728
  }
712
729
  } catch (error) {
@@ -780,12 +797,12 @@ module.exports = function (RED) {
780
797
  }
781
798
  };
782
799
 
783
- node.updateKNXLightHSVState = function updateKNXLightHSVState(_value, _outputtype = "write") {
784
- if (config.GALightHSVState !== undefined && config.GALightHSVState !== "") {
800
+ node.updateKNXLightKelvinPercentageState = function updateKNXLightKelvinPercentageState(_value, _outputtype = "write") {
801
+ if (config.GALightKelvinPercentageState !== undefined && config.GALightKelvinPercentageState !== "") {
785
802
  const knxMsgPayload = {};
786
- knxMsgPayload.topic = config.GALightHSVState;
787
- knxMsgPayload.dpt = config.dptLightHSVState;
788
- if (config.dptLightHSVState === "5.001") {
803
+ knxMsgPayload.topic = config.GALightKelvinPercentageState;
804
+ knxMsgPayload.dpt = config.dptLightKelvinPercentageState;
805
+ if (config.dptLightKelvinPercentageState === "5.001") {
789
806
  const retPercent = hueColorConverter.ColorConverter.scale(_value, [153, 500], [0, 100]);
790
807
  knxMsgPayload.payload = 100 - retPercent;
791
808
  }
@@ -804,7 +821,7 @@ module.exports = function (RED) {
804
821
  node.setNodeStatusHue({
805
822
  fill: "blue",
806
823
  shape: "ring",
807
- text: "HUE->KNX HSV",
824
+ text: "HUE->KNX Tunable White",
808
825
  payload: knxMsgPayload.payload,
809
826
  });
810
827
  }
@@ -508,7 +508,7 @@
508
508
  <select id="node-input-valscene" style="width:180px;margin-left: 5px; text-align: left;"></select>
509
509
  </div>
510
510
  <div class="form-row">
511
- <label for="node-input-namesceneStatus" style="width:100px;"><i class="fa fa-play-circle-o"></i> Status</label>
511
+ <label for="node-input-namesceneStatus" style="width:100px;"><i class="fa fa-question-circle"></i> Status</label>
512
512
 
513
513
  <label for="node-input-GAsceneStatus" style="width:20px;">GA</label>
514
514
  <input type="text" id="node-input-GAsceneStatus" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "engines": {
4
4
  "node": ">=16.0.0"
5
5
  },
6
- "version": "2.3.3",
6
+ "version": "2.3.5",
7
7
  "description": "Control your KNX intallation via Node-Red! A bunch of KNX nodes, with integrated Philips HUE control and ETS group address importer. Easy to use and highly configurable.",
8
8
  "dependencies": {
9
9
  "binary-parser": "2.2.1",