node-red-contrib-knx-ultimate 1.3.28 → 1.3.32

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,25 @@
6
6
 
7
7
  # CHANGELOG
8
8
 
9
+ <p>
10
+ <b>Version 1.3.32</b> - February 2022<br/>
11
+ - FIX Datapoint 16.001: fixed an issue with the ISO8859-1 encoding.<br/>
12
+ </p>
13
+ <p>
14
+ <b>Version 1.3.31</b> - February 2022<br/>
15
+ - KNX Viewer node: now the payload is formatted depending on value type.<br/>
16
+ - KNX Viewer node: now the list is ordered by group address.<br/>
17
+ - KNX Viewer node: added a second output pin, that emits an Array containing all group addresses.<br/>
18
+ </p>
19
+ <p>
20
+ <b>Version 1.3.30</b> - February 2022<br/>
21
+ - KNX Viewer node: changed the Datetime display to local time format.<br/>
22
+ </p>
23
+ <p>
24
+ <b>Version 1.3.29</b> - February 2022<br/>
25
+ - Load Control: the timer for shedding won't everytime obey to what you've set. Fixed. <br/>
26
+ - Load Control: Added pre-shedding yellow warning message in the node status.<br/>
27
+ </p>
9
28
  <p>
10
29
  <b>Version 1.3.28</b> - February 2022<br/>
11
30
  - NEW: KNX Viewer: this node allow you to see all datapints and values in a dashboard wirget. https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/knxUltimateViewer<br/>
@@ -22,7 +22,8 @@ exports.formatAPDU = function (value) {
22
22
  }
23
23
 
24
24
  var buf = new Buffer.alloc(14);
25
- buf.write(value, 'ascii')
25
+ if (this.subtypeid === "001") buf.write(value, 'latin1');
26
+ if (this.subtypeid === "000") buf.write(value, 'ascii');
26
27
  return buf;
27
28
 
28
29
  }
@@ -33,7 +34,9 @@ exports.fromBuffer = function (buf) {
33
34
  knxLog.get().error("DPT6: Buffer should be 14 byte long, got", buf.length);
34
35
  return null;
35
36
  }
36
- return buf.toString('ascii');
37
+ if (this.subtypeid === "001") return buf.toString('latin1');
38
+ if (this.subtypeid === "000") return buf.toString('ascii');
39
+
37
40
 
38
41
  }
39
42
 
package/README.md CHANGED
@@ -7,13 +7,13 @@
7
7
  [![NPM downloads total][npm-downloads-total-image]][npm-url]
8
8
  [![MIT License][license-image]][license-url]
9
9
  [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
10
- [![Facebook][facebook-image]][facebook-url]
10
+ [![Youtube][youtube-image]][youtube-url]
11
11
  [![Donate via PayPal](https://img.shields.io/badge/Donate-PayPal-blue.svg?style=flat-square)](https://www.paypal.me/techtoday)
12
12
 
13
13
 
14
14
  ![Sample Node](img/readmemain.png)
15
15
 
16
- Control your KNX intallation via Node-Red! Single Node KNX IN/OUT with optional ETS group address importer and gateway simulation. Easy to use and highly configurable.
16
+ Control your KNX intallation via Node-Red!
17
17
 
18
18
  **You can use it immediately!**
19
19
  ```javascript
@@ -21,7 +21,8 @@ payload = true // Turn light on
21
21
  payload = {red:255, green:200, blue:30} // Put some colors in our life
22
22
  ```
23
23
 
24
- ## DESCRIPTION
24
+
25
+ ## NODE LIST
25
26
 
26
27
  * **KNX-ULTIMATE node** [here](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/2.-Node-Configuration), allow you to control your *KNX installation* via Node-Red. You can control all your KNX devices as well as create a *Virtual Device* in Node-Red, to link external *non KNX* devices, and make it compatible with your KNX installation. I'ts very SIMPLE TO USE thus very customizable.
27
28
  * **SCENE CONTROLLER node** [here](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/SceneController-Configuration), The scene controller node can act as a real scene controller, with recall and save of the current scene.
@@ -29,7 +30,11 @@ payload = {red:255, green:200, blue:30} // Put some colors in our life
29
30
  * **LOGGER node** [here](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/Logger-Configuration), creates an XML diagnostic file, compatible with ETS. You can open it with ETS for diagnostic pourposes. Node: the Logger currently doesn't record the telegrams coming from KNX-Ultimate if you use a **KNX/IP Interface**.
30
31
  * **GLOBAL CONTEXT node** [here](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/GlobalVariable), exposes the group addresses to a Global Context variable, to be used in function nodes.
31
32
  * **ALERTER node** [here](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/Alerter-Configuration). With the Alerter node you can signal to a display or to the node-red-contrib-tts-ultimate node (audio feedback), whenever the selected devices are alerted, i.e. they have payload **true**.
33
+ * **LOAD CONTROL node** [here](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/LoadControl-Configuration). Control your loads (Oven, Washing machine, etc..) and avoit shutting down the main voltage due to too high power consumption.
34
+ * **VIEWER node** [here](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/knxUltimateViewer). View all Group Addresses and values of your KNX BUS, in the Node-Red Dashboard.
32
35
 
36
+ <br>
37
+ <br>
33
38
 
34
39
  ## CHANGELOG
35
40
 
@@ -38,18 +43,25 @@ payload = {red:255, green:200, blue:30} // Put some colors in our life
38
43
  <br>
39
44
  <br>
40
45
 
41
- ## SEARCHING FOR HELP _ VOLUNTEER NEEDED _
46
+ ## VOLUNTEER NEEDED FOR KNX SECURE
47
+
42
48
  **************************************************
43
49
  **************************************************
44
- *I need volunteer helping in development of KNX Secure. High knowledge of cryptography and KNX is needed.*
50
+
51
+ KNX-Secure is under development and **should** be ready by mid 2022.<br/>
52
+ Many users requested me to "extract" the baseline KNX API and make it accessible via npmjs. Here is it.<br/>
53
+ The API is named **KNXUltimate**. In the README page is well documented and there are also samples for unsecure and secure KNX connections.
54
+ * <a href="https://github.com/Supergiovane/KNXUltimate#readme">KNXUltimate API</a>
55
+
56
+ I need volunteer helping in development of KNX Secure.<br/>
57
+ High knowledge of cryptography and KNX is needed.
45
58
  **************************************************
46
59
  **************************************************
47
60
  <br>
48
61
  <br>
49
62
 
50
- ## KNX SECURE
51
63
 
52
- KNX-Secure is under development and **should** be ready by mid 2022. You can help me by clicking here [![Donate via PayPal](https://img.shields.io/badge/Donate-PayPal-blue.svg?style=flat-square)](https://www.paypal.me/techtoday)
64
+
53
65
 
54
66
  ## HELP, SAMPLES, TROUBLESHOOT, WIKI, FAQ, BEST PRACTICES
55
67
 
@@ -67,8 +79,7 @@ Click your language to go to the documentation.<br/>
67
79
  ## STARTER PACK
68
80
 
69
81
  * [Wiki and Help](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki)
70
- * [Youtube video](https://www.youtube.com/playlist?list=PL9Yh1bjbLAYpfy1Auz6CKDfXUusgMwOQr)
71
- * [Facebook page](https://www.facebook.com/supergiovaneDev)
82
+ * [Youtube channel](https://www.youtube.com/playlist?list=PL9Yh1bjbLAYpfy1Auz6CKDfXUusgMwOQr)
72
83
  * [FAQ + Troubleshoot](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/5.-FAQ-Troubleshoot)
73
84
  * [Security best practices](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/SECURITY)
74
85
 
@@ -297,11 +308,11 @@ List of commercial companies, which have given us permission to be mentioned on
297
308
  ## FRIENDLY COMMUNITIES AROUND THE WORLD
298
309
 
299
310
  **Italy**
300
- * [VivereSmart](https://www.facebook.com/groups/viveresmart)
311
+ * [![](https://raw.githubusercontent.com/Supergiovane/node-red-contrib-knx-ultimate/master/img/c/viveresmart.png)](https://www.facebook.com/groups/viveresmart)
301
312
  * [VivereSmart TV](https://www.youtube.com/channel/UC6GlFhcbNuoSEejZ_HlCynA)
302
313
 
303
314
  **Germany**
304
- * [knx-user-forum](https://knx-user-forum.de/forum/öffentlicher-bereich/knx-eib-forum/1389088-knx-node-for-node-red)
315
+ * [![](https://raw.githubusercontent.com/Supergiovane/node-red-contrib-knx-ultimate/master/img/c/knxuserforum.png)](https://knx-user-forum.de/forum/öffentlicher-bereich/knx-eib-forum/1389088-knx-node-for-node-red)
305
316
 
306
317
  **China**
307
318
  * [QQ group: 837579219 (加群需要备注 “来自github”](tencent://groupwpa/?subcmd=all&param=7b2267726f757055696e223a3833373537393231392c2274696d655374616d70223a313633303934363639312c22617574684b6579223a22762b72482b466f4a496a75613033794e4a30744a6970756c55753639424f4d55724f464c4a6c474b77346a30326b7a4f7a3338535536517844684d7756414d62222c2261757468223a22227d&jump_from=)
@@ -319,5 +330,5 @@ List of commercial companies, which have given us permission to be mentioned on
319
330
  [npm-version-image]: https://img.shields.io/npm/v/node-red-contrib-knx-ultimate.svg
320
331
  [npm-downloads-month-image]: https://img.shields.io/npm/dm/node-red-contrib-knx-ultimate.svg
321
332
  [npm-downloads-total-image]: https://img.shields.io/npm/dt/node-red-contrib-knx-ultimate.svg
322
- [facebook-image]: https://img.shields.io/badge/Visit%20me-Facebook-blue
323
- [facebook-url]: https://www.facebook.com/supergiovaneDev
333
+ [youtube-image]: https://img.shields.io/badge/Visit%20me-Youtube-red
334
+ [youtube-url]: https://www.youtube.com/channel/UCA9RsLps1IthT7fDSeUbRZw/playlists
package/img/c/agata.png CHANGED
Binary file
Binary file
Binary file
Binary file
@@ -81,7 +81,6 @@ module.exports = function (RED) {
81
81
  node.status({ fill: fill, shape: shape, text: text + " Shed:" + node.sheddingStage + " Power:" + node.totalWatt + "W" + " Limit:" + node.wattLimit + "W (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" });
82
82
  } catch (error) {
83
83
  }
84
-
85
84
  }
86
85
 
87
86
  // This function is called by the knx-ultimate config node.
@@ -90,8 +89,13 @@ module.exports = function (RED) {
90
89
  // Update the Total Watt?
91
90
  if (msg.topic === node.topic && msg.payload !== "" && msg.payload !== null && msg.payload !== undefined) {
92
91
  node.totalWatt = msg.payload;
93
- // Update current consumption
94
- node.setLocalStatus({ fill: "blue" });
92
+ // Update current consumption only if the node is in idle state
93
+ if (node.timerIncreaseShedding === null && node.timerDecreaseShedding === null) {
94
+ if (node.setLocalStatusTotalWattTimer === null) clearInterval(node.setLocalStatusTotalWattTimer);
95
+ node.setLocalStatusTotalWattTimer = setTimeout(() => {
96
+ node.setLocalStatus({ fill: "grey" });
97
+ }, 2000);
98
+ }
95
99
  return;
96
100
  }
97
101
 
@@ -123,7 +127,7 @@ module.exports = function (RED) {
123
127
  node.initialReadAllDevicesInRules = () => {
124
128
  if (node.server) {
125
129
  // Read status of the Total Power GA
126
- node.server.writeQueueAdd({ grpaddr: node.topic, payload: "", dpt: "", outputtype: "read", nodecallerid: node.id });
130
+ if (node.topic !== undefined && node.topic !== null && node.topic !== "") node.server.writeQueueAdd({ grpaddr: node.topic, payload: "", dpt: "", outputtype: "read", nodecallerid: node.id });
127
131
 
128
132
  for (var i = 0; i < node.deviceList.length; i++) {
129
133
  let grpaddr = node.deviceList[i].monitorGA;
@@ -143,27 +147,55 @@ module.exports = function (RED) {
143
147
  }
144
148
  }
145
149
 
150
+ node.startMainTimer = () => {
151
+ if (node.mainTimer !== null) clearInterval(node.mainTimer);// Clear the timer
152
+ node.mainTimer = setInterval(() => {
153
+ // Issue a READ on all GA's
154
+ node.initialReadAllDevicesInRules();
155
+
156
+ // Check consumption
157
+ if (node.totalWatt > node.wattLimit) {
158
+ // Start increasing shedding!
159
+ if (node.sheddingStage < node.deviceList.length) {
160
+ if (node.timerIncreaseShedding === null) {
161
+ setTimeout(() => {
162
+ node.setLocalStatus({ fill: "yellow", shape: "dot", text: "I'm about to shed the load " + node.sheddingStage, payload: "", GA: "", dpt: "", devicename: "" });
163
+ }, 2000);
164
+ if (node.timerDecreaseShedding !== null) clearTimeout(node.timerDecreaseShedding);// Clear the decreasing timer
165
+ node.startTimerIncreaseShedding();
166
+ }
167
+ }
168
+ } else if (node.totalWatt <= node.wattLimit) {
169
+ // Start decreasing shedding!
170
+ if (node.sheddingStage > 0) {
171
+ if (node.timerDecreaseShedding === null) {
172
+ setTimeout(() => {
173
+ node.setLocalStatus({ fill: "yellow", shape: "dot", text: "I'm about to unshed the load " + node.sheddingStage, payload: "", GA: "", dpt: "", devicename: "" });
174
+ }, 2000);
175
+ if (node.timerIncreaseShedding !== null) clearTimeout(node.timerIncreaseShedding);// Clear the increasing timer
176
+ node.startTimerDecreaseShedding();
177
+ }
178
+ }
179
+ }
180
+ }, 10000);
181
+ }
146
182
 
147
183
  // Start the timer
148
184
  node.startTimerIncreaseShedding = () => {
149
185
 
150
186
  // Increase shedding timer (Switch off devices)
151
- if (node.timerIncreaseShedding !== null) clearInterval(node.timerIncreaseShedding);
152
- node.timerIncreaseShedding = setInterval(() => {
187
+ if (node.timerIncreaseShedding !== null) clearTimeout(node.timerIncreaseShedding);
188
+ node.timerIncreaseShedding = setTimeout(() => {
153
189
  if (node.server) {
154
- // Issue a READ request to the main Watt GA
155
- // The devices should automatically send a value on change, but... you know....
156
- if (node.topic !== undefined && node.topic !== null && node.topic !== "") node.server.writeQueueAdd({ grpaddr: node.topic, payload: "", dpt: "", outputtype: "read", nodecallerid: node.id });
157
-
158
190
  // Check consumption
159
191
  if (node.totalWatt > node.wattLimit) {
160
192
  // Start increasing shedding!
161
193
  if (node.sheddingStage < node.deviceList.length) {
162
194
  node.increaseShedding();
163
- node.startTimerDecreaseShedding(); // Reset the decreasing timer from beginning
164
195
  }
165
196
  }
166
197
  }
198
+ node.timerIncreaseShedding = null; // Nullify the timer.
167
199
  }, node.sheddingCheckInterval);
168
200
  }
169
201
 
@@ -171,18 +203,18 @@ module.exports = function (RED) {
171
203
  node.startTimerDecreaseShedding = () => {
172
204
 
173
205
  // Decrease shedding timer (Switch devices on again)
174
- if (node.timerDecreaseShedding !== null) clearInterval(node.timerDecreaseShedding);
175
- node.timerDecreaseShedding = setInterval(() => {
176
-
177
- // Check consumption
178
- if (node.totalWatt <= node.wattLimit) {
179
- // Start decreasing shedding!
180
- if (node.sheddingStage > 0) {
181
- node.decreaseShedding();
182
- node.startTimerIncreaseShedding(); // Reset the increasing timer from beginning
206
+ if (node.timerDecreaseShedding !== null) clearTimeout(node.timerDecreaseShedding);
207
+ node.timerDecreaseShedding = setTimeout(() => {
208
+ if (node.server) {
209
+ // Check consumption
210
+ if (node.totalWatt <= node.wattLimit) {
211
+ // Start decreasing shedding!
212
+ if (node.sheddingStage > 0) {
213
+ node.decreaseShedding();
214
+ }
183
215
  }
184
216
  }
185
-
217
+ node.timerDecreaseShedding = null; // Nullify timer
186
218
  }, node.sheddingRestoreDelay);
187
219
  }
188
220
 
@@ -266,20 +298,18 @@ module.exports = function (RED) {
266
298
  node.setLocalStatus({ fill: "green", shape: "dot", text: "All loads have been restored" });
267
299
  }, 1000);
268
300
  }
269
-
270
-
271
301
  }
272
302
 
273
303
  // Start
274
- node.startTimerIncreaseShedding();
304
+ node.startMainTimer();
275
305
 
276
306
  node.on("input", function (msg) {
277
307
  if (typeof msg === "undefined") return;
278
308
 
279
309
  // Reset the shedding and activate all loads
280
310
  if (msg.hasOwnProperty("reset")) {
281
- if (node.timerDecreaseShedding !== null) clearInterval(node.timerDecreaseShedding);
282
- if (node.timerIncreaseShedding !== null) clearInterval(node.timerIncreaseShedding);
311
+ if (node.timerDecreaseShedding !== null) clearTimeout(node.timerDecreaseShedding);
312
+ if (node.timerIncreaseShedding !== null) clearTimeout(node.timerIncreaseShedding);
283
313
  node.sheddingStage = 0;
284
314
  for (let index = 0; index < node.deviceList.length; index++) {
285
315
  const oRow = node.deviceList[index];
@@ -287,16 +317,15 @@ module.exports = function (RED) {
287
317
  }
288
318
  setTimeout(() => {
289
319
  node.setLocalStatus({ fill: "green", shape: "dot", text: "All loads have been restored" });
290
- // Restart shedding timer
291
- node.startTimerIncreaseShedding();
292
320
  }, 1000);
293
321
  node.send({ topic: node.name || node.topic, operation: "Reset", payload: node.sheddingStage });
294
322
  }
295
323
 
296
324
  // Disable the shedding node
297
325
  if (msg.hasOwnProperty("disable")) {
298
- if (node.timerDecreaseShedding !== null) clearInterval(node.timerDecreaseShedding);
299
- if (node.timerIncreaseShedding !== null) clearInterval(node.timerIncreaseShedding);
326
+ if (node.timerDecreaseShedding !== null) clearTimeout(node.timerDecreaseShedding);
327
+ if (node.timerIncreaseShedding !== null) clearTimeout(node.timerIncreaseShedding);
328
+ if (node.mainTimer !== null) clearInterval(node.mainTimer);
300
329
  setTimeout(() => {
301
330
  node.setLocalStatus({ fill: "grey", shape: "dot", text: "Disabled" });
302
331
  }, 1000);
@@ -305,12 +334,12 @@ module.exports = function (RED) {
305
334
 
306
335
  // Disable the shedding node
307
336
  if (msg.hasOwnProperty("enable")) {
308
- if (node.timerDecreaseShedding !== null) clearInterval(node.timerDecreaseShedding);
309
- if (node.timerIncreaseShedding !== null) clearInterval(node.timerIncreaseShedding);
337
+ if (node.timerDecreaseShedding !== null) clearTimeout(node.timerDecreaseShedding);
338
+ if (node.timerIncreaseShedding !== null) clearTimeout(node.timerIncreaseShedding);
310
339
  setTimeout(() => {
311
340
  node.setLocalStatus({ fill: "green", shape: "dot", text: "Enabled" });
312
- // Restart shedding timer
313
- node.startTimerIncreaseShedding();
341
+ // Restart timer
342
+ node.startMainTimer();
314
343
  }, 1000);
315
344
  node.send({ topic: node.name || node.topic, operation: "Enabled", payload: node.sheddingStage });
316
345
  }
@@ -323,8 +352,9 @@ module.exports = function (RED) {
323
352
  })
324
353
 
325
354
  node.on("close", function (done) {
326
- if (node.timerDecreaseShedding !== null) clearInterval(node.timerDecreaseShedding);
327
- if (node.timerIncreaseShedding !== null) clearInterval(node.timerIncreaseShedding);
355
+ if (node.mainTimer !== null) clearInterval(node.mainTimer);
356
+ if (node.timerDecreaseShedding !== null) clearTimeout(node.timerDecreaseShedding);
357
+ if (node.timerIncreaseShedding !== null) clearTimeout(node.timerIncreaseShedding);
328
358
  if (node.server) {
329
359
  node.server.removeClient(node)
330
360
  }
@@ -8,7 +8,19 @@
8
8
  name: { value: "KNXViewer", validate: RED.validators.regex(/^[a-z]+$/i) }
9
9
  },
10
10
  inputs: 0,
11
- outputs: 1,
11
+ outputs: 2,
12
+ outputLabels: function (i) {
13
+ switch (i) {
14
+ case 0:
15
+ return "Formatted Payload";
16
+ break;
17
+ case 1:
18
+ return "Simple Array";
19
+ break;
20
+ default:
21
+ break;
22
+ }
23
+ },
12
24
  icon: "node-eye-icon.svg",
13
25
  label: function () {
14
26
  return (this.name);
@@ -1,11 +1,14 @@
1
+ const KNXAddress = require("./../KNXEngine/protocol/KNXAddress").KNXAddress;
2
+
1
3
  module.exports = function (RED) {
2
4
 
5
+
3
6
  function knxUltimateViewer(config) {
4
7
  RED.nodes.createNode(this, config)
5
8
  var node = this
6
9
  node.server = RED.nodes.getNode(config.server)
7
10
  node.topic = node.name;
8
- node.name = config.name === undefined ? "KNXGlobalContext" : config.name;
11
+ node.name = config.name === undefined ? "KNXViewer" : config.name;
9
12
  node.outputtopic = node.name;
10
13
  node.dpt = "";
11
14
  node.notifyreadrequest = false
@@ -43,14 +46,15 @@ module.exports = function (RED) {
43
46
  } catch (error) {
44
47
 
45
48
  }
46
- let dDate = new Date();
49
+ let sDeviceName = msg.devicename === node.name ? "Import ETS file to view the group address name" : msg.devicename; // The ETS file hasn't been imported
50
+ let sAddressRAW = KNXAddress.createFromString(msg.knx.destination, KNXAddress.TYPE_GROUP).get(); // Address as number (for ordering later)
47
51
  if (oGa === undefined) {
48
- node.exposedGAs.push({ address: msg.knx.destination, dpt: msg.knx.dpt, payload: msg.payload, devicename: msg.devicename || "Import ETS file", lastupdate: + dDate.getDate() + ", " + dDate.toLocaleTimeString() });
52
+ node.exposedGAs.push({ address: msg.knx.destination, addressRAW: sAddressRAW, dpt: msg.knx.dpt, payload: msg.payload, devicename: sDeviceName, lastupdate: new Date() });
49
53
  } else {
50
54
  oGa.dpt = msg.knx.dpt;
51
55
  oGa.payload = msg.payload;
52
- oGa.devicename = msg.devicename || "Import ETS file";
53
- oGa.lastupdate = dDate.getDate() + ", " + dDate.toLocaleTimeString()
56
+ oGa.devicename = sDeviceName;
57
+ oGa.lastupdate = new Date();
54
58
  }
55
59
  // Output the payload
56
60
  node.createPayload();
@@ -63,8 +67,8 @@ module.exports = function (RED) {
63
67
  <th> GA </th>
64
68
  <th> Value </th>
65
69
  <th> DPT </th>
66
- <th> Day, time </th>
67
- <th> Name </th>
70
+ <th> Last updated </th>
71
+ <th> Group Address Name </th>
68
72
  </tr>
69
73
  </thead>
70
74
  <tbody>`;
@@ -73,30 +77,44 @@ module.exports = function (RED) {
73
77
  let sPayload = "";
74
78
 
75
79
  const aSorted = node.exposedGAs.sort((a, b) => {
76
- if( a.address !== undefined && b.address !== undefined ) {
77
- return a.address > b.address ? 1 : -1;
80
+ if (a.addressRAW !== undefined && b.addressRAW !== undefined) {
81
+ return a.addressRAW > b.addressRAW ? 1 : -1;
78
82
  } else {
79
- return a.address !== undefined ? 1 : -1
83
+ return a.addressRAW !== undefined ? 1 : -1
80
84
  }
81
85
  });
82
-
83
- for (let index = 0; index < aSorted.length; index++) {
84
- const element = aSorted[index];
85
- sPayload += `<tr>
86
- <td>` + element.address + `</td>`;
87
- if (typeof element.payload === "boolean" && element.payload === true) {
88
- sPayload += "<td><b><font color=green>True</font></b></td>";
89
- } else if (typeof element.payload === "boolean" && element.payload === false) {
90
- sPayload += "<td><font color=red>False</font></td>";
91
- } else {
92
- sPayload += "<td>" + element.payload + "</td>";
86
+ try {
87
+ for (let index = 0; index < aSorted.length; index++) {
88
+ const element = aSorted[index];
89
+ sPayload += `<tr><td>` + element.address + `</td>`;
90
+ if (typeof element.payload === "boolean" && element.payload === true) {
91
+ sPayload += "<td><b><font color=green>True</font></b></td>";
92
+ } else if (typeof element.payload === "boolean" && element.payload === false) {
93
+ sPayload += "<td><font color=red>False</font></td>";
94
+ } else if (typeof element.payload === "object" && !isNaN(Date.parse(element.payload))) {
95
+ // The payload is a datetime
96
+ sPayload += "<td>" + element.payload.toLocaleString() + "</td>";
97
+ } else if (typeof element.payload === "object") {
98
+ // Is maybe a JSON?
99
+ try {
100
+ sPayload += "<td>" + JSON.stringify(element.payload) + "</td>";
101
+ } catch (error) {
102
+ sPayload += "<td>" + element.payload + "</td>";
103
+ }
104
+
105
+ } else {
106
+ sPayload += "<td>" + element.payload + "</td>";
107
+ }
108
+ sPayload += "<td>" + element.dpt + "</td>"
109
+ sPayload += "<td>" + element.lastupdate.toLocaleString() + "</td>";
110
+ sPayload += "<td><font size=2pt>" + element.devicename + "</font></td></tr>";
93
111
  }
94
- sPayload += "<td>" + element.dpt + "</td>"
95
- sPayload += "<td>" + element.lastupdate + "</td>";
96
- sPayload += "<td><font size=2pt>" + element.devicename + "</font></td></tr>";
112
+
113
+ } catch (error) {
114
+
97
115
  }
98
116
 
99
- node.send({ topic: node.name, payload: sHead + sPayload + sFooter });
117
+ node.send([{ topic: node.name, payload: sHead + sPayload + sFooter }, { topic: node.name, payload: node.exposedGAs }]);
100
118
  }
101
119
 
102
120
  node.on("input", function (msg) {
@@ -5,14 +5,14 @@
5
5
  "primoaldistacco": "(this is the first to be switched off)",
6
6
  "properties": {
7
7
  "node-input-server": "Gateway",
8
- "node-input-name": "NoNameme",
8
+ "node-input-name": "Name",
9
9
  "node-input-dpt": "Datapoint",
10
10
  "node-input-topic": "Monitor W",
11
11
  "node-input-controlGA": "Load",
12
12
  "node-input-monitorGA": "In use",
13
13
  "node-input-wattLimit": "Limit W",
14
- "node-input-sheddingCheckInterval": "Delay switch off (s)",
15
- "node-input-sheddingRestoreDelay": "Delay switch on (s)",
14
+ "node-input-sheddingCheckInterval": "Ausschaltverzögerung (s)",
15
+ "node-input-sheddingRestoreDelay": "Einschaltverzögerung (s)",
16
16
  "node-input-autoRestore": "Automatic recovery"
17
17
  },
18
18
  "selectlists": {},
@@ -5,7 +5,7 @@
5
5
  "primoaldistacco": "(this is the first to be switched off)",
6
6
  "properties": {
7
7
  "node-input-server": "Gateway",
8
- "node-input-name": "NoNameme",
8
+ "node-input-name": "Name",
9
9
  "node-input-dpt": "Datapoint",
10
10
  "node-input-topic": "Monitor W",
11
11
  "node-input-controlGA": "Load",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-knx-ultimate",
3
- "version": "1.3.28",
3
+ "version": "1.3.32",
4
4
  "description": "Control your KNX intallation via Node-Red! Single Node KNX IN/OUT with optional ETS group address importer. Easy to use and highly configurable.",
5
5
  "dependencies": {
6
6
  "fs": "0.0.1-security",
package/img/covidfree.png DELETED
Binary file