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

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.
@@ -468,114 +468,6 @@ module.exports = (RED) => {
468
468
  done();
469
469
  }
470
470
  });
471
-
472
- RED.httpAdmin.get("/knxUltimateGetHueColor", RED.auth.needsPermission("hue-config.read"), (req, res) => {
473
- try {
474
- // find wether the light is a light or is grouped_light
475
- let hexColor;
476
- const _oDevice = node.hueAllResources.filter((a) => a.id === req.query.id)[0];
477
- if (_oDevice.type === "light") {
478
- hexColor = node.getColorFromHueLight(req.query.id);
479
- } else {
480
- // grouped_light, get the first light in the group
481
- const oLight = node.getFirstLightInGroup(_oDevice.id);
482
- hexColor = node.getColorFromHueLight(oLight.id);
483
- }
484
- res.json(hexColor !== undefined ? hexColor : "Select the device first!");
485
- } catch (error) {
486
- res.json("Select the device first!");
487
- }
488
- });
489
- RED.httpAdmin.get("/knxUltimateGetKelvinColor", RED.auth.needsPermission("hue-config.read"), (req, res) => {
490
- try {
491
- // find wether the light is a light or is grouped_light
492
- let kelvinValue;
493
- const _oDevice = node.hueAllResources.filter((a) => a.id === req.query.id)[0];
494
- if (_oDevice.type === "light") {
495
- kelvinValue = node.getKelvinFromHueLight(req.query.id);
496
- } else {
497
- // grouped_light, get the first light in the group
498
- const oLight = node.getFirstLightInGroup(_oDevice.id);
499
- kelvinValue = node.getKelvinFromHueLight(oLight.id);
500
- }
501
- res.json(kelvinValue !== undefined ? kelvinValue : "Select the device first!");
502
- } catch (error) {
503
- res.json("Select the device first!");
504
- };
505
- });
506
-
507
- RED.httpAdmin.get("/knxUltimateGetLightObject", RED.auth.needsPermission("hue-config.read"), (req, res) => {
508
- try {
509
- if (node.hueAllResources === undefined) {
510
- throw (new Error("Resource not yet loaded"));
511
- }
512
- const _lightId = req.query.id;
513
- const oLight = node.hueAllResources.filter((a) => a.id === _lightId)[0];
514
- // Infer some useful info, so the HTML part can avoid to query the server
515
- // Kelvin
516
- try {
517
- if (oLight.color_temperature !== undefined && oLight.color_temperature.mirek !== undefined) {
518
- oLight.calculatedKelvin = hueColorConverter.ColorConverter.mirekToKelvin(oLight.color_temperature.mirek);
519
- }
520
- } catch (error) {
521
- oLight.calculatedKelvin = undefined;
522
- }
523
- // HEX value from XYBri
524
- try {
525
- const retRGB = hueColorConverter.ColorConverter.xyBriToRgb(oLight.color.xy.x, oLight.color.xy.y, oLight.dimming.brightness);
526
- const ret = "#" + hueColorConverter.ColorConverter.rgbHex(retRGB.r, retRGB.g, retRGB.b).toString();
527
- oLight.calculatedHEXColor = ret;
528
- } catch (error) {
529
- oLight.calculatedHEXColor = undefined;
530
- }
531
- res.json(oLight);
532
- } catch (error) {
533
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error(`KNXUltimateHue: hueEngine: knxUltimateGetLightObject: error ${error.message}.`);
534
- res.json({});
535
- }
536
- });
537
-
538
- RED.httpAdmin.get("/KNXUltimateGetResourcesHUE", RED.auth.needsPermission("hue-config.read"), (req, res) => {
539
- try {
540
- // °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
541
- const serverNode = RED.nodes.getNode(req.query.nodeID); // Retrieve node.id of the config node.
542
- if (serverNode === null) {
543
- RED.log.warn(`Warn KNXUltimateGetResourcesHUE serverNode is null`);
544
- res.json({ devices: `serverNode not set` });
545
- return;
546
- }
547
- const jRet = serverNode.getResources(req.query.rtype);
548
- if (jRet !== undefined) {
549
- res.json(jRet);
550
- } else {
551
- res.json({ devices: [{ name: "I'm still connecting...Try in some seconds" }] });
552
- }
553
- // °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
554
- } catch (error) {
555
- //RED.log.error(`Errore KNXUltimateGetResourcesHUE non gestito ${error.message}`);
556
- res.json({ devices: error.message });
557
- RED.log.error(`Err KNXUltimateGetResourcesHUE: ${error.message}`);
558
- // (async () => {
559
- // await node.initHUEConnection();
560
- // })();
561
- }
562
- });
563
-
564
- RED.httpAdmin.get("/knxUltimateGetFirstLightInGroup", RED.auth.needsPermission("hue-config.read"), (req, res) => {
565
- try {
566
- res.json(node.getFirstLightInGroup(req.query.id));
567
- } catch (error) {
568
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error(`KNXUltimateHue: hueEngine: knxUltimateGetFirstLightInGroup: error ${error.message}`);
569
- res.json({});
570
- }
571
- });
572
-
573
- RED.httpAdmin.get("/knxUltimateDpts", RED.auth.needsPermission("hue-config.read"), (req, res) => {
574
- try {
575
- const dpts = Object.entries(dptlib).filter(onlyDptKeys).map(extractBaseNo).sort(sortBy("base")).reduce(toConcattedSubtypes, []);
576
- res.json(dpts);
577
- } catch (error) { }
578
- });
579
471
  }
580
472
  RED.nodes.registerType("hue-config", hueConfig, {
581
473
  credentials: {
@@ -111,7 +111,7 @@
111
111
 
112
112
 
113
113
  // 14/08/2021 Elimino il file delle persistenze di questo nodo
114
- $.getJSON("deletePersistGAFile?nodeID=" + node.id, (data) => { });
114
+ $.getJSON("deletePersistGAFile?serverId=" + node.id, (data) => { });
115
115
 
116
116
  // 06/07/2023 Tabs
117
117
  // *****************************
@@ -5,7 +5,6 @@
5
5
  /* eslint-disable prefer-arrow-callback */
6
6
  const fs = require("fs");
7
7
  const path = require("path");
8
- const oOS = require("os");
9
8
  const net = require("net");
10
9
  const _ = require("lodash");
11
10
  const knx = require("../KNXEngine/src");
@@ -16,7 +15,8 @@ const payloadRounder = require("./utils/payloadManipulation");
16
15
  const loggerEngine = require("./utils/sysLogger.js");
17
16
 
18
17
 
19
- // Helpers
18
+ // DATAPONT MANIPULATION HELPERS
19
+ // ####################
20
20
  const sortBy = (field) => (a, b) => {
21
21
  if (a[field] > b[field]) {
22
22
  return 1;
@@ -51,57 +51,12 @@ const toConcattedSubtypes = (acc, baseType) => {
51
51
 
52
52
  return acc.concat(subtypes);
53
53
  };
54
+ // ####################
55
+
56
+
54
57
 
55
58
  module.exports = (RED) => {
56
- RED.httpAdmin.get("/knxUltimateDpts", RED.auth.needsPermission("knxUltimate-config.read"), function (req, res) {
57
- const dpts = Object.entries(dptlib).filter(onlyDptKeys).map(extractBaseNo).sort(sortBy("base")).reduce(toConcattedSubtypes, []);
58
- res.json(dpts);
59
- // Utilità per visualizzare i datapoints, da copiare in README
60
- // var stringa = "";
61
- // for (let index = 0; index < dpts.length; index++) {
62
- // const element = dpts[index];
63
- // stringa += element.text + "<br/>\n";
64
- // }
65
- // if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.warn(stringa)
66
- });
67
59
 
68
- // 15/09/2020 Supergiovane, read datapoint help usage
69
- RED.httpAdmin.get("/knxUltimateDptsGetHelp", RED.auth.needsPermission("knxUltimate-config.read"), function (req, res) {
70
- const sDPT = req.query.dpt.split(".")[0]; // Takes only the main type
71
- let jRet;
72
- if (sDPT === "0") {
73
- // Special fake datapoint, meaning "Universal Mode"
74
- jRet = {
75
- help: `// KNX-Ultimate set as UNIVERSAL NODE
76
- // Example of a function that sends a message to the KNX-Ultimate
77
- msg.destination = "0/0/1"; // Set the destination
78
- msg.payload = false; // issues a write or response (based on the options Telegram type above) to the KNX bus
79
- msg.event = "GroupValue_Write"; // "GroupValue_Write" or "GroupValue_Response", overrides the option Telegram type above.
80
- msg.dpt = "1.001"; // for example "1.001", overrides the Datapoint option. (Datapoints can be sent as 9 , "9" , "9.001" or "DPT9.001")
81
- return msg;`,
82
- helplink: "https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki",
83
- };
84
- res.json(jRet);
85
- return;
86
- }
87
- jRet = {
88
- help: "NO",
89
- helplink: "https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/-SamplesHome",
90
- };
91
- const dpts = Object.entries(dptlib).filter(onlyDptKeys);
92
- for (let index = 0; index < dpts.length; index++) {
93
- if (dpts[index][0].toUpperCase() === "DPT" + sDPT) {
94
- jRet = {
95
- help: dpts[index][1].basetype.hasOwnProperty("help") ? dpts[index][1].basetype.help : "NO",
96
- helplink: dpts[index][1].basetype.hasOwnProperty("helplink")
97
- ? dpts[index][1].basetype.helplink
98
- : "https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/-SamplesHome",
99
- };
100
- break;
101
- }
102
- }
103
- res.json(jRet);
104
- });
105
60
 
106
61
  function knxUltimateConfigNode(config) {
107
62
  RED.nodes.createNode(this, config);
@@ -286,186 +241,7 @@ return msg;`,
286
241
 
287
242
  // ************************
288
243
 
289
- // Endpoint for connecting to HUE Bridge
290
- RED.httpAdmin.get("/KNXUltimateRegisterToHueBridge", RED.auth.needsPermission("knxUltimate-config.read"), function (req, res) {
291
- try {
292
- if (typeof req.query.nodeID !== "undefined" && req.query.nodeID !== null && req.query.nodeID !== "") {
293
- const _node = RED.nodes.getNode(req.query.nodeID); // Retrieve node.id of the config node.
294
- if (_node !== null) res.json(RED.nodes.getNode(_node.id).csv);
295
- }
296
-
297
- (async () => {
298
- try {
299
- // °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
300
- const discovery = require("node-hue-api").discovery;
301
- // If using this code outside of the examples directory, you will want to use the line below and remove the
302
- // const discovery = require('node-hue-api').discovery
303
- const hueApi = require("node-hue-api").api;
304
- const appName = "KNXUltimate";
305
- const deviceName = "Node-Red";
306
-
307
- // async function discoverBridge() {
308
- // const discoveryResults = await discovery.nupnpSearch()
309
-
310
- // if (discoveryResults.length === 0) {
311
- // if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error('Failed to resolve any Hue Bridges')
312
- // return null
313
- // } else {
314
- // // Ignoring that you could have more than one Hue Bridge on a network as this is unlikely in 99.9% of users situations
315
- // return discoveryResults[0].ipaddress
316
- // }
317
- // }
318
- async function discoverAndCreateUser() {
319
- // const ipAddress = await discoverBridge()
320
- const ipAddress = req.query.IP;
321
-
322
- // Create an unauthenticated instance of the Hue API so that we can create a new user
323
- const unauthenticatedApi = await hueApi.createLocal(ipAddress).connect();
324
- let createdUser;
325
- try {
326
- createdUser = await unauthenticatedApi.users.createUser(appName, deviceName);
327
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info("*******************************************************************************\n");
328
- if (node.sysLogger !== undefined && node.sysLogger !== null) {
329
- node.sysLogger.info(
330
- "User has been created on the Hue Bridge. The following username can be used to\n" +
331
- "authenticate with the Bridge and provide full local access to the Hue Bridge.\n" +
332
- "YOU SHOULD TREAT THIS LIKE A PASSWORD\n",
333
- );
334
- }
335
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info(`Hue Bridge User: ${createdUser.username}`);
336
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info(`Hue Bridge User Client Key: ${createdUser.clientkey}`);
337
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info("*******************************************************************************\n");
338
-
339
- // Create a new API instance that is authenticated with the new user we created
340
- const authenticatedApi = await hueApi.createLocal(ipAddress).connect(createdUser.username);
341
- // Do something with the authenticated user/api
342
- const bridgeConfig = await authenticatedApi.configuration.getConfiguration();
343
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info(`Connected to Hue Bridge: ${bridgeConfig.name} :: ${bridgeConfig.ipaddress}`);
344
- return { bridge: bridgeConfig, user: createdUser };
345
- } catch (err) {
346
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error("The Link button on the bridge was not pressed. " + err.message);
347
- throw err;
348
- // return {
349
- // error:
350
- // "The Link button on the bridge was not pressed or an error has occurred. " +
351
- // err.message,
352
- // };
353
- }
354
- }
355
- async function discoverAndCreateUserInsecure() {
356
- // const ipAddress = await discoverBridge()
357
- const ipAddress = req.query.IP;
358
244
 
359
- // Create an unauthenticated instance of the Hue API so that we can create a new user
360
- const unauthenticatedApi = await hueApi.createInsecureLocal(ipAddress).connect();
361
- let createdUser;
362
- try {
363
- createdUser = await unauthenticatedApi.users.createUser(appName, deviceName);
364
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info("*******************************************************************************\n");
365
- if (node.sysLogger !== undefined && node.sysLogger !== null) {
366
- node.sysLogger.info(
367
- "User has been created on the Hue Bridge. The following username can be used to\n" +
368
- "authenticate with the Bridge and provide full local access to the Hue Bridge.\n" +
369
- "YOU SHOULD TREAT THIS LIKE A PASSWORD\n",
370
- );
371
- }
372
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info(`Hue Bridge User: ${createdUser.username}`);
373
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info(`Hue Bridge User Client Key: ${createdUser.clientkey}`);
374
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info("*******************************************************************************\n");
375
-
376
- // Create a new API instance that is authenticated with the new user we created
377
- const authenticatedApi = await hueApi.createInsecureLocal(ipAddress).connect(createdUser.username);
378
- // Do something with the authenticated user/api
379
- const bridgeConfig = await authenticatedApi.configuration.getConfiguration();
380
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info(`Connected to Hue Bridge: ${bridgeConfig.name} :: ${bridgeConfig.ipaddress}`);
381
- return { bridge: bridgeConfig, user: createdUser };
382
- } catch (err) {
383
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error("The Link button on the bridge was not pressed. " + err.message);
384
- return {
385
- error: "The Link button on the bridge was not pressed or an error has occurred. " + err.message,
386
- };
387
- }
388
- }
389
-
390
- // Invoke the discovery and create user code
391
- try {
392
- const jRet = await discoverAndCreateUser();
393
- res.json(jRet);
394
- } catch (error) {
395
- RED.log.error("Errore KNXUltimateRegisterToHueBridge non gestito Secure " + error.message + ". Try with insecure http connection...");
396
- // Try with insecureClient (avoid problems with expired https certificates)
397
- try {
398
- const jRet = await discoverAndCreateUserInsecure();
399
- res.json(jRet);
400
- } catch (error) {
401
- RED.log.error("Errore KNXUltimateRegisterToHueBridge non gestito Insecure " + error.message + ". I give up.");
402
- res.json({ error: error.message });
403
- }
404
- }
405
- } catch (err) {
406
- RED.log.error("Errore KNXUltimateRegisterToHueBridge non gestito " + err.message);
407
- }
408
- })();
409
- } catch (err) {
410
- RED.log.error("Errore KNXUltimateRegisterToHueBridge bsonto " + err.message);
411
- res.json({ error: err.message });
412
- }
413
- });
414
-
415
- // Endpoint for reading csv/esf by the other nodes
416
- RED.httpAdmin.get("/knxUltimatecsv", RED.auth.needsPermission("knxUltimate-config.read"), function (req, res) {
417
- if (typeof req.query.nodeID !== "undefined" && req.query.nodeID !== null && req.query.nodeID !== "") {
418
- const _node = RED.nodes.getNode(req.query.nodeID); // Retrieve node.id of the config node.
419
- if (_node !== null) res.json(RED.nodes.getNode(_node.id).csv);
420
- } else {
421
- // Get the first knxultimate-config having a valid csv
422
- try {
423
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info("KNXUltimate-config: Requested csv maybe from visu-ultimate?");
424
- RED.nodes.eachNode(function (_node) {
425
- if (_node.hasOwnProperty("csv") && _node.type == "knxUltimate-config" && _node.csv !== "") {
426
- res.json(RED.nodes.getNode(_node.id).csv);
427
- }
428
- });
429
- } catch (error) { }
430
- }
431
- });
432
-
433
- // 14/08/2019 Endpoint for retrieving the ethernet interfaces
434
- RED.httpAdmin.get("/knxUltimateETHInterfaces", RED.auth.needsPermission("knxUltimate-config.read"), function (req, res) {
435
- const oiFaces = oOS.networkInterfaces();
436
- const jListInterfaces = [];
437
- try {
438
- Object.keys(oiFaces).forEach((ifname) => {
439
- // Interface with single IP
440
- if (Object.keys(oiFaces[ifname]).length === 1) {
441
- if (Object.keys(oiFaces[ifname])[0].internal === false) jListInterfaces.push({
442
- name: ifname,
443
- address: Object.keys(oiFaces[ifname])[0].address,
444
- });
445
- } else {
446
- let sAddresses = "";
447
- oiFaces[ifname].forEach(function (iface) {
448
- if (iface.internal === false) sAddresses += "+" + iface.address;
449
- });
450
- if (sAddresses !== "") jListInterfaces.push({ name: ifname, address: sAddresses });
451
- }
452
- });
453
- } catch (error) { }
454
- res.json(jListInterfaces);
455
- });
456
-
457
- // 12/08/2021 Endpoint for deleting the GA persistent file for the current gateway
458
- RED.httpAdmin.get("/deletePersistGAFile", RED.auth.needsPermission("knxUltimate-config.read"), function (req, res) {
459
- if (typeof req.query.nodeID !== "undefined" && req.query.nodeID !== null && req.query.nodeID !== "") {
460
- const sFile = path.join(node.userDir, "knxpersistvalues", "knxpersist" + req.query.nodeID + ".json");
461
- try {
462
- fs.unlinkSync(sFile);
463
- } catch (error) { }
464
- res.json({ error: "No error" });
465
- } else {
466
- res.json({ error: "No NodeID specified" });
467
- }
468
- });
469
245
 
470
246
  // 16/02/2020 KNX-Ultimate nodes calls this function, then this funcion calls the same function on the Watchdog
471
247
  node.reportToWatchdogCalledByKNXUltimateNode = (_oError) => {
@@ -890,7 +666,8 @@ return msg;`,
890
666
  node.knxConnection.on(knx.KNXClient.KNXClientEvents.error, (err) => {
891
667
  try {
892
668
  if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error("knxUltimate-config: received KNXClientEvents.error: " + (err.message === undefined ? err : err.message));
893
- } catch (error) { }
669
+ } catch (error) {
670
+ }
894
671
  // 31/03/2022 Don't care about some errors
895
672
  if (err.message !== undefined && (err.message === "ROUTING_LOST_MESSAGE" || err.message === "ROUTING_BUSY")) {
896
673
  if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error(
@@ -932,7 +709,11 @@ return msg;`,
932
709
  // Start the timer to do initial read.
933
710
  if (node.timerDoInitialRead !== null) clearTimeout(node.timerDoInitialRead);
934
711
  node.timerDoInitialRead = setTimeout(() => {
935
- DoInitialReadFromKNXBusOrFile();
712
+ try {
713
+ DoInitialReadFromKNXBusOrFile();
714
+ } catch (error) {
715
+ if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error("knxUltimate-config: DoInitialReadFromKNXBusOrFile " + error.stack);
716
+ }
936
717
  }, 6000); // 17/02/2020 Do initial read of all nodes requesting initial read
937
718
  const t = setTimeout(() => {
938
719
  // 21/03/2022 fixed possible memory leak. Previously was setTimeout without "let t = ".
@@ -1764,7 +1545,7 @@ return msg;`,
1764
1545
  " NodeID " +
1765
1546
  _oNode.id || "",
1766
1547
  );
1767
- errorMessage.payload = "UNKNOWN: ERROR dptlib.fromBuffer:" + error.message;
1548
+ errorMessage.payload = "UNKNOWN: ERROR dptlib.fromBuffer:" + error.stack;
1768
1549
  return errorMessage;
1769
1550
  }
1770
1551
  }
@@ -78,7 +78,7 @@
78
78
 
79
79
  // 15/09/2020 Supergiovane, set the help sample based on Datapoint
80
80
  function knxUltimateDptsGetHelp(_dpt, _forceClose) {
81
- $.getJSON("knxUltimateDptsGetHelp?dpt=" + _dpt, (data) => {
81
+ $.getJSON("knxUltimateDptsGetHelp?dpt=" + _dpt + "&serverId=" + $("#node-input-server").val() + "&" + { _: new Date().getTime() }, (data) => {
82
82
  try {
83
83
  $("#example-editor").html("");
84
84
  $("#sampleCodeEditor").html();
@@ -86,23 +86,27 @@
86
86
  delete node.sampleEditor;
87
87
  } catch (error) {
88
88
  }
89
- if (data.help !== "NO") {
90
- node.sampleEditor = RED.editor.createEditor({
91
- id: 'example-editor',
92
- mode: 'ace/mode/javascript',
93
- value: data.help//this.exampleText
94
- }).renderer.setShowGutter(false);//.setReadOnly(true).setShowPrintMargin(false);
95
- if (data.helplink !== "") $("#sampleCodeEditor").html("&nbsp<i class=\"fa fa-question-circle\"></i>&nbsp<a target=\"_blank\" href=\"" + data.helplink + "\"><u>Link example of " + _dpt + "</u></a>");
96
- } else {
97
- // No help avaiable
98
- node.sampleEditor = RED.editor.createEditor({
99
- id: 'example-editor',
100
- mode: 'ace/mode/javascript',
101
- value: "Currently, no sample payload is avaiable, sorry."
102
- }).renderer.setShowGutter(false);//.setReadOnly(true).setShowPrintMargin(false);
103
- if (data.helplink !== "") $("#sampleCodeEditor").html("&nbsp<i class=\"fa fa-question-circle\"></i>&nbsp<a target=\"_blank\" href=\"" + data.helplink + "\"><u>Link to wiki</u></a>");
89
+ try {
90
+ if (data.help !== "NO") {
91
+ node.sampleEditor = RED.editor.createEditor({
92
+ id: 'example-editor',
93
+ mode: 'ace/mode/javascript',
94
+ value: data.help//this.exampleText
95
+ }).renderer.setShowGutter(false);//A.setReadOnly(true).setShowPrintMargin(false);
96
+ if (data.helplink !== "") $("#sampleCodeEditor").html("&nbsp<i class=\"fa fa-question-circle\"></i>&nbsp<a target=\"_blank\" href=\"" + data.helplink + "\"><u>Link example of " + _dpt + "</u></a>");
97
+ } else {
98
+ // No help avaiable
99
+ node.sampleEditor = RED.editor.createEditor({
100
+ id: 'example-editor',
101
+ mode: 'ace/mode/javascript',
102
+ value: "Currently, no sample payload is avaiable, sorry."
103
+ }).renderer.setShowGutter(false);//B.setReadOnly(true).setShowPrintMargin(false);
104
+ if (data.helplink !== "") $("#sampleCodeEditor").html("&nbsp<i class=\"fa fa-question-circle\"></i>&nbsp<a target=\"_blank\" href=\"" + data.helplink + "\"><u>Link to wiki</u></a>");
105
+ }
106
+ } catch (error) {
104
107
  }
105
108
  })
109
+
106
110
  }
107
111
 
108
112
  // 02/04/2020 Alert user about data type
@@ -133,7 +137,7 @@
133
137
  // ###########################
134
138
 
135
139
 
136
- $.getJSON("knxUltimateDpts", (data) => {
140
+ $.getJSON("knxUltimateDpts?serverId=" + $("#node-input-server").val() + "&" + { _: new Date().getTime() }, (data) => {
137
141
  data.forEach(dpt => {
138
142
  $("#node-input-dpt").append($("<option></option>")
139
143
  .attr("value", dpt.value)
@@ -214,7 +218,7 @@
214
218
  $("#node-input-topic").autocomplete({
215
219
  minLength: 1,
216
220
  source: function (request, response) {
217
- $.getJSON("knxUltimatecsv?nodeID=" + oNodeServer.id, (data) => {
221
+ $.getJSON("knxUltimatecsv?nodeID=" + oNodeServer.id + "&" + { _: new Date().getTime() }, (data) => {
218
222
  response($.map(data, function (value, key) {
219
223
  var sSearch = (value.ga + " (" + value.devicename + ") DPT" + value.dpt);
220
224
  if (fullSearch(sSearch, request.term)) {
@@ -311,6 +315,7 @@
311
315
  // 15/09/2020 Supergiovane, Detele the sample help editor
312
316
  try {
313
317
  node.sampleEditor.destroy();
318
+ RED.editor.destroy(); // 23/01/2024 added
314
319
  delete node.sampleEditor;
315
320
  } catch (error) { }
316
321
 
@@ -319,6 +324,7 @@
319
324
  // 15/09/2020 Supergiovane, Detele the sample help editor
320
325
  try {
321
326
  node.sampleEditor.destroy();
327
+ RED.editor.destroy(); // 23/01/2024 added
322
328
  delete node.sampleEditor;
323
329
  } catch (error) { }
324
330
  }
@@ -70,7 +70,7 @@
70
70
 
71
71
  // DPT
72
72
  // ########################
73
- $.getJSON('knxUltimateDpts', (data) => {
73
+ $.getJSON('knxUltimateDpts?serverId=' + $("#node-input-server").val(), (data) => {
74
74
  data.forEach(dpt => {
75
75
  if (dpt.value.startsWith("5.001")) {
76
76
  $("#node-input-dptbatterysensor").append($("<option></option>")
@@ -121,7 +121,7 @@
121
121
  $("#node-input-name").autocomplete({
122
122
  minLength: 1,
123
123
  source: function (request, response) {
124
- $.getJSON("KNXUltimateGetResourcesHUE?rtype=device_power&nodeID=" + oNodeServerHue.id, (data) => {
124
+ $.getJSON("KNXUltimateGetResourcesHUE?rtype=device_power&serverId=" + oNodeServerHue.id, (data) => {
125
125
  response($.map(data.devices, function (value, key) {
126
126
  //alert(JSON.stringify(value) + " "+ key)
127
127
  var sSearch = (value.name);
@@ -77,7 +77,7 @@
77
77
 
78
78
  // DPT Dim
79
79
  // ########################
80
- $.getJSON('knxUltimateDpts', (data) => {
80
+ $.getJSON('knxUltimateDpts?serverId=' + $("#node-input-server").val(), (data) => {
81
81
  data.forEach(dpt => {
82
82
  if (dpt.value.startsWith("3.007")) {
83
83
  $("#node-input-dptrepeat").append($("<option></option>")
@@ -124,7 +124,7 @@
124
124
 
125
125
  // DPT dptshort_release
126
126
  // ########################
127
- $.getJSON('knxUltimateDpts', (data) => {
127
+ $.getJSON('knxUltimateDpts?serverId=' + $("#node-input-server").val(), (data) => {
128
128
  data.forEach(dpt => {
129
129
  if (dpt.value.startsWith('1.')) {
130
130
  $("#node-input-dptshort_release").append($("<option></option>")
@@ -267,7 +267,7 @@
267
267
  $("#node-input-name").autocomplete({
268
268
  minLength: 1,
269
269
  source: function (request, response) {
270
- $.getJSON("KNXUltimateGetResourcesHUE?rtype=button&nodeID=" + oNodeServerHue.id, (data) => {
270
+ $.getJSON("KNXUltimateGetResourcesHUE?rtype=button&serverId=" + oNodeServerHue.id, (data) => {
271
271
  response($.map(data.devices, function (value, key) {
272
272
  //alert(JSON.stringify(value) + " "+ key)
273
273
  var sSearch = (value.name);