node-red-contrib-knx-ultimate 2.1.25 → 2.1.27

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,15 @@
6
6
 
7
7
  # CHANGELOG
8
8
 
9
+ <p>
10
+ <b>Version 2.1.27</b> - July 2023<br/>
11
+ - Trashed some old unuseful code and status options.<br/>
12
+ - Keep moving help to the help box of node-red.<br/>
13
+ </p>
14
+ <p>
15
+ <b>Version 2.1.26</b> - July 2023<br/>
16
+ - Hue Light: fixed brightness states issue.<br/>
17
+ </p>
9
18
  <p>
10
19
  <b>Version 2.1.25</b> - July 2023<br/>
11
20
  - Hue Light: added the option to update the KNX Brightness status when turn on/off the HUE light.<br/>
@@ -137,10 +137,10 @@
137
137
 
138
138
 
139
139
  </script>
140
- <script type="text/html" data-help-name="hue-config">
140
+ <script type="text/markdown" data-help-name="hue-config">
141
141
  <p> This node registers to the Hue Bridge.<br/>
142
142
 
143
- Just set the Bridge's ip and click **CONNECT** button.
143
+ Just set the Bridge's IP and click **CONNECT** button.
144
144
 
145
145
  [Find it useful?](https://www.paypal.me/techtoday)
146
146
 
@@ -12,9 +12,6 @@
12
12
  csv: { value: "", required: false },
13
13
  KNXEthInterface: { value: "Auto" },
14
14
  KNXEthInterfaceManuallyInput: { value: "" },
15
- statusDisplayLastUpdate: { value: true },
16
- statusDisplayDeviceNameWhenALL: { value: true },
17
- statusDisplayDataPoint: { value: false },
18
15
  stopETSImportIfNoDatapoint: { value: "stop" },
19
16
  loglevel: { value: "error" },
20
17
  name: { value: "KNX Gateway" },
@@ -112,10 +109,6 @@
112
109
  });
113
110
  });
114
111
 
115
- // 14/02/2020 San Valentino. Retrieve all nodes and show here. Requested by use Alloc in knx-user-forum.de
116
- $.getJSON("nodeList?nodeID=" + node.id, (data) => {
117
- $("#nodeList").val(data);
118
- });
119
112
 
120
113
  // 14/08/2021 Elimino il file delle persistenze di questo nodo
121
114
  $.getJSON("deletePersistGAFile?nodeID=" + node.id, (data) => {
@@ -134,22 +127,13 @@
134
127
  // })
135
128
  });
136
129
 
137
- // 07/01/2020 Collapsible script
130
+ // 06/07/2023 Tabs
138
131
  // *****************************
139
- $("#advancedOptionsAccordion").accordion({
140
- header: "h3",
141
- heightStyle: "content",
142
- collapsible: true,
143
- active: false
144
- });
145
- $("#etsCSVListBox").accordion({
146
- header: "h3",
147
- heightStyle: "content",
148
- collapsible: true,
149
- active: false
150
- });
132
+ $("#tabs").tabs();
151
133
  // *****************************
152
134
 
135
+
136
+
153
137
  var sRetDebugText = "";
154
138
  $("#getinfocam").click(function () {
155
139
  $("#divDebugText").show();
@@ -220,6 +204,8 @@
220
204
  color: #459e00;
221
205
  }
222
206
  </style>
207
+
208
+
223
209
  <script type="text/html" data-template-name="knxUltimate-config">
224
210
  <div class="form-row">
225
211
  <b><span data-i18n="knxUltimate-config.properties.title"></span></b>&nbsp&nbsp<span style="color:red" data-i18n="[html]knxUltimate-config.properties.helplink"></span>
@@ -282,73 +268,64 @@
282
268
  </p>
283
269
  </div>
284
270
  </div> -->
285
-
286
- <br/>
287
- <div class="form-row">
288
- <label for="node-config-input-KNXEthInterface" style="width: 200px">
289
- <i class="fa fa-wifi"></i>
290
- <span data-i18n="knxUltimate-config.properties.bind_local_int"></span>
291
- </label>
292
- <select id="node-config-input-KNXEthInterface"></select>
293
- </div>
294
- <div class="form-row" id="divKNXEthInterfaceManuallyInput" style="display: none;">
295
- <label for="node-config-input-KNXEthInterfaceManuallyInput">Interface name:</label>
296
- <input type="text" id="node-config-input-KNXEthInterfaceManuallyInput" placeholder="Interface name, ex: eth0 or ens1 or Ethernet 1 and so on..."></input>
297
- </div>
298
- <div class="form-row">
299
- <label for="node-config-input-autoReconnect" style="width: 200px">
300
- <i class="fa fa-plug"></i>
301
- <span data-i18n="knxUltimate-config.properties.autoReconnect"></span>
302
- </label>
303
- <select id="node-config-input-autoReconnect">
304
- <option value="yes" data-i18n="knxUltimate-config.properties.autoReconnect_yes"></option>
305
- <option value="no" data-i18n="knxUltimate-config.properties.autoReconnect_no"></option>
306
- </select>
307
- </div>
308
271
 
309
- <div id="advancedOptionsAccordion">
310
- <h3><span data-i18n="knxUltimate-config.properties.adv_options"></span></h3>
311
- <div>
272
+ <br/>
273
+
274
+ <div id="tabs">
275
+ <ul>
276
+ <li><a href="#tabs-1"><i class="fa fa-list-ol"></i> Configuration</a></li>
277
+ <li><a href="#tabs-2"><i class="fa fa-braille"></i> Advanced</a></li>
278
+ <li><a href="#tabs-3"><i class="fa fa-code"></i> ETS file import</a></li>
279
+ <li><a href="#tabs-4"><i class="fa fa-key"></i> Maintenance</a></li>
280
+ </ul>
281
+ <div id="tabs-1">
282
+ <p>
312
283
  <div class="form-row">
313
- <label for="node-config-input-physAddr" style="width:auto">
284
+ <label for="node-config-input-physAddr" style="width: 200px">
314
285
  <i class="fa fa-microchip"></i>
315
286
  <span data-i18n="knxUltimate-config.advanced.knx_phy_addr"></span>
316
287
  </label>
317
288
  <input type="text" id="node-config-input-physAddr" style="width:30%">
318
289
  </div>
319
-
290
+
320
291
  <div class="form-row">
321
- <input type="checkbox" id="node-config-input-localEchoInTunneling" style="display:inline-block; width:auto; vertical-align:top;">
322
- <label style="width:85%" for="node-config-input-localEchoInTunneling">
323
- <i class="fa fa-bullhorn"></i>
324
- <span data-i18n="knxUltimate-config.advanced.localEchoInTunneling"></span>
292
+ <label for="node-config-input-KNXEthInterface" style="width: 200px">
293
+ <i class="fa fa-wifi"></i>
294
+ <span data-i18n="knxUltimate-config.properties.bind_local_int"></span>
325
295
  </label>
296
+ <select id="node-config-input-KNXEthInterface"></select>
326
297
  </div>
327
-
328
- <div class="form-row">
329
- <input type="checkbox" id="node-config-input-statusDisplayLastUpdate" style="display:inline-block; width:auto; vertical-align:top;">
330
- <label style="width:85%" for="node-config-input-statusDisplayLastUpdate">
331
- <i class="fa fa-comment-o"></i>
332
- <span data-i18n="knxUltimate-config.advanced.show_date_status"></span>
333
- </label>
298
+ <div class="form-row" id="divKNXEthInterfaceManuallyInput" style="display: none;">
299
+ <label for="node-config-input-KNXEthInterfaceManuallyInput">Interface name:</label>
300
+ <input type="text" id="node-config-input-KNXEthInterfaceManuallyInput"
301
+ placeholder="Interface name, ex: eth0 or ens1 or Ethernet 1 and so on...">
334
302
  </div>
335
303
  <div class="form-row">
336
- <input type="checkbox" id="node-config-input-statusDisplayDeviceNameWhenALL" style="display:inline-block; width:auto; vertical-align:top;">
337
- <label style="width:85%" for="node-config-input-statusDisplayDeviceNameWhenALL">
338
- <i class="fa fa-comment-o"></i>
339
- <span data-i18n="knxUltimate-config.advanced.show_device_status"></span>
304
+ <label for="node-config-input-autoReconnect" style="width: 200px">
305
+ <i class="fa fa-plug"></i>
306
+ <span data-i18n="knxUltimate-config.properties.autoReconnect"></span>
340
307
  </label>
308
+ <select id="node-config-input-autoReconnect">
309
+ <option value="yes" data-i18n="knxUltimate-config.properties.autoReconnect_yes"></option>
310
+ <option value="no" data-i18n="knxUltimate-config.properties.autoReconnect_no"></option>
311
+ </select>
341
312
  </div>
313
+ </p>
314
+ </div>
315
+ <div id="tabs-2">
316
+ <p>
342
317
  <div class="form-row">
343
- <input type="checkbox" id="node-config-input-statusDisplayDataPoint" style="display:inline-block; width:auto; vertical-align:top;">
344
- <label style="width:85%" for="node-config-input-statusDisplayDataPoint">
345
- <i class="fa fa-comment-o"></i>
346
- <span data-i18n="knxUltimate-config.advanced.show_datapoint_status"></span>
318
+ <input type="checkbox" id="node-config-input-localEchoInTunneling"
319
+ style="display:inline-block; width:auto; vertical-align:top;">
320
+ <label style="width:85%" for="node-config-input-localEchoInTunneling">
321
+ <i class="fa fa-bullhorn"></i>
322
+ <span data-i18n="knxUltimate-config.advanced.localEchoInTunneling"></span>
347
323
  </label>
348
324
  </div>
349
325
 
350
326
  <div class="form-row">
351
- <input type="checkbox" id="node-config-input-ignoreTelegramsWithRepeatedFlag" style="display:inline-block; width:auto; vertical-align:top;">
327
+ <input type="checkbox" id="node-config-input-ignoreTelegramsWithRepeatedFlag"
328
+ style="display:inline-block; width:auto; vertical-align:top;">
352
329
  <label style="width:85%" for="node-config-input-ignoreTelegramsWithRepeatedFlag">
353
330
  <i class="fa fa-ban"></i>
354
331
  <span data-i18n="knxUltimate-config.advanced.ignoreTelegramsWithRepeatedFlag"></span>
@@ -356,23 +333,22 @@
356
333
  </div>
357
334
 
358
335
  <div class="form-row">
359
- <input type="checkbox" id="node-config-input-suppressACKRequest" style="display:inline-block; width:auto; vertical-align:top;">
336
+ <input type="checkbox" id="node-config-input-suppressACKRequest"
337
+ style="display:inline-block; width:auto; vertical-align:top;">
360
338
  <label style="width:85%" for="node-config-input-suppressACKRequest">
361
339
  <i class="fa fa-ban"></i>
362
340
  <span data-i18n="knxUltimate-config.advanced.suppress_ack"></span>
363
341
  </label>
364
- <div id="helpallga" class="form-tips" style="margin-top:11px">
365
- <span data-i18n="knxUltimate-config.advanced.suppress_ack_help"></span>
366
- </div>
367
342
  </div>
368
-
343
+
369
344
  <div class="form-row">
370
345
  <label for="node-config-input-delaybetweentelegrams" style="width:auto">
371
346
  <i class="fa fa-hourglass-start"></i>
372
347
  <span data-i18n="knxUltimate-config.advanced.delaybetweentelegrams"></span>
373
348
  </label>
374
349
  <input type="number" id="node-config-input-delaybetweentelegrams" style="width:20%">
375
- <span data-i18n="knxUltimate-config.advanced.delaybetweentelegramsfurtherdelayREAD"></span><input type="number" id="node-config-input-delaybetweentelegramsfurtherdelayREAD" style="width:15%">X
350
+ <span data-i18n="knxUltimate-config.advanced.delaybetweentelegramsfurtherdelayREAD"></span><input type="number"
351
+ id="node-config-input-delaybetweentelegramsfurtherdelayREAD" style="width:15%">X
376
352
  </div>
377
353
 
378
354
  <div class="form-row">
@@ -389,59 +365,69 @@
389
365
  <option value="trace" data-i18n="knxUltimate-config.advanced.select_trace"></option>
390
366
  </select>
391
367
  <!-- <div class="form-tips" style="margin-top: 11px;background-color:#FFEEEE;text-align:center">
392
- <b><span data-i18n="knxUltimate-config.properties.restart_hint"></span></b>
393
- </div> -->
368
+ <b><span data-i18n="knxUltimate-config.properties.restart_hint"></span></b>
369
+ </div> -->
394
370
  </div>
395
- <p>
396
- <span data-i18n="knxUltimate-config.advanced.nodes_list_title"></span>
397
- <textarea rows="20" id="nodeList" style="width:100%" data-i18n="[placeholder]knxUltimate-config.advanced.nodes_list_help"></textarea>
398
- </p>
399
- </div>
371
+ </p>
400
372
  </div>
401
373
 
402
- <div id="etsCSVListBox">
403
- <h3><span data-i18n="knxUltimate-config.properties.ets_import"></span></h3>
404
- <div>
405
- <div class="form-row">
406
- <span data-i18n="knxUltimate-config.ets.description"></span>
407
- </div>
408
- <div class="form-row">
409
- <span style="color:red" data-i18n="[html]knxUltimate-config.ets.instruction"></span>
410
- </div>
411
- <div class="form-row">
412
- <span style="color:red" data-i18n="[html]knxUltimate-config.ets.youtube"></span>
413
- </div>
414
- <div class="form-row">
415
- <label style="width:auto" for="node-config-input-stopETSImportIfNoDatapoint">
416
- <i class="fa fa-question-circle"></i>
417
- <span data-i18n="knxUltimate-config.ets.help_ga"></span>
418
- </label>
419
- <select id="node-config-input-stopETSImportIfNoDatapoint" style="width:100%">
420
- <option value="stop" data-i18n="knxUltimate-config.ets.import_select_stop"></option>
421
- <option value="fake" data-i18n="knxUltimate-config.ets.import_select_fake"></option>
422
- <option value="skip" data-i18n="knxUltimate-config.ets.import_select_skip"></option>
423
- </select>
424
- </div>
374
+
375
+ <div id="tabs-3">
376
+ <p>
377
+ <div id="etsCSVListBox">
378
+ <h3><span data-i18n="knxUltimate-config.properties.ets_import"></span></h3>
379
+ <div>
380
+ <div class="form-row">
381
+ <span data-i18n="knxUltimate-config.ets.description"></span>
382
+ </div>
383
+ <div class="form-row">
384
+ <span style="color:red" data-i18n="[html]knxUltimate-config.ets.instruction"></span>
385
+ </div>
386
+ <div class="form-row">
387
+ <span style="color:red" data-i18n="[html]knxUltimate-config.ets.youtube"></span>
388
+ </div>
389
+ <div class="form-row">
390
+ <label for="node-config-input-stopETSImportIfNoDatapoint" style="width:250px">
391
+ <i class="fa fa-question-circle"></i>
392
+ <span data-i18n="knxUltimate-config.ets.help_ga"></span>
393
+ </label>
394
+ <select id="node-config-input-stopETSImportIfNoDatapoint" style="width:210px">
395
+ <option value="stop" data-i18n="knxUltimate-config.ets.import_select_stop"></option>
396
+ <option value="fake" data-i18n="knxUltimate-config.ets.import_select_fake"></option>
397
+ <option value="skip" data-i18n="knxUltimate-config.ets.import_select_skip"></option>
398
+ </select>
399
+ </div>
400
+ <div class="form-row">
401
+ <label style="width:auto" for="node-config-input-csv">
402
+ <i class="fa fa-th-list"></i> ETS group address list
403
+ </label>
404
+ </div>
405
+ <div class="form-row">
406
+ <textarea rows="20" id="node-config-input-csv" style="width:100%"
407
+ data-i18n="[placeholder]knxUltimate-config.ets.ga_list_help"></textarea>
408
+ </div>
409
+ </div>
410
+ </div>
411
+ </p>
412
+ </div>
413
+
414
+ <div id="tabs-4">
415
+ <p>
425
416
  <div class="form-row">
426
- <label style="width:auto" for="node-config-input-csv">
427
- <i class="fa fa-th-list"></i>
428
- <span data-i18n="knxUltimate-config.ets.ga_list_title"></span>
429
- </label>
417
+ <label style="width:300px"><i class="fa fa-sign-in"></i> Gather debug info for troubleshoot</label>
418
+ <input type="button" id="getinfocam" class="ui-button ui-corner-all ui-widget"
419
+ style="background-color:#AEE1FF;width:150px" value="Read">
430
420
  </div>
431
- <div class="form-row">
432
- <textarea rows="20" id="node-config-input-csv" style="width:100%" data-i18n="[placeholder]knxUltimate-config.ets.ga_list_help"></textarea>
421
+ <div class="form-row" id="divDebugText" style="display: none;">
422
+ Copy this text, open a new github issue <a target="_blank"
423
+ href="https://github.com/Supergiovane/node-red-contrib-knx-ultimate/issues/new?assignees=Supergiovane&labels=&template=bug_report.md&title=KNXDebugText">
424
+ ->by CLICKING HERE</a>, or paste it to an already open issue.
425
+ <textarea rows="10" id="debugText" style="width:100%"></textarea>
433
426
  </div>
434
- </div>
435
- </div>
436
- <br/>
437
- <div class="form-row">
438
- <label style="width:300px"><i class="fa fa-sign-in"></i> Gather debug info for troubleshoot</label>
439
- <input type="button" id="getinfocam" class="ui-button ui-corner-all ui-widget" style="background-color:#AEE1FF;width:150px" value="Read">
440
- </div>
441
- <div class="form-row" id="divDebugText" style="display: none;">
442
- Copy this text, open a new github issue <a target="_blank" href="https://github.com/Supergiovane/node-red-contrib-knx-ultimate/issues/new?assignees=Supergiovane&labels=&template=bug_report.md&title=KNXDebugText"> ->by CLICKING HERE</a>, or paste it to an already open issue.
443
- <textarea rows="10" id="debugText" style="width:100%"></textarea>
427
+ </p>
444
428
  </div>
429
+ </div>
430
+
445
431
  </script>
446
432
  <script type="text/markdown" data-help-name="knxUltimate-config">
447
433
  <p>This node connects to your KNX/IP Gateway.
@@ -453,16 +439,40 @@
453
439
  | IP/Hostname | ETH/KNX Router multicast address or Interface unicast IP address. If you have an KNX/IP interface, use the interface's IP address, for example 1982.168.1.22, otherwise, if you have a KNX/IP router, put the multicast address 224.0.23.12. You can also type an **Hostname** instead of an IP. |
454
440
  | Port | The port. |
455
441
  | Protocol dropdown | *Tunnel UDP* is for KNX/IP interfaces, *Multicast UDP* is for KNX/IP Routers. |
442
+
443
+ <br/>
444
+
445
+ **Configuration**
446
+ |Property|Description|
447
+ |--|--|
456
448
  | Bind to local interface | The Node will use this local interface for communications. Leave "Auto" for automatic selection. If you have more than one lan connection, for example Ethernet and Wifi, it's strongly recommended to manually select the interface, otherwise not all UDP telegram will reach your computer, thus the Node may not work as expected. |
457
449
  | Automatically connect to KNX BUS at start | Auto connect to the bus at start. You want to leave it enabled. |
458
450
  | KNX Physical Address | The physical KNX address, example 1.1.200 |
451
+
452
+ <br/>
453
+
454
+ **Advanced**
455
+ |Property|Description|
456
+ |--|--|
459
457
  | Suppress repeated (R-Flag) telegrams fom BUS | Ignore repeated KNX telegrams coming from the bus. |
460
458
  | Suppress ACK request in tunneling mode | Enable it if you have a very old KNX/IP gateway. You want to leave it disabled. |
461
459
  | Delay between each telegram (in milliseconds) | Leave it 50ms, unless you're connecting to a remote KNX Gateway via a slow internet connection. |
462
460
  | and further multiply delay only between -read- telegrams | Multiply the delay for read requests to the KNX bus. Again, for slow KNX Gateways. |
463
461
  | Loglevel | Log level, in case you need to debug something with the dev. |
464
- | List of your nodes in all flows | This is a list of all configured node in your flow. You'll find it useful to manually fill the KNX Routers filters. |
465
- | ETS Group Address list import | Use this section to import your ETS CSV or ESF file. Please refer to the help links for further infos. |
462
+
463
+ <br/>
464
+
465
+ **ETS file import**
466
+ |Property|Description|
467
+ |--|--|
468
+ | If Group Address has no Datapoint | If a group address doesn't have a datapoint, it allow to choose wether to stop import, import quth a fake datapoint of 1.001 or to skip import of that group address |
469
+ | ETS group address list | Use this section to import your ETS CSV or ESF file. You can either **paste the CSV or ESF file content** or **set the file path**, for example *./pi/homecsv.csv*. Please refer to the help links for further infos. |
470
+
471
+ <br/>
472
+
473
+ **Maintenance**
474
+ |Property|Description|
475
+ |--|--|
466
476
  | Gather debug info for troubleshoot | Please click the button and add it to the gitHub issue you want to open, it will help me a lot to helping you. |
467
477
 
468
478
  <br/>
@@ -110,9 +110,6 @@ return msg;`,
110
110
  node.nodeClients = [] // Stores the registered clients
111
111
  node.KNXEthInterface = typeof config.KNXEthInterface === 'undefined' ? 'Auto' : config.KNXEthInterface
112
112
  node.KNXEthInterfaceManuallyInput = typeof config.KNXEthInterfaceManuallyInput === 'undefined' ? '' : config.KNXEthInterfaceManuallyInput // If you manually set the interface name, it will be wrote here
113
- node.statusDisplayLastUpdate = typeof config.statusDisplayLastUpdate === 'undefined' ? true : config.statusDisplayLastUpdate
114
- node.statusDisplayDeviceNameWhenALL = typeof config.statusDisplayDeviceNameWhenALL === 'undefined' ? false : config.statusDisplayDeviceNameWhenALL
115
- node.statusDisplayDataPoint = typeof config.statusDisplayDataPoint === 'undefined' ? false : config.statusDisplayDataPoint
116
113
  node.telegramsQueue = [] // 02/01/2020 Queue containing telegrams
117
114
  node.timerSendTelegramFromQueue = null
118
115
  node.delaybetweentelegramsfurtherdelayREAD = (typeof config.delaybetweentelegramsfurtherdelayREAD === 'undefined' || Number(config.delaybetweentelegramsfurtherdelayREAD < 1)) ? 1 : Number(config.delaybetweentelegramsfurtherdelayREAD) // 18/05/2020 delay multiplicator only for "read" telegrams.
@@ -385,99 +382,6 @@ return msg;`,
385
382
  res.json(jListInterfaces)
386
383
  })
387
384
 
388
- // 14/02/2020 Endpoint for retrieving all nodes in all flows
389
- RED.httpAdmin.get('/nodeList', RED.auth.needsPermission('knxUltimate-config.read'), function (req, res) {
390
- let sNodeID = req.query.nodeID // Retrieve node.id of the config node.
391
- const _node = RED.nodes.getNode(sNodeID)
392
- if (_node === null) {
393
- // 27/09/2020 Something wrong
394
- return
395
- }
396
- let sNodes = '"Group Address"\t"Datapoint"\t"Node ID"\t"Device Name"\t"Options"\n' // Contains the text with nodes
397
- let sGA = ''
398
- let sDPT = ''
399
- let sName = ''
400
- let sOptions = ''
401
- try {
402
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info('KNXUltimate-config: Total knx-ultimate nodes: ' + _node.nodeClients.length || 0)
403
- _node.nodeClients
404
- // .map( a => a.topic.indexOf("/") !== -1 ? a.topic.split('/').map( n => +n+100000 ).join('/'):0 ).sort().map( a => a.topic.indexOf("/") !== -1 ? a.topic.split('/').map( n => +n-100000 ).join('/'):0 )
405
- .sort((a, b) => {
406
- if (a.topic !== undefined && b.topic !== undefined) {
407
- if (a.topic.indexOf('/') === -1) return -1
408
- if (b.topic.indexOf('/') === -1) return -1
409
- let date1 = a.topic.split('/')
410
- let date2 = b.topic.split('/')
411
- date1 = date1[0].padStart(2, '0') + date1[1].padStart(2, '0') + date1[2].padStart(2, '0')
412
- date2 = date2[0].padStart(2, '0') + date2[1].padStart(2, '0') + date2[2].padStart(2, '0')
413
- return date1.localeCompare(date2)
414
- } else { return -1 }
415
- })
416
- .forEach(_input => {
417
- const input = RED.nodes.getNode(_input.id)
418
- sNodeID = '"' + input.id + '"'
419
- sName = '"' + (input.name !== undefined ? input.name : '') + '"'
420
- sOptions = '"' + '"'
421
- if (input.listenallga === true) {
422
- if (input.hasOwnProperty('isSceneController')) {
423
- // Is a Scene Controller
424
- sGA = '"Scene Controller"'
425
- sDPT = '"Any"'
426
- } else if (input.hasOwnProperty('isLogger')) {
427
- // Is a Scene Controller
428
- sGA = '"Logger"'
429
- sDPT = '"Any"'
430
- } else if (input.hasOwnProperty('isalertnode')) {
431
- // Is a Scene Controller
432
- sGA = '"Alerter"'
433
- sDPT = '"Any"'
434
- } else if (input.hasOwnProperty('isLoadControlNode')) {
435
- // Is a Load Controller
436
- sGA = '"LoadControl"'
437
- sDPT = '"Any"'
438
- } else {
439
- // Is a ListenallGA
440
- sGA = '"Universal Node"'
441
- sDPT = '"Any"'
442
- sOptions = '"' + 'No Initial Read' + ', '
443
-
444
- sOptions += (input.notifywrite === true ? 'React to Write' : 'No React to Write') + ', '
445
- sOptions += (input.notifyresponse === true ? 'React to Response' : 'No React to Response') + ', '
446
- sOptions += (input.notifyreadrequest === true ? 'React to Read' : 'No React to Read') + ', '
447
- sOptions += 'No Autorespond to Read Requests' + ', '
448
-
449
- sOptions += 'Output type ' + input.outputtype + ', '
450
- sOptions += 'No RBE on Output to Bus' + ', '
451
- sOptions += 'No RBE on Input from Bus' + '"'
452
- }
453
- } else {
454
- sGA = '"' + (input.topic !== undefined ? input.topic : '') + '"'
455
- sDPT = '"' + (input.dpt !== undefined ? input.dpt : '') + '"'
456
-
457
- if (input.hasOwnProperty('isWatchDog')) {
458
- // Is a watchdog node
459
-
460
- } else {
461
- // Is a device node
462
- sOptions = '"' + (Number(input.initialread) > 0 ? 'Initial Read' : 'No Initial Read') + ', '
463
- sOptions += (input.notifywrite === true ? 'React to Write' : 'No React to Write') + ', '
464
- sOptions += (input.notifyresponse === true ? 'React to Response' : 'No React to Response') + ', '
465
- sOptions += (input.notifyreadrequest === true ? 'React to Read' : 'No React to Read') + ', '
466
- sOptions += (input.notifyreadrequestalsorespondtobus === true ? 'Autorespond to Read Requests' : 'No Autorespond to Read Requests') + ', '
467
-
468
- sOptions += 'Output type ' + input.outputtype + ', '
469
- sOptions += (input.outputRBE === true ? 'RBE on Output to Bus' : 'No RBE on Output to Bus') + ', '
470
- sOptions += (input.inputRBE === true ? 'RBE on Input from Bus' : 'No RBE on Input from Bus') + '"'
471
- };
472
- };
473
- sNodes += sGA + '\t' + sDPT + '\t' + sNodeID + '\t' + sName + '\t' + sOptions + '\n'
474
- })
475
- res.json(sNodes)
476
- } catch (error) {
477
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.warn('D ' + error)
478
- }
479
- })
480
-
481
385
  // 12/08/2021 Endpoint for deleting the GA persistent file for the current gateway
482
386
  RED.httpAdmin.get('/deletePersistGAFile', RED.auth.needsPermission('knxUltimate-config.read'), function (req, res) {
483
387
  if (typeof req.query.nodeID !== 'undefined' && req.query.nodeID !== null && req.query.nodeID !== '') {
@@ -397,7 +397,7 @@
397
397
  <ul>
398
398
  <li><a href="#tabs-1"><i class="fa fa-code"></i> Sample in Function</a></li>
399
399
  <li><a href="#tabs-2"><i class="fa fa-braille"></i> Advanced options</a></li>
400
- <li><a href="#tabs-3"><i class="fa fa-list-ol"></i>Format input</a></li>
400
+ <li><a href="#tabs-3"><i class="fa fa-list-ol"></i> Format input</a></li>
401
401
  </ul>
402
402
  <div id="tabs-1">
403
403
  <p>
@@ -49,7 +49,7 @@ module.exports = function (RED) {
49
49
  devicename = devicename || ''
50
50
  dpt = (typeof dpt === 'undefined' || dpt == '') ? '' : ' DPT' + dpt
51
51
  payload = typeof payload === 'object' ? JSON.stringify(payload) : payload
52
- node.status({ fill, shape, text: GA + payload + ((node.listenallga && node.server.statusDisplayDeviceNameWhenALL) === true ? ' ' + devicename : '') + (node.server.statusDisplayDataPoint === true ? dpt : '') + (node.server.statusDisplayLastUpdate === true ? ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ')' : '') + ' ' + text })
52
+ node.status({ fill, shape, text: GA + payload + (node.listenallga === true ? ' ' + devicename : '') + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ' ' + text })
53
53
  // 16/02/2020 signal errors to the server
54
54
  if (fill.toUpperCase() === 'RED') {
55
55
  if (node.server) {
@@ -1,6 +1,6 @@
1
1
 
2
2
  module.exports = function (RED) {
3
- function knxUltimateAlerter (config) {
3
+ function knxUltimateAlerter(config) {
4
4
  const fs = require('fs')
5
5
  const path = require('path')
6
6
  const mkdirp = require('mkdirp')
@@ -53,235 +53,234 @@ module.exports = function (RED) {
53
53
  devicename = devicename || ''
54
54
  dpt = (typeof dpt === 'undefined' || dpt == '') ? '' : ' DPT' + dpt
55
55
  payload = typeof payload === 'object' ? JSON.stringify(payload) : payload
56
- node.status({ fill, shape, text: GA + payload + ((node.listenallga && node.server.statusDisplayDeviceNameWhenALL) === true ? ' ' + devicename : '') + (node.server.statusDisplayDataPoint === true ? dpt : '') + (node.server.statusDisplayLastUpdate === true ? ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ')' : '') + ' ' + text })
57
- } catch (error) {
58
-
56
+ node.status({ fill, shape, text: GA + payload + (node.listenallga === true ? ' ' + devicename : '') + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ' ' + text })
57
+ } catch (error) {
58
+ }
59
59
  }
60
- }
61
60
 
62
61
  // Used to call the status update from the config node.
63
62
  node.setLocalStatus = ({ fill, shape, text, payload, GA, dpt, devicename }) => {
64
- const dDate = new Date()
65
- // 30/08/2019 Display only the things selected in the config
66
- GA = (typeof GA === 'undefined' || GA == '') ? '' : '(' + GA + ') '
67
- devicename = devicename || ''
68
- dpt = (typeof dpt === 'undefined' || dpt == '') ? '' : ' DPT' + dpt
69
- try {
70
- node.status({ fill, shape, text: GA + payload + ((node.listenallga && node.server.statusDisplayDeviceNameWhenALL) === true ? ' ' + devicename : '') + (node.server.statusDisplayDataPoint === true ? dpt : '') + (node.server.statusDisplayLastUpdate === true ? ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ')' : '') + ' ' + text })
71
- } catch (error) {
63
+ const dDate = new Date()
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
68
+ try {
69
+ node.status({ fill, shape, text: GA + payload + (node.listenallga === true ? ' ' + devicename : '') + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ' ' + text })
70
+ } catch (error) {
71
+ }
72
72
  }
73
- }
74
73
 
75
- // This function is called by the knx-ultimate config node, to output a msg.payload.
76
- node.handleSend = msg => {
77
- try {
78
- if (!msg.knx.dpt.startsWith('1.')) return
79
- } catch (error) {
80
- return
81
- }
82
- let bFound = false // 24/04/2021 true if the cycle below found a match, otherwise false
74
+ // This function is called by the knx-ultimate config node, to output a msg.payload.
75
+ node.handleSend = msg => {
76
+ try {
77
+ if (!msg.knx.dpt.startsWith('1.')) return
78
+ } catch (error) {
79
+ return
80
+ }
81
+ let bFound = false // 24/04/2021 true if the cycle below found a match, otherwise false
83
82
 
84
- // Update the node.rules with the values taken from the file, if any, otherwise leave the default value
85
- for (let i = 0; i < node.rules.length; i++) {
86
- // rule is { topic: rowRuleTopic, devicename: rowRuleDeviceName, longdevicename: rowRuleLongDeviceName}
87
- var rule = node.rules[i]
88
- if (msg.topic === rule.topic) {
89
- if (msg.payload == true) {
90
- bFound = true
91
- // Add the device to the array of alertedDevices
92
- const oTrovato = node.alertedDevices.find(a => a.topic === rule.topic)
93
- if (oTrovato === undefined) {
94
- node.alertedDevices.unshift({ topic: rule.topic, devicename: rule.devicename, longdevicename: rule.longdevicename }) // Add to the begin of array
95
- if (node.whentostart === 'ifnewalert') node.send([null, null, node.getThirdPinMSG()])
83
+ // Update the node.rules with the values taken from the file, if any, otherwise leave the default value
84
+ for (let i = 0; i < node.rules.length; i++) {
85
+ // rule is { topic: rowRuleTopic, devicename: rowRuleDeviceName, longdevicename: rowRuleLongDeviceName}
86
+ var rule = node.rules[i]
87
+ if (msg.topic === rule.topic) {
88
+ if (msg.payload == true) {
89
+ bFound = true
90
+ // Add the device to the array of alertedDevices
91
+ const oTrovato = node.alertedDevices.find(a => a.topic === rule.topic)
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()])
95
+ }
96
+ node.setLocalStatus({ fill: 'red', shape: 'dot', text: 'Alert', payload: '', GA: msg.topic, dpt: '', devicename: rule.devicename })
97
+ } else {
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 })
96
101
  }
97
- node.setLocalStatus({ fill: 'red', shape: 'dot', text: 'Alert', payload: '', GA: msg.topic, dpt: '', devicename: rule.devicename })
98
- } else {
99
- // Remove the device from the array
100
- node.alertedDevices = node.alertedDevices.filter(a => a.topic !== msg.topic)
101
- node.setLocalStatus({ fill: 'green', shape: 'dot', text: 'Restore', payload: '', GA: msg.topic, dpt: '', devicename: rule.devicename })
102
102
  }
103
103
  }
104
- }
105
104
 
106
- // If there's some device to alert, stop current timer and restart
107
- // This allow the last alerted device to be outputted immediately
108
- if (bFound && node.whentostart === 'ifnewalert' && node.alertedDevices.length > 0) {
109
- clearTimeout(node.timerSend)
110
- // Send directly the second and third message PIN
111
- node.send([null, node.getSecondPinMSG(), null])
112
- node.curIndexAlertedDevice = 0 // Restart form the beginning
113
- node.startTimer()
105
+ // If there's some device to alert, stop current timer and restart
106
+ // This allow the last alerted device to be outputted immediately
107
+ if (bFound && node.whentostart === 'ifnewalert' && node.alertedDevices.length > 0) {
108
+ clearTimeout(node.timerSend)
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()
113
+ }
114
114
  }
115
- }
116
115
 
117
- // Get the msg to be outputted on second PIN
118
- node.getSecondPinMSG = () => {
119
- if (node.alertedDevices.length > 0) {
120
- const msg = {}
121
- let sRet = ''
122
- let sRetLong = ''
123
- let sTopic = ''
124
- node.alertedDevices.forEach(function (item) {
125
- sTopic += item.topic + ', '
126
- if (item.devicename !== undefined && item.devicename !== '') sRet += item.devicename + ', '
127
- if (item.longdevicename !== undefined && item.longdevicename !== '') sRetLong += item.longdevicename + ', '
128
- })
129
- sTopic = sTopic.slice(0, -2)
130
- if (sRet.length > 2) sRet = sRet.slice(0, -2)
131
- if (sRetLong.length > 2) sRetLong = sRetLong.slice(0, -2)
132
- msg.topic = sTopic
133
- msg.devicename = sRet
134
- msg.longdevicename = sRetLong
135
- msg.count = node.alertedDevices.length
136
- msg.payload = true
137
- return msg
116
+ // Get the msg to be outputted on second PIN
117
+ node.getSecondPinMSG = () => {
118
+ if (node.alertedDevices.length > 0) {
119
+ const msg = {}
120
+ let sRet = ''
121
+ let sRetLong = ''
122
+ let sTopic = ''
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
137
+ }
138
138
  }
139
- }
140
139
 
141
- // Get the msg to be outputted on third PIN
142
- node.getThirdPinMSG = () => {
143
- if (node.alertedDevices.length > 0) {
144
- const msg = {}
145
- let sRet = ''
146
- let sRetLong = ''
147
- let sTopic = ''
148
- const item = node.alertedDevices[0] // Pick the last alerted device
149
- sTopic = item.topic
150
- if (item.devicename !== undefined && item.devicename !== '') sRet = item.devicename
151
- if (item.longdevicename !== undefined && item.longdevicename !== '') sRetLong = item.longdevicename
152
- msg.topic = sTopic
153
- msg.devicename = sRet
154
- msg.longdevicename = sRetLong
155
- msg.count = node.alertedDevices.length
156
- msg.payload = true
157
- return msg
140
+ // Get the msg to be outputted on third PIN
141
+ node.getThirdPinMSG = () => {
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
157
+ }
158
158
  }
159
- }
160
159
 
161
- // 24/04/2021 perform a read on all GA in the rule list. Called both from node.on("input") and knxUltimate-config
162
- node.initialReadAllDevicesInRules = () => {
163
- if (node.server) {
164
- let grpaddr = ''
165
- for (let i = 0; i < node.rules.length; i++) {
166
- // rule is { topic: rowRuleTopic, devicename: rowRuleDeviceName, longdevicename: rowRuleLongDeviceName}
167
- const rule = node.rules[i]
168
- // READ: Send a Read request to the bus
169
- grpaddr = rule.topic
170
- try {
171
- // Check if it's a group address
172
- // const ret = Address.KNXAddress.createFromString(grpaddr, Address.KNXAddress.TYPE_GROUP)
173
- node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'Read', payload: '', GA: grpaddr, dpt: '', devicename: rule.devicename })
174
- node.server.writeQueueAdd({ grpaddr, payload: '', dpt: '', outputtype: 'read', nodecallerid: node.id })
175
- } catch (error) {
176
- node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'Not a KNX GA ' + error.message, payload: '', GA: grpaddr, dpt: '', devicename: rule.devicename })
160
+ // 24/04/2021 perform a read on all GA in the rule list. Called both from node.on("input") and knxUltimate-config
161
+ node.initialReadAllDevicesInRules = () => {
162
+ if (node.server) {
163
+ let grpaddr = ''
164
+ for (let i = 0; i < node.rules.length; i++) {
165
+ // rule is { topic: rowRuleTopic, devicename: rowRuleDeviceName, longdevicename: rowRuleLongDeviceName}
166
+ const rule = node.rules[i]
167
+ // READ: Send a Read request to the bus
168
+ grpaddr = rule.topic
169
+ try {
170
+ // Check if it's a group address
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 })
174
+ } catch (error) {
175
+ node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'Not a KNX GA ' + error.message, payload: '', GA: grpaddr, dpt: '', devicename: rule.devicename })
176
+ }
177
177
  }
178
+ } else {
179
+ node.setLocalStatus({ fill: 'red', shape: 'ring', text: 'No gateway selected. Unable to read from KNX bus', payload: '', GA: '', dpt: '', devicename: '' })
178
180
  }
179
- } else {
180
- node.setLocalStatus({ fill: 'red', shape: 'ring', text: 'No gateway selected. Unable to read from KNX bus', payload: '', GA: '', dpt: '', devicename: '' })
181
181
  }
182
- }
183
182
 
184
- node.on('input', function (msg) {
185
- if (typeof msg === 'undefined') return
186
- if (msg.hasOwnProperty('start')) {
183
+ node.on('input', function (msg) {
184
+ if (typeof msg === 'undefined') return
185
+ if (msg.hasOwnProperty('start')) {
186
+ clearTimeout(node.timerSend)
187
+ node.curIndexAlertedDevice = 0 // Restart form the beginning
188
+ if (node.alertedDevices.length > 0) {
189
+ node.send([null, node.getSecondPinMSG(), node.getThirdPinMSG()])
190
+ node.startTimer()
191
+ } else {
192
+ // Nothing more to output
193
+ node.sendNoMoreDevices()
194
+ }
195
+ return
196
+ }
197
+
198
+ // 24/04/2021 if payload is read or the output type is set to "read", do a read
199
+ if ((msg.hasOwnProperty('readstatus') && msg.readstatus === true)) {
200
+ node.initialReadAllDevicesInRules()
201
+ return
202
+ }
203
+
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
207
+ }
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
211
+ }
212
+ msg.knx = { dpt: '1.001' }
213
+ node.handleSend(msg)
214
+ })
215
+
216
+ node.on('close', function (done) {
187
217
  clearTimeout(node.timerSend)
188
- node.curIndexAlertedDevice = 0 // Restart form the beginning
218
+ if (node.server) {
219
+ node.server.removeClient(node)
220
+ }
221
+ done()
222
+ })
223
+
224
+ node.handleTimer = () => {
189
225
  if (node.alertedDevices.length > 0) {
190
- node.send([null, node.getSecondPinMSG(), node.getThirdPinMSG()])
226
+ const count = node.alertedDevices.length
227
+ if (node.curIndexAlertedDevice > count - 1) {
228
+ node.curIndexAlertedDevice = 0
229
+ if (node.whentostart === 'manualstart') {
230
+ node.curIndexAlertedDevice = 0 // Restart form the beginning
231
+ return
232
+ }
233
+ }
234
+ // Create output message
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])
244
+ } catch (error) {
245
+ }
246
+ node.curIndexAlertedDevice += 1
247
+ // Restart timer
191
248
  node.startTimer()
192
249
  } else {
193
250
  // Nothing more to output
194
251
  node.sendNoMoreDevices()
195
252
  }
196
- return
197
253
  }
198
254
 
199
- // 24/04/2021 if payload is read or the output type is set to "read", do a read
200
- if ((msg.hasOwnProperty('readstatus') && msg.readstatus === true)) {
201
- node.initialReadAllDevicesInRules()
202
- return
255
+ // Start timer
256
+ node.startTimer = () => {
257
+ clearTimeout(node.timerSend)
258
+ node.timerSend = setTimeout(() => {
259
+ node.handleTimer()
260
+ }, node.timerinterval * 1000)
203
261
  }
204
262
 
205
- if (msg.topic === undefined) {
206
- node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'ERROR: You must provide a msg.topic', payload: '', GA: '', dpt: '', devicename: '' })
207
- return
208
- }
209
- if (msg.payload === undefined) {
210
- node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'ERROR: You must provide payload (true/false)', payload: '', GA: '', dpt: '', devicename: '' })
211
- return
263
+ // As soon as there no more devices..
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])
212
272
  }
213
- msg.knx = { dpt: '1.001' }
214
- node.handleSend(msg)
215
- })
216
273
 
217
- node.on('close', function (done) {
218
- clearTimeout(node.timerSend)
274
+ // Init
275
+ node.sendNoMoreDevices()
276
+
277
+ // On each deploy, unsubscribe+resubscribe
219
278
  if (node.server) {
220
279
  node.server.removeClient(node)
221
- }
222
- done()
223
- })
224
-
225
- node.handleTimer = () => {
226
- if (node.alertedDevices.length > 0) {
227
- const count = node.alertedDevices.length
228
- if (node.curIndexAlertedDevice > count - 1) {
229
- node.curIndexAlertedDevice = 0
230
- if (node.whentostart === 'manualstart') {
231
- node.curIndexAlertedDevice = 0 // Restart form the beginning
232
- return
233
- }
234
- }
235
- // Create output message
236
- try {
237
- const curDev = node.alertedDevices[node.curIndexAlertedDevice] // is { topic: rule.topic, devicename: rule.devicename }
238
- const msg = {}
239
- msg.topic = curDev.topic
240
- msg.count = count
241
- msg.devicename = curDev.devicename
242
- msg.longdevicename = curDev.longdevicename
243
- msg.payload = true
244
- node.send([msg, null, null])
245
- } catch (error) {
280
+ if (node.topic !== '' || node.topicSave !== '') {
281
+ node.server.addClient(node)
246
282
  }
247
- node.curIndexAlertedDevice += 1
248
- // Restart timer
249
- node.startTimer()
250
- } else {
251
- // Nothing more to output
252
- node.sendNoMoreDevices()
253
- }
254
- }
255
-
256
- // Start timer
257
- node.startTimer = () => {
258
- clearTimeout(node.timerSend)
259
- node.timerSend = setTimeout(() => {
260
- node.handleTimer()
261
- }, node.timerinterval * 1000)
262
- }
263
-
264
- // As soon as there no more devices..
265
- node.sendNoMoreDevices = () => {
266
- const msg = {}
267
- msg.topic = ''
268
- msg.count = 0
269
- msg.devicename = ''
270
- msg.longdevicename = ''
271
- msg.payload = false
272
- node.send([msg, msg, msg])
273
- }
274
-
275
- // Init
276
- node.sendNoMoreDevices()
277
-
278
- // On each deploy, unsubscribe+resubscribe
279
- if (node.server) {
280
- node.server.removeClient(node)
281
- if (node.topic !== '' || node.topicSave !== '') {
282
- node.server.addClient(node)
283
283
  }
284
284
  }
285
+ RED.nodes.registerType('knxUltimateAlerter', knxUltimateAlerter)
285
286
  }
286
- RED.nodes.registerType('knxUltimateAlerter', knxUltimateAlerter)
287
- }
@@ -1055,7 +1055,7 @@ Start typing in the GA field, the name or group address of your KNX device, the
1055
1055
  |Property|Description|
1056
1056
  |--|--|
1057
1057
  | Blink | *true* Blink the light, *false* Stop blinking. Blinks the light on and off. Useful for signalling. Works with all HUE lights. |
1058
- | Color Cycle | *true* start cycle, *false* Stop cycle. Randomly changes the HUE light's color at regular interval. Works with all HUE lights having color capabilities. |
1058
+ | Color Cycle | *true* start cycle, *false* Stop cycle. Randomly changes the HUE light's color at regular interval. Works with all HUE lights having color capabilities. The color effect will start 10 seconds after set. |
1059
1059
 
1060
1060
  <br/>
1061
1061
 
@@ -84,7 +84,6 @@ module.exports = function (RED) {
84
84
 
85
85
  // First, switch on the light if off
86
86
  if (node.currentHUEDevice !== undefined && node.currentHUEDevice.on.on === false) {
87
- node.disableBSC = true // Temporary disable sending the 100% to the KNX brightness state group address.
88
87
  node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, { on: { on: true } }, 'setLight')
89
88
  }
90
89
 
@@ -120,15 +119,13 @@ module.exports = function (RED) {
120
119
 
121
120
  //If the brightness is not zero, must send true to the "on" property of the HUE lamp.
122
121
  if (node.currentHUEDevice !== undefined && node.currentHUEDevice.on.on === false && msg.payload > 0) {
123
- node.disableBSC = true
124
122
  node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, { on: { on: true } }, 'setLight')
125
123
  setTimeout(() => {
126
- // Wait to the light to turn on and disable the node.disableBSC, then send the brightness %
127
124
  node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state, 'setLight')
128
125
  }, 1000);
129
126
  } else {
130
- node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state, 'setLight')
131
- }
127
+ node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state, 'setLight')
128
+ }
132
129
  node.setNodeStatusHue({ fill: 'green', shape: 'dot', text: 'KNX->HUE', payload: state })
133
130
  break
134
131
  case config.GALightColor:
@@ -195,7 +192,10 @@ module.exports = function (RED) {
195
192
  node.status({ fill: 'red', shape: 'dot', text: 'KNX->HUE error ' + error.message + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
196
193
  }
197
194
  }
195
+
196
+
198
197
  // Start dimming
198
+ // ***********************************************************
199
199
  node.timerDim = undefined
200
200
  node.dimDirection = {}
201
201
  node.timeoutDim = 0
@@ -221,9 +221,12 @@ module.exports = function (RED) {
221
221
  node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, node.dimDirection, 'setLight')
222
222
  }, 700)
223
223
  }
224
+ // ***********************************************************
225
+
224
226
 
225
227
  // Start dimming tunable white
226
228
  // mirek: required(integer minimum: 153, maximum: 500)
229
+ // ***********************************************************
227
230
  node.timerDimTunableWhite = undefined
228
231
  node.dimDirectionTunableWhite = {}
229
232
  node.timeoutDimTunableWhite = 0
@@ -247,16 +250,17 @@ module.exports = function (RED) {
247
250
  node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, node.dimDirectionTunableWhite, 'setLight')
248
251
  }, 700)
249
252
  }
253
+ // ***********************************************************
254
+
250
255
 
251
256
  node.handleSendHUE = _event => {
252
257
  try {
253
258
  if (_event.id === config.hueDevice) {
254
259
  if (_event.hasOwnProperty('on')) {
255
260
  node.updateKNXLightState(_event.on.on)
256
- if (!node.disableBSC && (config.updateGALightBrightnessStateOnHUELightStatusChange === undefined || config.updateGALightBrightnessStateOnHUELightStatusChange === 'yes')) {
257
- node.disableBSC = false // Reset the flag
258
- // Mimic KNX by sending 100% brightness
259
- node.updateKNXBrightnessState(_event.on.on === true ? 100 : 0)
261
+ if (config.updateGALightBrightnessStateOnHUELightStatusChange === undefined || config.updateGALightBrightnessStateOnHUELightStatusChange === 'yes') {
262
+ // Mimic KNX by sending 100% or 0% brightness
263
+ node.updateKNXBrightnessState(_event.on.on === true ? 100 : 0)
260
264
  }
261
265
  if (node.currentHUEDevice !== undefined) node.currentHUEDevice.on = _event.on // Update the internal object representing the current light
262
266
  }
@@ -58,7 +58,7 @@ module.exports = function (RED) {
58
58
  }
59
59
  node.startDimStopper(knxMsgPayload)
60
60
  } else if (knxMsgPayload.dpt.startsWith('5.001')) {
61
- // 0 maximum: 32767
61
+ // 0 - maximum: 32767
62
62
  node.brightnessState < 100 ? node.brightnessState += 20 : node.brightnessState = 100
63
63
  knxMsgPayload.payload = node.brightnessState
64
64
  } else if (knxMsgPayload.dpt.startsWith('232.600')) {
@@ -64,7 +64,7 @@ module.exports = function (RED) {
64
64
  devicename = devicename || ''
65
65
  dpt = (typeof dpt === 'undefined' || dpt == '') ? '' : ' DPT' + dpt
66
66
  payload = typeof payload === 'object' ? JSON.stringify(payload) : payload
67
- node.status({ fill, shape, text: GA + payload + ((node.listenallga && node.server.statusDisplayDeviceNameWhenALL) === true ? ' ' + devicename : '') + (node.server.statusDisplayDataPoint === true ? dpt : '') + (node.server.statusDisplayLastUpdate === true ? ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ')' : '') + ' ' + text })
67
+ node.status({ fill, shape, text: GA + payload + (node.listenallga === true ? ' ' + devicename : '') + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ' ' + text })
68
68
  } catch (error) {
69
69
 
70
70
  }
@@ -36,7 +36,7 @@ module.exports = function (RED) {
36
36
  devicename = devicename || ''
37
37
  dpt = (typeof dpt === 'undefined' || dpt == '') ? '' : ' DPT' + dpt
38
38
  payload = typeof payload === 'object' ? JSON.stringify(payload) : payload
39
- node.status({ fill, shape, text: GA + payload + ((node.listenallga && node.server.statusDisplayDeviceNameWhenALL) === true ? ' ' + devicename : '') + (node.server.statusDisplayDataPoint === true ? dpt : '') + (node.server.statusDisplayLastUpdate === true ? ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ')' : '') + ' ' + text })
39
+ node.status({ fill, shape, text: GA + payload + (node.listenallga === true ? ' ' + devicename : '') + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ' ' + text })
40
40
  } catch (error) {
41
41
  }
42
42
  }
@@ -102,7 +102,7 @@ module.exports = function (RED) {
102
102
  devicename = devicename || ''
103
103
  dpt = (typeof dpt === 'undefined' || dpt === '') ? '' : ' DPT' + dpt
104
104
  payload = typeof payload === 'object' ? JSON.stringify(payload) : payload
105
- node.status({ fill, shape, text: GA + payload + ((node.listenallga && node.server.statusDisplayDeviceNameWhenALL) === true ? ' ' + devicename : '') + (node.server.statusDisplayDataPoint === true ? dpt : '') + (node.server.statusDisplayLastUpdate === true ? ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ')' : '') + ' ' + text })
105
+ node.status({ fill, shape, text: GA + payload + (node.listenallga === true ? ' ' + devicename : '') + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ' ' + text })
106
106
  // 16/02/2020 signal errors to the server
107
107
  if (fill.toUpperCase() === 'RED') {
108
108
  if (node.server) {
@@ -39,7 +39,7 @@ module.exports = function (RED) {
39
39
  devicename = devicename || ''
40
40
  dpt = (typeof dpt === 'undefined' || dpt == '') ? '' : ' DPT' + dpt
41
41
  payload = typeof payload === 'object' ? JSON.stringify(payload) : payload
42
- node.status({ fill, shape, text: GA + payload + ((node.listenallga && node.server.statusDisplayDeviceNameWhenALL) === true ? ' ' + devicename : '') + (node.server.statusDisplayDataPoint === true ? dpt : '') + (node.server.statusDisplayLastUpdate === true ? ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ')' : '') + ' ' + text })
42
+ node.status({ fill, shape, text: GA + payload + (node.listenallga === true ? ' ' + devicename : '') + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ' ' + text })
43
43
  } catch (error) {
44
44
  }
45
45
  }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "engines": {
4
4
  "node": ">=16.0.0"
5
5
  },
6
- "version": "2.1.25",
6
+ "version": "2.1.27",
7
7
  "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. With integrated Philips HUE devices handling.",
8
8
  "dependencies": {
9
9
  "mkdirp": "3.0.1",