node-red-contrib-knx-ultimate 2.2.15 → 2.2.18

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,7 +6,12 @@
6
6
 
7
7
  # CHANGELOG
8
8
 
9
- <b>Version 2.2.15</b> - November 2023<br/>
9
+ <b>Version 2.2.18</b> - November 2023<br/>
10
+ <p>
11
+ - HUE Bugfix.<br/>
12
+ - New connection check for HUE bridge.<br/>
13
+ </p>
14
+ <b>Version 2.2.16</b> - November 2023<br/>
10
15
  <p>
11
16
  - NEW: Hue Light: you can now enable the input/output PINs and send/receive commands to/from the light, via the msg flow, like msg.on={"on":true}. The option is "Node Input/Output PINs".<br/>
12
17
  - NEW: Hue Scene: you can now enable the input/output PINs and send/receive commands to/from the light, via the msg flow. The option is "Node Input/Output PINs".<br/>
@@ -81,7 +81,7 @@ module.exports = (RED) => {
81
81
  // }
82
82
 
83
83
  // Connect to Bridge and get the resources
84
- node.initHUEConnection = async () => {
84
+ node.initHUEConnection = () => {
85
85
  try {
86
86
  if (node.hueManager !== undefined) node.hueManager.close();
87
87
  } catch (error) { }
@@ -94,9 +94,10 @@ module.exports = (RED) => {
94
94
  // Init HUE Utility
95
95
  node.hueManager = new HueClass(node.host, node.credentials.username, node.credentials.clientkey, config.bridgeid, node.sysLogger);
96
96
  } catch (error) { }
97
- await node.hueManager.Connect();
97
+ node.hueManager.Connect();
98
98
  } catch (error) {
99
- /* empty */
99
+ if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error(`Errore hue-config: node.initHUEConnection: ${error.message}`);
100
+ node.linkStatus = "disconnected";
100
101
  }
101
102
  node.hueManager.on("event", (_event) => {
102
103
  node.nodeClients.forEach((_oClient) => {
@@ -117,21 +118,27 @@ module.exports = (RED) => {
117
118
  node.loadResourcesFromHUEBridge();
118
119
  }, 6000); // 17/02/2020 Do initial read of all nodes requesting initial read
119
120
  });
121
+
122
+ node.hueManager.on("disconnected", () => {
123
+ node.linkStatus = "disconnected";
124
+ node.nodeClients.forEach((_oClient) => {
125
+ _oClient.setNodeStatusHue({
126
+ fill: "red",
127
+ shape: "ring",
128
+ text: "HUE Disconnected",
129
+ payload: "",
130
+ });
131
+ });
132
+ });
120
133
  };
121
134
 
122
135
  node.startWatchdogTimer = () => {
123
136
  node.timerHUEConfigCheckState = setTimeout(() => {
124
137
  (async () => {
125
138
  if (node.linkStatus === "disconnected") {
126
- await node.initHUEConnection();
127
- } else {
128
- // Check wether the hue connection is still alive
129
- if (node.hueManager !== undefined) {
130
- try {
131
- const ret = await node.hueManager.isConnected();
132
- if (!ret) node.linkStatus = "disconnected";
133
- } catch (error) { node.linkStatus = "disconnected"; }
134
- } else {
139
+ try {
140
+ node.initHUEConnection();
141
+ } catch (error) {
135
142
  node.linkStatus = "disconnected";
136
143
  }
137
144
  }
@@ -143,6 +150,7 @@ module.exports = (RED) => {
143
150
 
144
151
  // Query the HUE Bridge to return the resources
145
152
  node.loadResourcesFromHUEBridge = () => {
153
+ if (node.linkStatus === "disconnected") return;
146
154
  (async () => {
147
155
  // °°°°°° Load ALL resources
148
156
  try {
@@ -317,9 +325,9 @@ module.exports = (RED) => {
317
325
  _Node.handleSendHUE(oHUEDevice);
318
326
  // Add _Node to the clients array
319
327
  _Node.setNodeStatusHue({
320
- fill: "yellow",
328
+ fill: "green",
321
329
  shape: "dot",
322
- text: "Initializing. Please Wait.",
330
+ text: "I'm new and ready.",
323
331
  });
324
332
  }
325
333
  } else {
@@ -394,8 +402,10 @@ module.exports = (RED) => {
394
402
  });
395
403
 
396
404
  RED.httpAdmin.get("/knxUltimateDpts", RED.auth.needsPermission("hue-config.read"), (req, res) => {
397
- const dpts = Object.entries(dptlib).filter(onlyDptKeys).map(extractBaseNo).sort(sortBy("base")).reduce(toConcattedSubtypes, []);
398
- res.json(dpts);
405
+ try {
406
+ const dpts = Object.entries(dptlib).filter(onlyDptKeys).map(extractBaseNo).sort(sortBy("base")).reduce(toConcattedSubtypes, []);
407
+ res.json(dpts);
408
+ } catch (error) { }
399
409
  });
400
410
  }
401
411
  RED.nodes.registerType("hue-config", hueConfig, {
@@ -49,7 +49,6 @@ module.exports = function (RED) {
49
49
  if (_event.id === config.hueDevice) {
50
50
 
51
51
  // IMPORTANT: exit if no event presen.
52
- if (!node.initializingAtStart) return;
53
52
  if (!_event.hasOwnProperty("power_state") || _event.power_state.battery_level === undefined) return;
54
53
 
55
54
  const knxMsgPayload = {};
@@ -79,7 +79,6 @@ module.exports = function (RED) {
79
79
  if (_event.id === config.hueDevice) {
80
80
 
81
81
  // IMPORTANT: exit if no button last_event present.
82
- if (!node.initializingAtStart) return;
83
82
  if (!_event.hasOwnProperty("button") || _event.button.last_event === undefined) return;
84
83
 
85
84
  const knxMsgPayload = {};
@@ -31,7 +31,6 @@ module.exports = function (RED) {
31
31
  node.formatnegativevalue = "leave";
32
32
  node.formatdecimalsvalue = 2;
33
33
  node.currentHUEDevice = undefined; // At start, this value is filled by a call to HUE api. It stores a value representing the current light status.
34
- node.currentKNXGALightState = false; // Stores the current KNX value for the GA
35
34
  node.DayTime = true;
36
35
  node.isGrouped_light = config.hueDevice.split("#")[1] === "grouped_light";
37
36
  node.hueDevice = config.hueDevice.split("#")[0];
@@ -426,8 +425,6 @@ module.exports = function (RED) {
426
425
  });
427
426
  return;
428
427
  }
429
- // IMPORTANT: exit if no button last_event present.
430
- if (!node.initializingAtStart) return;
431
428
 
432
429
  // Output the msg to the flow
433
430
  node.send(_event);
@@ -458,7 +455,7 @@ module.exports = function (RED) {
458
455
  if (node.currentHUEDevice.hasOwnProperty("on") && node.currentHUEDevice.on.on === false && _event.dimming.brightness === 0) {
459
456
  // Do nothing, because the light is off and the dimming also is 0
460
457
  } else {
461
- if (node.currentHUEDevice.on.on === false) node.updateKNXLightState(_event.dimming.brightness > 0);
458
+ if (node.currentHUEDevice.on.on === false && (!_event.hasOwnProperty("on") || (_event.hasOwnProperty("on") && _event.on.on === true))) node.updateKNXLightState(_event.dimming.brightness > 0);
462
459
  node.updateKNXBrightnessState(_event.dimming.brightness);
463
460
  // If the brightness reaches zero, the hue lamp "on" property must be set to zero as well
464
461
  if (_event.dimming.brightness === 0) {
@@ -520,27 +517,25 @@ module.exports = function (RED) {
520
517
  knxMsgPayload.dpt = config.dptLightState;
521
518
  knxMsgPayload.payload = _value;
522
519
  if (config.GALightState !== undefined && config.GALightState !== "") {
523
- if (node.currentKNXGALightState !== knxMsgPayload.payload) {
524
- // Check not to have already sent the value
525
- // Send to KNX bus
526
- if (knxMsgPayload.topic !== "" && knxMsgPayload.topic !== undefined) {
527
- node.server.writeQueueAdd({
528
- grpaddr: knxMsgPayload.topic,
529
- payload: knxMsgPayload.payload,
530
- dpt: knxMsgPayload.dpt,
531
- outputtype: "write",
532
- nodecallerid: node.id,
533
- });
534
- }
535
- node.setNodeStatusHue({
536
- fill: "blue",
537
- shape: "ring",
538
- text: "HUE->KNX On/Off",
520
+
521
+ // Check not to have already sent the value
522
+ // Send to KNX bus
523
+ if (knxMsgPayload.topic !== "" && knxMsgPayload.topic !== undefined) {
524
+ node.server.writeQueueAdd({
525
+ grpaddr: knxMsgPayload.topic,
539
526
  payload: knxMsgPayload.payload,
527
+ dpt: knxMsgPayload.dpt,
528
+ outputtype: "write",
529
+ nodecallerid: node.id,
540
530
  });
541
531
  }
532
+ node.setNodeStatusHue({
533
+ fill: "blue",
534
+ shape: "ring",
535
+ text: "HUE->KNX On/Off",
536
+ payload: knxMsgPayload.payload,
537
+ });
542
538
  }
543
- node.currentKNXGALightState = knxMsgPayload.payload; // Stores the current value
544
539
  } catch (error) {
545
540
  /* empty */
546
541
  }
@@ -45,8 +45,6 @@ module.exports = function (RED) {
45
45
  try {
46
46
  if (_event.id === config.hueDevice) {
47
47
 
48
- // IMPORTANT: exit if no event presen.
49
- if (!node.initializingAtStart) return;
50
48
  if (!_event.hasOwnProperty('light') || _event.light.light_level === undefined) return;
51
49
 
52
50
  const knxMsgPayload = {};
@@ -42,8 +42,6 @@ module.exports = function (RED) {
42
42
  try {
43
43
  if (_event.id === config.hueDevice) {
44
44
 
45
- // IMPORTANT: exit if no event presen.
46
- if (!node.initializingAtStart) return;
47
45
  if (!_event.hasOwnProperty("motion") || _event.motion.motion === undefined) return;
48
46
 
49
47
 
@@ -79,7 +79,6 @@ module.exports = function (RED) {
79
79
  node.handleSendHUE = (_event) => {
80
80
  try {
81
81
  if (_event.id === config.hueDevice) {
82
- if (!node.initializingAtStart) return;
83
82
  // Output the msg to the flow
84
83
  node.send(_event);
85
84
  }
@@ -51,8 +51,7 @@ module.exports = function (RED) {
51
51
  try {
52
52
  if (_event.id === config.hueDevice) {
53
53
 
54
- // IMPORTANT: exit if no event presen.
55
- if (!node.initializingAtStart) return;
54
+
56
55
  if (!_event.hasOwnProperty("relative_rotary")
57
56
  || !_event.relative_rotary.hasOwnProperty("last_event")
58
57
  || _event.relative_rotary.last_event === undefined
@@ -23,6 +23,7 @@ module.exports = function (RED) {
23
23
  node.formatnegativevalue = 'leave';
24
24
  node.formatdecimalsvalue = 2;
25
25
  node.hueDevice = config.hueDevice;
26
+ node.initializingAtStart = !((config.readStatusAtStartup === undefined || config.readStatusAtStartup === "no"));
26
27
 
27
28
  // Used to call the status update from the config node.
28
29
  node.setNodeStatus = ({
@@ -13,11 +13,14 @@ class classHUE extends EventEmitter {
13
13
  this.commandQueue = [];
14
14
  this.closePushEventStream = false;
15
15
  // eslint-disable-next-line max-len
16
- this.timerwriteQueueAdd = setTimeout(this.handleQueue, 15000); // First start. Allow the KNX to connect
16
+ this.timerwriteQueueAdd = setTimeout(this.handleQueue, 10000); // First start. Allow the KNX to connect
17
17
  this.sysLogger = _sysLogger;
18
+ this.timerCheckConnected = undefined;
19
+
18
20
  }
19
21
 
20
- Connect = async () => {
22
+ Connect = () => {
23
+
21
24
  const options = {
22
25
  headers: {
23
26
  "hue-application-key": this.username,
@@ -70,6 +73,12 @@ class classHUE extends EventEmitter {
70
73
  this.es.onopen = () => {
71
74
  // if (this.sysLogger !== undefined && this.sysLogger !== null) this.sysLogger.error('KNXUltimatehueEngine: classHUE: SSE-Connected')
72
75
  this.emit("connected");
76
+
77
+ // Check wether the hue bridge is connected or not
78
+ if (this.timerCheckConnected !== undefined) clearInterval(this.timerCheckConnected);
79
+ this.timerCheckConnected = setInterval(() => {
80
+ this.writeHueQueueAdd(null, null, "Ping");
81
+ }, 30000);
73
82
  };
74
83
 
75
84
  // this.es.onerror = (error) => {
@@ -146,28 +155,14 @@ class classHUE extends EventEmitter {
146
155
  this.sysLogger.error(`KNXUltimatehueEngine: classHUE: handleQueue: stopScene: ${error.message}`);
147
156
  }
148
157
  break;
149
- case "getBattery":
150
- try {
151
- const jReturn = await this.hueApiV2.get(`/resource/device_power/${jRet._lightID}`);
152
- } catch (error) {
153
- if (this.sysLogger !== undefined && this.sysLogger !== null)
154
- this.sysLogger.error(`KNXUltimatehueEngine: classHUE: handleQueue: getBattery: ${error.message}`);
155
- }
156
- break;
157
- case "getLightLevel":
158
+ case "Ping":
158
159
  try {
159
- const jReturn = await this.hueApiV2.get(`/resource/light_level/${jRet._lightID}`);
160
+ const jReturn = await this.hueApiV2.get('/resource/bridge');
160
161
  } catch (error) {
161
- if (this.sysLogger !== undefined && this.sysLogger !== null)
162
- this.sysLogger.error(`KNXUltimatehueEngine: classHUE: handleQueue: getLightLevel: ${error.message}`);
163
- }
164
- break;
165
- case "getTemperature":
166
- try {
167
- const jReturn = await this.hueApiV2.get(`/resource/temperature/${jRet._lightID}`);
168
- } catch (error) {
169
- if (this.sysLogger !== undefined && this.sysLogger !== null)
170
- this.sysLogger.error(`KNXUltimatehueEngine: classHUE: handleQueue: getTemperature: ${error.message}`);
162
+ if (this.sysLogger !== undefined && this.sysLogger !== null) this.sysLogger.error(`KNXUltimatehueEngine: classHUE: handleQueue: Ping: ${error.message}`);
163
+ if (this.timerCheckConnected !== undefined) clearInterval(this.timerCheckConnected);
164
+ this.commandQueue.length = [];
165
+ this.emit("disconnected");
171
166
  }
172
167
  break;
173
168
  default:
@@ -175,6 +170,7 @@ class classHUE extends EventEmitter {
175
170
  }
176
171
  }
177
172
  // The Hue bridge allows about 10 telegram per second, so i need to make a queue manager
173
+ //await new Promise(resolve => setTimeout(resolve, 2000));
178
174
  this.timerwriteQueueAdd = setTimeout(this.handleQueue, 200);
179
175
  };
180
176
 
@@ -184,16 +180,6 @@ class classHUE extends EventEmitter {
184
180
  };
185
181
  // ######################################
186
182
 
187
- isConnected = async () => {
188
- try {
189
- await this.hueApiV2.get('/resource/bridge');
190
- return true;
191
- } catch (error) {
192
- console.log("hueEngine: isConnected: " + error.message)
193
- return false;
194
- }
195
- };
196
-
197
183
  close = async () =>
198
184
  new Promise((resolve, reject) => {
199
185
  try {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "engines": {
4
4
  "node": ">=16.0.0"
5
5
  },
6
- "version": "2.2.15",
6
+ "version": "2.2.18",
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 control.",
8
8
  "dependencies": {
9
9
  "binary-parser": "2.2.1",